更新时,我的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;
但这并没有解决问题
当您执行查询时,JPA 会将您的所有更改刷新到数据库。 这将触发您的更新前侦听器。 您的触发器尝试执行查询,这将触发 JPA 将所有更改刷新到数据库...
解决方法是不要这样做。 如何避免这样做,当然取决于你实际想要实现什么样的逻辑,我不太确定。
您似乎试图对不同实体之间的数据施加一些约束。在这种情况下,使用数据库约束通常可以更好地完成此操作。 尤其如此,因为即使您刚刚检查不存在重复项,一旦您实际将数据刷新到数据库,它也可能存在。此外,众所周知,JPA 会使这种检查变得更加困难,因为它从一级缓存返回过时的数据。
一般来说,生命周期监听器确实限制了你可以做的事情。基本上你不能改变领域模型的结构,也不能访问
EntityManager
。 有关详细信息,请参阅规范(重点是我的):
一般来说,可移植应用程序的生命周期方法不应调用EntityManager或查询操作、访问其他实体实例或修改同一持久性上下文中的关系。生命周期回调方法可以修改调用它的实体的非关系状态。
注意:这肯定是重复的。但每次写这种答案我都找不到骗子