监听器的递归调用

问题描述 投票:0回答:1

更新时,我的Listener进入无限循环;我已经尝试了所有解决方案,但我不确定可能是什么问题。

@Component
public class UserGroupListener implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        UserGroupListener.applicationContext = applicationContext;
    }

    @PreUpdate
    public void preUpdate(UserGroup userGroup) {
        if (userGroup.getId() == null ) {
            throw new CommonException("Group ID is mandatory");
        }
        checkIdExists(userGroup);
        checkForDuplicateGroupName(userGroup);
    }


    private void checkForDuplicateGroupName(UserGroup userGroup) {
        try {
            UserGroupDTO filter = new UserGroupDTO();
            filter.setGroupName(userGroup.getGroupName().toLowerCase());
            UserGroupService userGroupService = applicationContext.getBean(UserGroupService.class);
            List<UserGroupDTO> duplicates = userGroupService.get(filter);
            duplicates.removeIf(x -> x.getId().equals(userGroup.getId()));

            System.out.println("duplicates: " + duplicates);

            if (!duplicates.isEmpty()) {
                throw new CommonException("Group name already exists");
            }
        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        }
    }

    private void checkIdExists(UserGroup userGroup) {
        try {
            UserGroupDTO filter = new UserGroupDTO();
            filter.setId(userGroup.getId());
            UserGroupService userGroupService = applicationContext.getBean(UserGroupService.class);
            List<UserGroupDTO> userGroups = userGroupService.get(filter);
            if (userGroups.isEmpty()) {
                throw new CommonException("Group ID not found");
            }
        }catch (Exception e){
            throw new CommonException(e.getMessage());
        }
    }
}

这是我的听众

public class UserGroup {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false, unique = true)
    private String groupName;

    @Column(name = "description",length = 1025)
    private String groupDescription;

    @Column(name = "qualified_name")
    private String qualifiedName;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private UserGroup parentGroup;

    @OneToMany(mappedBy = "parentGroup", cascade = CascadeType.ALL)
    private Set<UserGroup> childGroups;
}

这是我的实体

public class UserGroupDAOImpl implements UserGroupDAO {

    @PersistenceContext
    private EntityManager entityManager;
    private final UserGroupMapper mapper;

    public List<UserGroupDTO> get(UserGroupDTO userGroupDTO) {
        try {
            CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
            CriteriaQuery<UserGroup> criteriaQuery = criteriaBuilder.createQuery(UserGroup.class);
            Root<UserGroup> root = criteriaQuery.from(UserGroup.class);

            List<Predicate> predicates = buildPredicates(userGroupDTO, criteriaBuilder, root);

            criteriaQuery.where(predicates.toArray(new Predicate[0]));

            TypedQuery<UserGroup> query = entityManager.createQuery(criteriaQuery);

            // Apply pagination
            PaginationUtil.applyPagination(query, userGroupDTO);

            List<UserGroup> userGroups = query.getResultList();
            return mapper.map(userGroups);
        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        }
    }

这是我的 DAOImpl

List<UserGroup> userGroups = query.getResultList()
就在这个地方;它不会移动到下一行,而是返回到
@preUpdate
到监听器。

这在为双向实体创建数据时导致了一些复杂性。收到称为共享引用的错误。

我用过

@Transient
private boolean isUpdating = false;

但这并没有解决问题

java spring jpa spring-data-jpa
1个回答
0
投票

当您执行查询时,JPA 会将您的所有更改刷新到数据库。 这将触发您的更新前侦听器。 您的触发器尝试执行查询,这将触发 JPA 将所有更改刷新到数据库...

解决方法是不要这样做。 如何避免这样做,当然取决于你实际想要实现什么样的逻辑,我不太确定。

您似乎试图对不同实体之间的数据施加一些约束。在这种情况下,使用数据库约束通常可以更好地完成此操作。 尤其如此,因为即使您刚刚检查不存在重复项,一旦您实际将数据刷新到数据库,它也可能存在。此外,众所周知,JPA 会使这种检查变得更加困难,因为它从一级缓存返回过时的数据。

一般来说,生命周期监听器确实限制了你可以做的事情。基本上你不能改变领域模型的结构,也不能访问

EntityManager
有关详细信息,请参阅规范(重点是我的)

一般来说,可移植应用程序的生命周期方法不应调用EntityManager或查询操作、访问其他实体实例或修改同一持久性上下文中的关系。生命周期回调方法可以修改调用它的实体的非关系状态。

注意:这肯定是重复的。但每次写这种答案我都找不到骗子

© www.soinside.com 2019 - 2024. All rights reserved.