Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring@Transactional注释行为怪异_Spring_Hibernate_Jpa_Transactional - Fatal编程技术网

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);
}