2

如果可以的话,我有几个关于 Spring 事务的问题。假设我有这个 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)anddao.setBeingPublished(id)会在同一个事务中执行还是在单独的事务中执行?

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

我的问题的解决方案到底是什么?我阅读了 spring 的事务传播并发现REQUIRES_NEW即使当前正在执行一个事务也会创建一个新事务,但是我仍然看不出这将如何解决我的问题。

预先感谢您的帮助。

4

2 回答 2

3

需要考虑的事情很少,DAO 是专注于对单个实体的操作,而 service 是专注于一个或多个实体的操作,所以事务应该放在服务层,这样你就可以在没有任何事务的情况下重用 DAO 的操作,而是让服务来决定何时开始和结束事务

  1. 它不是在单个事务中,而是在两个单独的事务中。
  2. 这是您当前设计的并发问题,请参阅以下建议。

界面

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

class MyDAO {

    public bloolean isBeingPublished(Long recordID){
        // bigbang
    }

    public boolean setBeingPublished(Long recordID){
        // bigbang
    }
}

使用上述设计,这两个问题都得到了解决。

于 2012-04-20T14:47:52.943 回答
1

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

除非有一个方法@Transactional在堆栈中进一步注释,否则它们将在单独的事务中发生,所以是的,您将有可能出现竞争条件。

如果我是你,我会抛弃isBeingPublishedandsetBeingPublished支持一个@Transactional publishIfPossible返回布尔值的方法,它是否能够获取数据库行锁并执行发布操作。

于 2012-04-20T14:47:50.983 回答