【问题标题】:Operations after committing a transaction in springspring 提交事务后的操作
【发布时间】:2014-11-04 23:41:59
【问题描述】:

我在 Spring 中遇到一种情况,我正在将数据写入某个外部源, 现在在将数据写入外部源之前,

  1. 我拿了一把锁
  2. 读取对象
  3. 执行一些操作
  4. 写回项目。并解锁对象。

下面的代码大致解释了我是如何做到的。

//代码从这里开始

Lock lck = new ReentrantLock();

public void manipulateData(){

lck.lock();
//Object obj = read the data
//modify it

Write(obj)
lck.unlock();

}

//代码到此结束

现在在多线程环境中,当前发生的情况是在写调用之后我正在调用解锁,但在我的函数执行完成之前我的事务不会提交。但是,由于我正在调用解锁。其他线程获取锁并读取实际正确的数据。

所以我希望只有在事务提交时才应该由其他线程获得锁之类的东西。

我也不能使用程序化事务。

【问题讨论】:

    标签: spring transactions locks


    【解决方案1】:

    你可以实现一个与此类似的 Aspect (AOP):

    首先创建一个类似这样的专有事务:

    @Target({ ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LockingTransactional {
    }
    

    那么方面有趣的代码应该是这样的:

        ...
        private final Lock lck = new ReentrantLock();
        ...
    
        @Around("@annotation(<FULL-PACKAGE-NAME-HERE>.LockingTransactional)")
        public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
            try {
                lck.lock();
                TransactionStatus status = createTransaction(); // create the transaction "manually"
                Object result;
                try {
                    result = pjp.proceed();
                } catch (Throwable t) { 
                    txManager.rollback(status);
                    throw t;
                }
                txManager.commit(status);
                return result;
            } finally {
                lck.unlock();
            }
        }
    
    ...
    
        private TransactionStatus createTransaction() {
            DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
            def.setIsolationLevel(<YOUR-LEVEL-HERE>);
            def.setPropagationBehavior(<YOUR-PROPAGATION-HERE>);
            return txManager.getTransaction(definition);
        }
    
    ...
    

    【讨论】:

      【解决方案2】:

      您可以考虑提取读取对象的代码并将其修改为不同的方法(使用@Transactional 注释)。然后应该在调用方法之前获取锁,并在方法返回后释放。像这样的:

      @Autowired
      private Dao dao;
      
      public void manipulateData(){
      
          lck.lock();
          dao.update(myObj);
          lck.unlock();
      }
      
      class Dao {
      
          @Transactional
          public void update(MyObject obj) {
              //read and modify
          }
      }
      

      【讨论】:

      • 问题是从 transcaion 开始的某个其他类调用了操作数据,我无法更改该代码。因此,每个函数都在事务的上下文中调用:(
      • 另外我不能在没有事务的情况下进行 write(obj) 调用。
      • 这是一个奇怪的设计。您能详细说明为什么要锁定该对象吗?因为如果您担心并发线程读取对象的未提交状态,那么事务隔离本身就会解决这个问题。
      猜你喜欢
      • 2015-12-17
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多