代码之家  ›  专栏  ›  技术社区  ›  ip696

在不同事务中更新和保存相关实体时,服务器将停止工作

  •  0
  • ip696  · 技术社区  · 6 年前

    我的问题很长,因为在开始的时候我写了一个完整的清单,我正在测试,所以请要么完成阅读,要么走到问题本身的结尾。

    我在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 .

    我的问题 -为什么会发生这种情况?解决办法是什么?可以同时更新两个实体(一个事务中的旧用户和新用户( 传播。需要新的 ). 我不知道这是否正确)

    0 回复  |  直到 6 年前