2015-09-27 48 views
0

我有这种方法遍历列表并调用存储过程。它运行良好。在多线程进程中运行存储过程

@Transactional(propagation = Propagation.SUPPORTS) 
public class SomeService{ 

@Autowired  
MyJpaConfiguration myJpaConfiguration ; 

private String runProcedure(...){   
    for (int j = 0; j < size; j++) { 
     EntityManager entityManager = myJpaConfiguration.mainUnitEM(); 
     Query query = entityManager.createNativeQuery("CALL PROCEDURE(params...)");  
     query.setParameter(...);     
     query.executeUpdate(); 
    } 
} 
} 

现在,为了加快这一进程,我希望做同样的事情,但在并行调用,所以我的代码变得

@Transactional(propagation = Propagation.SUPPORTS) 
public class SomeService{ 

@Autowired 
MyJpaConfiguration myJpaConfiguration ; 

private String runProcedure(...){  
    ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); 
    for (int j = 0; j < size; j++) { 
    executor.submit(new Callable<String>(){ 
         public String call() throws Exception { 
          EntityManager entityManager = myJpaConfiguration.mainUnitEM(); 
          Query query = entityManager.createNativeQuery("CALL PROCEDURE(params...)");  
          query.setParameter(...);     
          query.executeUpdate(); 
          return "Ok"; 
          } 
        });  
    } 
} 
} 

并行运行的代码时,我的问题是,我得到这个错误:

javax.persistence.TransactionRequiredException: Executing an update/delete query 

据我所知,由于某种原因,新的线程没有找到当前事务上下文所以我手动企图以

开始交易
entityManager.getTransaction().begin(); 
... 
entityManager.getTransaction().commit(); 

,但我得到

A JTA EntityManager cannot use getTransaction() 

这使得SENS因为它是一个容器管理事务。

在这一点上,我只是不知道如何在多线程环境中管理事务。

我对JTA使用Spring3.2,Hibernate 3.6,atomikos 3.8。

回答

1

您可以使用TransactionTemplate的(见the example

@Autowired 
private TransactionTemplate txTemplate; 
/** 
* Insert new user using transactionTemplate. 
* @param user 
*/ 
public void insertUserByTxTemplate(final User user) { 
    txTemplate.execute(new TransactionCallback() { 

     @Override 
     public Void doInTransaction(TransactionStatus txStatus) { 
      try { 
       Session session = sessionFactory.getCurrentSession(); 
       session.save(user); 
       throw new RuntimeException("Exception throwed!"); 
      } catch (Exception e) { 
       txStatus.setRollbackOnly(); 
      } 
      return null; 
     } 
    }); 
} 

你可以只是包装在TransactionCallback存储过程调用。

+0

这个答案将解决你的问题,但它不能解释为什么。请注意,JPA会话是_NOT_线程安全的,Spring管理事务是线程爆炸。 – lscoughlin