Hibernate 和 jOOQ 共享事务

Posted

技术标签:

【中文标题】Hibernate 和 jOOQ 共享事务【英文标题】:Hibernate and jOOQ sharing a transaction 【发布时间】:2020-02-14 18:15:09 【问题描述】:

我正在尝试将 jOOQ 与 hibernate 一起放在现有的大型服务中。代码按照有人参与的方式工作,保存一个问题:jOOQ 查询似乎忽略了 Spring 事务(基于注释的方法)。

问题在于,在同一个调用堆栈中有一些休眠操作(存储库),jOOQ 看不到这些实体,而休眠可以。 我怀疑问题出在 bean 定义、单独的事务管理器或其他问题上。 请注意,我使用的不是 Spring 机器人应用程序,而是“普通”Spring(版本 5.0.8-RELEASE)。

配置是从 Spring autoconfig 复制而来的:

@Configuration
public class JooqAutoConfiguration 

    @Bean
    public DataSourceConnectionProvider dataSourceConnectionProvider(DataSource dataSource) 
        return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));
    

    @Bean
    public SpringTransactionProvider transactionProvider(PlatformTransactionManager txManager) 
        return new SpringTransactionProvider(txManager);
    

    @Bean
    @Order(0)
    public DefaultExecuteListenerProvider jooqExceptionTranslatorExecuteListenerProvider() 
        return new DefaultExecuteListenerProvider(new JooqExceptionTranslator());
    

    @Configuration
    public static class DslContextConfiguration 
        private final ConnectionProvider connection;

        private final DataSource dataSource;

        private final TransactionProvider transactionProvider;

        private final RecordMapperProvider recordMapperProvider;

        private final RecordUnmapperProvider recordUnmapperProvider;

        private final Settings settings;

        private final RecordListenerProvider[] recordListenerProviders;

        private final ExecuteListenerProvider[] executeListenerProviders;

        private final VisitListenerProvider[] visitListenerProviders;

        private final TransactionListenerProvider[] transactionListenerProviders;

        private final ExecutorProvider executorProvider;

        public DslContextConfiguration(ConnectionProvider connectionProvider,
                                       DataSource dataSource, ObjectProvider<TransactionProvider> transactionProvider,
                                       ObjectProvider<RecordMapperProvider> recordMapperProvider,
                                       ObjectProvider<RecordUnmapperProvider> recordUnmapperProvider, ObjectProvider<Settings> settings,
                                       ObjectProvider<RecordListenerProvider[]> recordListenerProviders,
                                       ExecuteListenerProvider[] executeListenerProviders,
                                       ObjectProvider<VisitListenerProvider[]> visitListenerProviders,
                                       ObjectProvider<TransactionListenerProvider[]> transactionListenerProviders,
                                       ObjectProvider<ExecutorProvider> executorProvider) 
            this.connection = connectionProvider;
            this.dataSource = dataSource;
            this.transactionProvider = transactionProvider.getIfAvailable();
            this.recordMapperProvider = recordMapperProvider.getIfAvailable();
            this.recordUnmapperProvider = recordUnmapperProvider.getIfAvailable();
            this.settings = settings.getIfAvailable();
            this.recordListenerProviders = recordListenerProviders.getIfAvailable();
            this.executeListenerProviders = executeListenerProviders;
            this.visitListenerProviders = visitListenerProviders.getIfAvailable();
            this.transactionListenerProviders = transactionListenerProviders.getIfAvailable();
            this.executorProvider = executorProvider.getIfAvailable();
        

        @Bean
        public DefaultDSLContext dslContext(org.jooq.Configuration configuration) 
            return new DefaultDSLContext(configuration);
        

        @Bean
        public DefaultConfiguration jooqConfiguration() 
            DefaultConfiguration configuration = new DefaultConfiguration();
            configuration.set(SQLDialect.mysql);
            configuration.set(this.connection);
            if (this.transactionProvider != null) 
                configuration.set(this.transactionProvider);
            
            if (this.recordMapperProvider != null) 
                configuration.set(this.recordMapperProvider);
            
            if (this.recordUnmapperProvider != null) 
                configuration.set(this.recordUnmapperProvider);
            
            if (this.settings != null) 
                configuration.set(this.settings);
            
            if (this.executorProvider != null) 
                configuration.set(this.executorProvider);
            
            configuration.set(this.recordListenerProviders);
            configuration.set(this.executeListenerProviders);
            configuration.set(this.visitListenerProviders);
            configuration.setTransactionListenerProvider(this.transactionListenerProviders);
            return configuration;
        

    


【问题讨论】:

【参考方案1】:

如果您让 Spring Boot 配置 jOOQ 的 DSLContext,以及在幕后配置 ConfigurationConnectionProvider,那么您应该不会遇到事务问题。但是请注意,Hibernate 可能没有将应用于其缓存的更改刷新到数据库,并且 jOOQ 仅直接查询数据库,而不是任何 Hibernate 缓存。

因此,您必须确保在运行任何 jOOQ(或 JDBC,或其他本机 SQL 查询)之前始终刷新 Hibernate 的会话。

【讨论】:

以上是关于Hibernate 和 jOOQ 共享事务的主要内容,如果未能解决你的问题,请参考以下文章

spring与hibernate整合事务管理的理解

Spring Hiernate整合

如何配置 Spring 使 JPA(Hibernate)和 JDBC(JdbcTemplate 或 MyBatis)共享同一个事务

SQL 方言如何在 hibernate 和 JOOQ 等框架内部实际工作

jOOQ 和 Spring 事务管理

JOOQ 与休眠 [关闭]