有没有办法在 JooQ 中以编程方式回滚事务?

Posted

技术标签:

【中文标题】有没有办法在 JooQ 中以编程方式回滚事务?【英文标题】:Is there a way to programmatically rollback transactions in JooQ? 【发布时间】:2018-11-17 01:00:22 【问题描述】:

在我们的应用程序中,我们使用 Either monad 来传达故障。根据Jooq transaction management 文档,@TransactionalDslContext.transaction 都需要抛出Exception 来触发事务回滚。我们更愿意根据 Either 的状态提交或回滚事务。

我们需要的伪代码如下所示:

public class DomainService 

    private DSLContext dslContext;

    public Either<SomeError, String> businessOperation() 
        return transactional(configuration ->
                firstDatabaseChange(configuration)
                .flatMap(i -> secondDatabaseChange(configuration)));

    

    private Either<SomeError, String> firstDatabaseChange(
             DSLContext dslContext) 
        //Mutate the Db in some way
    

    private Either<SomeError, String> secondDatabaseChange(
             DSLContext dslContext) 
        //Mutate the Db in some way
    


    /* How do we implement this method */
    private Either<SomeError, String> transactional(Function<DSLContext, 
             Either<SomeError, String>> function) 
        return function.apply(dslContext)
                .onSuccess(i -> /*Commit the transaction */)
                .onFailure(i -> /*Rollback the transaction*/);
    

我有以下transactional 方法的工作实现,感觉就像一个黑客。 (有趣的是,@Transactional 注释是回滚工作所必需的,即使我们没有抛出任何异常)。有没有更好的方法来做到这一点?

@Transactional
public <T> Either<SomeError, T> transactional(Function<DSLContext, 
         Either<SomeError, T>> function) 
    Connection connection = dslContext.parsingConnection();

    try 
        connection.setAutoCommit(false);
        Either<SomeError, T> either = function.apply(dslContext);
        if (either.isSuccess()) 
            connection.commit();
         else 
            connection.rollback();
        
        return result;
     catch (SQLException e) 
        log.error("SqlException encountered", e);
        return SomeError.failure(e);
     catch (Exception e) 
        try 
            connection.rollback();
         catch (SQLException e1) 
            log.error("Exception encountered while rolling back", e1);
        
        return SomeError.failure(e);
    

【问题讨论】:

我不确定你为什么认为你的实现是一个 hack。你只需要自己做。您不妨从问题中删除实现,并将其作为您自己问题的答案。 @LukasEder 感谢您的快速回复。我希望 Jooq 中有另一个 API(我没有注意到)可以让我在不下降到 Connection 级别的情况下实现这一目标。另外,我担心直接使用parsingConnection 的影响。你知道为什么仍然需要@Transactional 才能让它工作吗? 路线图上有一个替代的程序 API:github.com/jOOQ/jOOQ/issues/5376。不知道parsingConnection是怎么关联的,这里为什么会涉及@Transactional。我想你的问题并不完整,关于后者...... parsingConnection 被标记为实验性功能。因此,我想知道它在用于事务管理时是否会出现任何问题。从您链接的问题中,我看到我可以使用dslContext.connectionResult 来实现相同的结果@Transactional 理想情况下不应该存在,但我们发现connection.rollback() 在缺少注释时似乎实际上没有做任何事情.但是,这可能与我们的应用程序的设置方式非常具体。 哦,您刚刚尝试从 jOOQ 获取 any JDBC Connection?是的,DSLContext.connection()connectionResult() 是要走的路。不要使用parsingConnection()。 Javadoc 非常清楚它的用途 :) 【参考方案1】:

正如Lukas Seder 所述,Jooq 的路线图上有一个过程 API:github.com/jOOQ/jOOQ/issues/5376

在此发布之前,您可以实现如下所需的行为:

public <T> Either<SomeError, T> transactional(Function<DSLContext,
        Either<SomeError, T>> function) 
    return dslContext.connectionResult(connection -> 
        try 
            connection.setAutoCommit(false);
            Either<SomeError, T> either = function.apply(dslContext);
            if (either.isSuccess()) 
                connection.commit();
             else 
                connection.rollback();
            
            return result;
         catch (SQLException e) 
            log.error("SqlException encountered", e);
            return SomeError.failure(e);
         catch (Exception e) 
            try 
                connection.rollback();
             catch (SQLException e1) 
                log.error("Exception encountered while rolling back", e1);
            
            return SomeError.failure(e);
        
    );

【讨论】:

以上是关于有没有办法在 JooQ 中以编程方式回滚事务?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Windows 上的 C++ 中以编程方式设置环境路径?

有没有办法在Swift中以编程方式设置NSCollectionView?

有没有办法在多 GPU 环境中以编程方式选择渲染 GPU? (视窗)

有没有办法从我的 Joomla 组件中以编程方式添加菜单项?

如何在Parse中以编程方式设置类级别权限?

如何在 CUDA 中以编程方式获取卡规格