【问题标题】:@Transactional Annotation + for a data insertion in a loop@Transactional Annotation + 用于循环中的数据插入
【发布时间】:2012-04-01 00:52:08
【问题描述】:

我正在为 CMS 应用程序使用 Spring 3,JPA + Hibernate。在那个应用程序中,我有一个服务类方法,它用@Transactional 注释和rollBack 属性注释。在该方法中,我使用循环将数据(即实体类)插入到表中。对于循环实体类的每个iteration,都必须保存到数据库中。但它没有发生。提交仅在循环执行完成并退出方法时发生。然后它一次提交并保存所有内容。但是在这种情况下,我需要在将数据插入数据库后读取数据,然后再提交。我尝试使用ISOLATION LEVEL 读取未提交但它不支持,因为我使用的是默认的JPADialect。还尝试添加 jpaDialecthibernate 实现,但仍然没有成功。请帮助解决此问题。还有一件事,有没有什么方法可以使用传播所需的方法。

【问题讨论】:

  • 您似乎已经意识到您的问题所在。你只是把你的交易边界放在了错误的地方。一旦你修复它,你应该会发现它按预期工作。
  • 您应该能够在同一个事务中读取未提交的数据,而无需提交或更改隔离级别。据我所知,这是最常见的行为..

标签: spring hibernate jpa transactions


【解决方案1】:

你说得对,这就是I 中的含义。因为事务是独立工作的,所以其他事务在提交之前无法看到它们。但是使用隔离级别是一种不好的做法。我宁愿建议你在一个单独的事务中运行每个迭代,其中包含 start 和 commit。

这在 Spring 中有点棘手,但这里有一个例子:

public void batch() {
    for(...) {
        insert(...)
    }
}

//necessarily in a different class!
@Transactional
public void insert() {

}

请注意,batch()@Transactional 注释,insert() 必须属于不同的类(Spring 服务)。评论太长了,但这就是生活。如果不喜欢,可以手动使用TransactionTemplate

【讨论】:

  • 我想使用 TransactionTemplate 来解决这个问题,但我正在对其他服务类使用声明式事务方法。将使用 TransactionTemplate 的 Programmatic Transactions 与 Declarative Transactions 混合使用是不是一种不好的行为。
  • 这真的有用吗? “在代理模式下(默认),只有通过代理传入的外部方法调用被拦截。这意味着自调用,实际上,目标对象中的一个方法调用目标对象的另一个方法,不会导致到运行时的实际事务,即使调用的方法用@Transactional 标记。此外,代理必须完全初始化以提供预期的行为,因此您不应在初始化代码中依赖此功能,即“-spring 参考手册
【解决方案2】:

删除带有循环的方法上的事务注释。

在循环中调用一个单独的方法来执行保存,使该方法具有事务性

【讨论】:

  • 感谢您的回复@NimChimpsky,但我有一个类级别的事务注释,即使我从循环方法中删除了事务注释并将其提供给同一类中的另一个方法。它不起作用,因为类级别注释已经存在。有什么方法可以在类级别指定事务注释以忽略该类中定义的某些方法,即不考虑事务管理。
  • 只需删除类级别的注释并将其添加到您想要的每个方法中
  • 我试过了,但是当我运行应用程序时它会抛出一个 TransactionRequiedException 说'没有事务正在进行'。我创建了两种方法,在一种方法中的服务类中我编写了一些业务逻辑,在第二种方法中我编写了代码来创建实体类并引用 DAO 类来保存这些实体类。对于第一种方法,我没有给出任何注释,但对于第二种方法,我使用 Transactional annoation 进行注释,传播需要新属性。执行从第一个方法开始。
  • @Krishna 事务操作方法必须与调用方法在不同的类中,根据下面的 Tomasz。
  • @NimChimpsky ..感谢您的回复。我明白这个问题。但我认为 Spring 应该支持 Service 类中没有 Transactions 的方法,就像它们在 Test 环境中 nottransactional 一样。
【解决方案3】:

您要么需要使用程序化事务(Spring 的 TransactionTemplatePlatformTransactionManager 是要查看的类,请参阅 Spring Doc for programmatic transactions,或者您可以从循环中调用另一个事务方法,其中事务标记为 @ 987654325@,表示该方法的每个调用都在自己的事务中执行,请参阅here。我认为第二种方法需要您在不同的Spring bean上定义REQUIRES_NEW方法,因为AOP-Proxy。您也可以省略如果循环不在事务中执行,则为 REQUIRES_NEW。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多