我的问题很长,因为在开始的时候我写了一个完整的清单,我正在测试,所以请要么完成阅读,要么走到问题本身的结尾。
我在PostgreSQL数据库中创建表:
create table if not exists users
(
id bigserial not null
constraint users_pkey
primary key,
name varchar(50),
is_active boolean not null,
old_user bigint
constraint users_users_id_fk
references users
);
alter table users owner to postgres;
create unique index if not exists users_id_uindex on users (id);
create unique index if not exists users_is_active_idx
on users (is_active) where (is_active = true);
可能有
只有一个活动用户
.
我创建了Spring boot应用程序。下面是对结构的描述(非常简单),下面是问题本身。
1)实体:
@Data
@NoArgsConstructor
@Entity
@Table(name = "users")
public class User {
public User(String name, Boolean isActive, User oldUser) {
this.name = name;
this.isActive = isActive;
this.oldUser = oldUser;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "is_active")
private Boolean isActive;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "old_user")
private User oldUser;
}
2)存储库:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
3)服务:
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User getOne(Long id) {
return userRepository.getOne(id);
}
@Override
public User save(User user) {
return userRepository.save(user);
}
@Override
public User saveAndFlush(User user) {
return userRepository.saveAndFlush(user);
}
}
我插入一个活动用户:
INSERT INTO "public"."users" ("id", "name", "is_active", "old_user") VALUES (DEFAULT, 'FirstUser', true, NULL)
现在我想插入第二个用户(活动),但来自应用程序:
@Slf4j
@Component
public class TestBean implements CommandLineRunner {
private final UserService userService;
public TestBean(UserService userService) {
this.userService = userService;
}
@Override
@Transactional
public void run(String... args) throws Exception {
log.info("Start...");
User first = userService.getOne(1L);
User secondUser = new User("SecondUser", true, first);
userService.saveAndFlush(secondUser);
}
}
如果运行服务器,则会出现异常:o
rg.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "users_is_active_idx"
要解决这个问题,我必须先停用旧用户,然后激活新用户。但这样做行不通,所以在激活新用户之前,我必须将其刷新到上下文:
User first = userService.getOne(1L);
first.setIsActive(false);
userService.saveAndFlush(first);
User secondUser = new User("SecondUser", true, first);
userService.saveAndFlush(secondUser);
这个解决方案很好。但现在我为服务添加了新方法:
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public User saveInRequiredNew(User user) {
return userRepository.saveAndFlush(user);
}
并尝试使用以下方法保存用户:
User first = userService.getOne(1L);
first.setIsActive(false);
userService.saveAndFlush(first);
User secondUser = new User("SecondUser", true, first);
User user = userService.saveInRequiredNew(secondUser);
log.info(String.valueOf(user.getId()));
在这种情况下,当我打电话给
saveInRequiredNew
方法我的应用程序没有抛出异常和结果。它只是停止工作。在实际应用程序中,我的逻辑是建立的,因此我必须将对象保存在
Propagation.REQUIRES_NEW
.
我的问题
-为什么会发生这种情况?解决办法是什么?可以同时更新两个实体(一个事务中的旧用户和新用户(
传播。需要新的
). 我不知道这是否正确)