【问题标题】:Commit during transaction in @Transactional在@Transactional 中的事务期间提交
【发布时间】:2012-10-15 14:34:20
【问题描述】:

是否可以在标记为 Spring 的 @Transactional 的方法中执行提交?

@PersistenceContext
private EntityManager em;

@Transactional(propagation = Propagation.REQUIRED)
public void saveMembersWithMultipleCommits(List<Member> members)
    throws HibernateException
{
    Iterator<Member> it = members.iterator();
    while (it.hasNext())
    {
        while (it.hasNext())
        {
            Member wsBean = it.next();
            em.persist(wsBean); // overall commit will be made after method exit
            log.info("Webservices record " + wsBean + " saved. " + i++);
        }
    }
}

我想在说每 500 个项目后提交给 DB。在上述情况下这可能吗?

【问题讨论】:

    标签: spring hibernate jpa transactions transactional


    【解决方案1】:

    不,您需要使用例如TransactionTemplate API 以编程方式进行。阅读更多here

    看起来像

    while (it.hasNext())
    {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                int counter = 0;
                while (it.hasNext() && counter++ < 500) {
                    Member wsBean = it.next();
                    em.persist(wsBean);
                    log.info("Webservices record " + wsBean + " saved. " + i++);
                }
            }
        );
    }
    

    【讨论】:

    • 所以每次回调我都会有一个新的数据库连接?
    • @MichaelZ 不,只是一个新交易。
    【解决方案2】:

    您的问题表明您放错了交易边界。

    您可以将持久调用移动到私有方法中,并使该方法具有事务性,而不是外部方法。此方法一次可以接受 500 个成员,然后在退出时提交。

    【讨论】:

    • 需要加载时或编译时编织,不适用于 Springs“标准”基于代理的编织。
    【解决方案3】:

    如果您希望在其他事务中以事务方式提交,您可能需要使用@Transactional (propagation = Propagation.REQUIRES_NEW)

    【讨论】:

    • 我是否会为第二个@Transactional 方法调用打开新的数据库连接,或者它将是同一个连接?
    • 这是一个完全分开的transaction,但连接是一样的。自己检查一下。我可能犯了一个错误。
    【解决方案4】:

    替代策略是您在 DAO 中创建一个方法并将其标记为@Transactional。此方法将进行批量更新(例如 500 个)。所以你可以有一个带有代码的方法

    @Transactional
    
    public void mybatchUpdateMethod(){
    
        StatelessSession session = this.hibernateTemplate.getSessionFactory()
                .openStatelessSession();
    
        Transaction transaction = null;
    
        Long entryCounter = 0L;
    
        PreparedStatement batchUpdate = null;
        try {
            transaction = session.beginTransaction();
            batchUpdate = session.connection().prepareStatement(insertSql);
    
            for (BatchSnapshotEntry entry : entries) {
                entry.addEntry(batchUpdate);
                batchUpdate.addBatch();
    
                if (++entryCounter == 500) {
                    // Reached limit for uncommitted entries, so commit
                    batchUpdate.executeBatch();
                }
            }
    
            batchUpdate.executeBatch();
            batchUpdate.close();
            batchUpdate = null;
        }
        catch (HibernateException ex) {
            transaction.rollback();
            transaction = null;
        }
    }
    

    每次调用此方法时,都会在 500 次插入/更新后提交

    【讨论】:

    • 这里的 hibernateTemplate 是什么?什么课?
    • 对不起。应该已经澄清了。我正在举一个带有休眠和使用 hibernateTemplate 的 spring 示例。您正在使用 JPA 中的 EntityManager 并且可以使用它。你可以这样做 Session session = entityManager.unwrap(Session.class);会话是休眠会话
    • 哪个版本的休眠? JPA 的 EntityManager 有 hibernateTemplate 吗?
    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多