多个存储库上的 JOOQ @Transactional

Posted

技术标签:

【中文标题】多个存储库上的 JOOQ @Transactional【英文标题】:JOOQ @Transactional on multiple repository 【发布时间】:2019-02-11 13:49:41 【问题描述】:

情况:

我安排了一个 15 分钟长的任务。它重新生成 2 个表。我想在 ONE 交易中进行,但是使用 @Transational,repo 调用有 2 个不同的交易,用于很多 repo 调用。

这是一个带有 postgres 的 spring boot 2 项目。

repos 有可能有不同的连接吗?

(我删除并简化了一些 DI。)

代码示例:

@Scheduled(...)
public class ScheduledTaskRunner

    @Transactional
    public void run()
    
        aService.parseXML();
        bService.parseCSV();
    


@Service
public class AService

    public function parseXML()
    
         for (Node node : parserMethodSomewhere())
         
            aRepository.save(node.getDataA(), node.getDataB());
         
    


@Service
public class BService

    public function parseCSV()
    
         for (Node node : parserMethodSomewhere())
         
            bRepository.save(node.getDataA(), node.getDataB());
         
    


@Service
public class ConnectionService

    @Autowired
    private DataSource dataSource;
    private Connection connection = null;

    public Connection getConnection() throws SQLException
    
        if (null == connection)
        
            connection = dataSource.getConnection();
        

        return connection;
    


@Service
public class JooqService

    @Autowired
    private Connection connection;
    private DSLContext dslContext = null;

    public DSLContext createQueryBuilder()
    
        if (null == dslContext)
        
           this.dslContext = DSL.using(connection, SQLDialect.POSTGRES);
        

        return dslContext;
    


@Repository
public abstract class AbstractRepository

    @Autowired
    private JooqService jooqService;

    DSLContext createQueryBuilder()
    
        return jooqService.createQueryBuilder();
    


public function ARepository extends AbstractRepository

    public function save(int a, int b)
    
        createQueryBuilder().insertInto(table, table.a, table.b).values(a, b).execute();
    


public function BRepository extends AbstractRepository

    public function save(int a, int b)
    
        createQueryBuilder().insertInto(table, table.a, table.b).values(a, b).execute();
    

============================================== 变通方法 - 解决方案:

@Scheduled(...)
public class ScheduledTaskRunner

    // @Transactional
    public void run()
    
        jooqService.createQueryBuilder().transaction(
            (configuration) ->
            
                aService.parseXML();
                bService.parseCSV();
            
        );
    

【问题讨论】:

【参考方案1】:

我不确定这是否能解决您的问题,但您确实不应该在 Service 中引用 static DSLContext,尤其是因为您的 DSLContext 引用了个人 Connection。您的设计意味着任何 JooqService 实现都将使用相同的 JDBC 连接。

我也怀疑你是否也应该缓存你的 JDBC Connection。理想情况下,您的 DSLContext 直接包装 DataSource。这是将 jOOQ 插入到您配置的事务管理的最佳方式,方法是从数据源正确获取 Connection,并在使用后通过为您调用 Connection.close() 再次释放它。

【讨论】:

静态只是我最后一次尝试。现在,我将缓存添加到 ConnectionService 中的 getter,并将记录器添加到 getter。我只有一个电话:HikariProxyConnection@2021993849 返回。看起来我只有一个连接,但我仍然遇到同样的问题。 DSL.using() 上有第三个参数调用设置。现在我看到了一个默认配置: DefaultConfiguration [ connected=true, transactional=false, dialect=POSTGRES, data=, settings=... 我应该在某处添加一个 transactionProvider 吗? @KrizsánBalazs:使用基于 Spring / Annotation 的配置时会发生很多神奇的事情。您可能不再使用您发布的代码,所以我可能会发现错误的树(例如静态引用)。通常,您应该只将DataSource 传递给jOOQ,一切都会奏效。仅当您使用 jOOQ 事务 API 时才可能需要事务提供程序,而您不需要。 jOOQ 以这种方式完全忽略了 Spring 的事务,这意味着您遇到的 Spring 问题比 jOOQ 问题更多。 @KrizsánBalazs:也许最好重新开始,并尝试重新配置?也许您可以将您的配置基于基于 Spring 的 jOOQ 示例之一? github.com/jOOQ/jOOQ/tree/master/jOOQ-examples

以上是关于多个存储库上的 JOOQ @Transactional的主要内容,如果未能解决你的问题,请参考以下文章

分叉存储库上的原始存储库问题

Nexus 存储库上的 conda 包

sh 删除本地和远程存储库上的所有标记(小心)

删除不再在远程存储库上的本地 git 标签

使用 gradle 解决代理存储库上的 ivy 依赖关系会导致资源丢失

如何在GIT Rebase Interactive Squash之后删除远程存储库上的历史记录提交消息