【问题标题】:Do I want to minimize the scope of @Transactional?我想最小化@Transactional 的范围吗?
【发布时间】:2010-10-22 21:20:39
【问题描述】:

不确定“范围”是否是正确的术语。

我正在使用 Spring 进行 JPA 事务管理(下面有一个 Hibernate)。我执行数据库事务的方法是私有的,但是由于您只能在类或 public method 上设置 @Transactional

由于这种机制是基于代理的,只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象中的一个方法调用目标对象的其他方法,即使调用的方法标有@Transactional,也不会在运行时导致实际事务!

我已将类的公共入口点设置为@Transactional。

@Transactional
public void run(parameters) {
    //First non-database method, takes a decent amount of time
    Data data = getData();
    //Call to database
    storeData(data);
}

private storeData(data) {
    em.persist(data);
}

这是不好的做法吗? Spring 是否保持开放事务的时间比这里需要的时间更长?我正在考虑将 storeData() 方法移至 DAO 类并将其公开,但作为学术观点,我想知道重构为 public 是否会对性能产生任何好处。

【问题讨论】:

  • 我这里有两个答案,如果我理解正确的话,它们是在说相反的事情,还有其他人可以就这个问题发表意见吗?
  • stackoverflow.com/questions/1079114 的问题与这个问题有些相关。

标签: java spring jpa transactions annotations


【解决方案1】:

正如每个人都指出的那样,我们应该使事务尽可能小,以便连接仍然可用于其他请求。 可以这样重构吗

public void run(parameters) {
  Data data = getData();
  storeData(data);                                                             
 }

@Transactional
public storeDate(data){em.persist(data)}

【讨论】:

    【解决方案2】:

    在您的代码执行与事务上下文交互的操作之前,事务范围无效,在本例中为 storeData() 方法。 getData() 是非事务性的这一事实不应影响代码的并发性能,因为只有在达到 storeData() 时才会发生任何数据库锁定。

    【讨论】:

    • 取决于事务隔离级别。使用 SERIALIZABLE 隔离,数据库需要在事务开始时跟踪状态,以便其他事务的提交不会影响您的读取。
    • @andri,那么交易什么时候开始?我以为 skaffman 是说直到调用 em.persist 才开始?
    • 就数据库而言,事务只有在获得与数据库的连接时才开始。如果在调用 storeData() 方法之前没有这样做,那么就数据库而言,那就是事务开始的时候。在包含连接之前,不涉及数据库,也不通知数据库。
    • 我最初写这个问题的时候并没有意识到,但是你可以在类级别上设置@Transactional。所以 Spring 必须做一些事情来限制事务长度。
    【解决方案3】:

    如果数据库上存在严重争用,那么保持事务尽可能小绝对是至关重要的 - 比公有与私有区别重要得多,后者本身不会影响性能和可扩展性。所以,要实用...!

    【讨论】:

    • 我想你可能误解了我的问题。 @Transactional 只能存在于公共方法上,但我要问的是我们是否应该尝试将 @Transactional 限制为仅用于数据库工作的方法。
    • 我确实明白:我们确实应该尽可能严格地限制交易范围,如果这意味着公开一些你宁愿保密的事情,那并不是世界末日。
    猜你喜欢
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 2013-11-14
    • 2015-10-02
    相关资源
    最近更新 更多