事务/ spring事务传播会解决这个并发问题吗?

时间:2012-04-20 14:40:09

标签: java spring concurrency transactions

如果可能,我有几个关于春季交易的问题。 让我们假设我有这个DAO课程:

public class MyDAO {

    /**
    * verifies if a certain record in DB contains 'True' in a certain Column named publishFlag
    */
    @Transactional
    public bloolean isBeingPublished(Long recordID){
    ...
    }

    /**
    * sets the record's publishFlag column to true indicating that it's being published
    */
    @Transactional
    public boolean setBeingPublished(Long recordID){
    ...
    }

}

以下课程使用它:

public class MyClass {

    @Autowired
    MyDAO dao;

    public void publishRecords(List<Long> ids){

        for(Long id : ids){
            if(!dao.isBeingPublished(id)){
                dao.setBeingPublished(id);
                //do something to publish the record
            }
        }

    }
}

我的问题是:

  • 首先,!dao.isBeingPublished(id)dao.setBeingPublished(id)是在同一交易中执行还是在单独交易中执行?

  • 关于并发性的第二个问题,可以创建多个MyClass实例,并且可以对publishRecord方法进行并发调用,因此对!dao.isBeingPublished(id)的两个并发调用可能都会提供相同的结果,从而使记录发布两次! 我会考虑使publishRecords同步,但应用程序可能部署在多个服务器上,这使得同步声明无效,因此我对事务的问题,因为数据库是这些服务器上部署的应用程序之间唯一的共享资源。

究竟是什么解决了我的问题?我读到了关于spring的事务传播,并发现REQUIRES_NEW会创建一个新事务,即使当前正在执行一个事务,但是,我仍然无法看到这将如何解决我的问题。

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

很少有事情需要考虑,DAO专注于单个实体的操作,而服务专注于一个或多个实体的操作,因此事务应该放在服务层上,这样你就可以重用DAO的操作而不需要任何事务,但是让服务决定何时开始和结束交易

  1. 这不是单笔交易,而是两笔单独的交易。
  2. 这是您当前设计的并发问题,请参阅以下建议。
  3. <强>接口

    public interface MyClass {
        public void publishRecords(List<Long> ids);
    }
    

    <强>实施

    @Service
    @Transactional(readOnly = false)
    class DefaultMyClass implements MyClass  {
    
        @Autowired
        MyDAO dao;
    
        // single transaction
        @Override
        public void publishRecords(List<Long> ids) {
            for(Long id : ids){
                if(!dao.isBeingPublished(id)){
                    dao.setBeingPublished(id);
                    //do something to publish the record
                }
            }
        }
    }
    

    <强> DAO

    class MyDAO {
    
        public bloolean isBeingPublished(Long recordID){
            // bigbang
        }
    
        public boolean setBeingPublished(Long recordID){
            // bigbang
        }
    }
    

    使用上述设计,两个问题都在解决。

答案 1 :(得分:1)

  

首先,将!dao.isBeingPublished(id)和   dao.setBeingPublished(id)可以在同一个事务中执行,也可以在   单独的?

除非有一个用@Transactional注释的方法,否则它们将在不同的交易中发生,所以是的,你将有可能出现竞争条件。

如果我是你,我会抛弃isBeingPublishedsetBeingPublished,转而使用一个@Transactional publishIfPossible方法,该方法返回一个布尔值,表明它是否能够获取数据库行锁并执行发布操作。