Spring@Transactional注释行为怪异
我有以下方法:Spring@Transactional注释行为怪异,spring,hibernate,jpa,transactional,Spring,Hibernate,Jpa,Transactional,我有以下方法: @Transactional public void onEmailMessage() { this.departmentService.removeUserFromDepartments(user, depsids); this.departmentService.getDepartmentUsers(user.id); } 当我调用这个方法时,第一行奇怪的事情是: this.departmentService.removeUserFromDepart
@Transactional
public void onEmailMessage() {
this.departmentService.removeUserFromDepartments(user, depsids);
this.departmentService.getDepartmentUsers(user.id);
}
当我调用这个方法时,第一行奇怪的事情是:
this.departmentService.removeUserFromDepartments(user, depsids);
调用,但数据库根本没有更改,用户仍连接到部门(多对多关系)
之后,该方法:
this.departmentService.getDepartmentUsers(user.id);
调用并返回连接到部门的用户,包括从第#1行删除的用户
当方法返回时-如果我检查数据库,我删除的用户实际上已从表中删除
我可以让查询返回实际更新的值吗???您已经将其标记为
事务性的。执行所有查询后,DB
中进行更改。要么提交所有操作,要么不提交任何操作。事务尚未提交,因此更改不一定已写入数据库
你可以试着打电话
entityManager.flush();
在removeUserFromDepartments()
之后,但在getDepartmentUsers()
之前,强制在提交之前写入DB更改。这没有什么奇怪的。您正在同一事务中执行两个不同的查询。持久性上下文已更新,但事务尚未提交,在第一行完成后,您无法看到所做的更改。事务是一组语句(在本例中是由您的这两个方法创建的语句),在调用commit
后执行。当整个(onEmailMessage)方法完成它的工作时,事务被提交,您可以看到更改
解决方案是:
将它们作为两个独立的事务处理。例如:
@Transactional
public void removeUser(...) {
someInstance.departmentService.removeUserFromDepartments(user, depsids);
}
以及:
@Transactional
公共列表getUsers(…){
返回someInstance.departmentService.getDepartmentUsers(user.id);
}
然后最高级别将是onEmailMessage()
方法,该方法必须是非事务性的,并且在独立的类中,然后是上述两个方法。在这个级别调用这两个命令,它就会工作。启用sql日志记录,您就会知道sql指令何时实际执行。有趣。JPA实现(我假设您正在使用一个)应该知道元素已在同一事务中被删除。可能它尚未连接到事务管理器,或者您设置了一个非事务性的二级缓存。我只是猜测,因为我已经有一段时间没有使用JPA了,但解决方案不应该是强制刷新或将其拆分为两个事务。当从包装器方法中删除事务注释时,它实际上是有效的。其他两种方法都是事务性的,如果它们是事务性的,那么是的,它会起作用。这只是级别的问题——你是如何管理它们的。控制器中的所有方法都应该是非事务性的,这是应用程序的最高级别。DB级别,所有调用实体管理器方法(如:persit、merge等)的方法也应该是非事务性的,因为这是最低级别。所有的事务都应该处理在中间级别的类中,这样就更容易在最高级别上进行管理。这不是必需的,但建议使用。从我的包装器方法中删除事务性注释时,它实际上是有效的。
如果在onEmailMessage()方法中保留@transactional,并且在其中调用的其他方法是事务性的,则不会为它们创建新的事务,将只执行来自更高级别的一个事务。在某些情况下,您可能需要在现有事务中打开其他事务,因此为此,您需要使用:@Transactional(propagation=propagation.REQUIRES\u NEW)
。但在这种情况下,没有理由。
@Transactional
public List<?> getUsers(...) {
return someInstance.departmentService.getDepartmentUsers(user.id);
}