【问题标题】:Run a stored procedure in a multithreaded process在多线程进程中运行存储过程
【发布时间】:2015-09-27 23:33:00
【问题描述】:

我有这个方法可以遍历一个列表并调用一个存储过程。它工作得很好。

@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()

这很有意义,因为它是一个容器管理的事务。

此时,我只是不知道在多线程环境中应该如何管理事务。

我在 JTA 中使用 Spring3.2、Hibernate 3.6、atomikos 3.8。

【问题讨论】:

    标签: java multithreading spring hibernate jta


    【解决方案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 中。

    【讨论】:

    • 此答案将解决您的问题,但没有解释原因。请注意,JPA 会话是线程安全的,Spring 管理的事务是线程爆炸的。
    猜你喜欢
    • 1970-01-01
    • 2020-06-12
    • 2018-09-27
    • 2014-11-24
    • 1970-01-01
    • 2010-09-15
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多