【问题标题】:Spring nested transactions not working with jOOQSpring 嵌套事务不适用于 jOOQ
【发布时间】:2015-12-29 20:02:05
【问题描述】:

我想使用 Spring @Transactional 管理我的事务,并通过关注 this example 来支持嵌套事务。

我的问题是,如果我打电话给UserService.addAdmin(),那么SpringTransactionProvider.begin()SpringTransactionProvider.commit() 由于某种原因没有被调用,这表明它没有按照我的方式工作..

我正在实施我的service

/*
 *
 */
public class UserService {

    private final static Logger LOGGER = Logger.getLogger(UserService.class.getName());

    private AdminRepository adminRepository;

    public UserService(DSLContext ctx) {        
        this.adminRepository = new AdminRepository(ctx);
    }

    @Transactional
    public void addAdmin(String userId) {
        DSLContext ctx = adminRepository.getCtx();
        ctx.insertInto(Admin.ADMIN)
            .set(Admin.ADMIN.USER_NAME, userId)
            .execute();
    }
}

以及定义我的configuration file servlet-context.xml

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" value="jdbc:postgresql://localhost:5432/mz_db" />
    <property name="username" value="postgres" />
    <property name="password" value="huehuehue" />
</bean>

<!-- Configure Spring's transaction manager to use a DataSource -->
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- Configure jOOQ's TransactionProvider as a proxy to Spring's transaction manager -->
<bean id="transactionProvider"
    class="com.mz.server.web.SpringTransactionProvider">
</bean>

<!-- Configure jOOQ's ConnectionProvider to use Spring's TransactionAwareDataSourceProxy,
     which can dynamically discover the transaction context -->
<bean id="transactionAwareDataSource"
    class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg ref="dataSource" />
</bean>

<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
    <constructor-arg ref="transactionAwareDataSource" />
</bean>

<!-- Configure the DSL object, optionally overriding jOOQ Exceptions with Spring Exceptions -->
<bean id="dsl" class="org.jooq.impl.DefaultDSLContext">
    <constructor-arg ref="config" />
</bean>

<!-- Invoking an internal, package-private constructor for the example
     Implement your own Configuration for more reliable behaviour -->
<bean class="org.jooq.impl.DefaultConfiguration" name="config">
    <property name="SQLDialect"><value type="org.jooq.SQLDialect">POSTGRES_9_4</value></property>
    <property name="connectionProvider" ref="connectionProvider" />
    <property name="transactionProvider" ref="transactionProvider" />
</bean>

<!-- BEGIN Services -->

<bean id="userService" class="com.mz.server.web.service.UserService">
    <constructor-arg>
        <ref bean="dsl" />
    </constructor-arg>
</bean>

基本上是SpringTransactionProvider的副本:

public class SpringTransactionProvider implements TransactionProvider {

    private final static Logger LOGGER = Logger.getLogger(SpringTransactionProvider.class);

    @Autowired
    DataSourceTransactionManager txMgr;

    public SpringTransactionProvider() {
        LOGGER.info("Ctor()");
    }

    @Override
    public void begin(TransactionContext ctx) {
        LOGGER.info("##### begin #####");
        TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED));
        ctx.transaction(new SpringTransaction(tx));
    }

    @Override
    public void commit(TransactionContext ctx) {
        LOGGER.info("##### commit #####");
        txMgr.commit(((SpringTransaction) ctx.transaction()).tx);
    }

    @Override
    public void rollback(TransactionContext ctx) {
        LOGGER.info("##### rollback #####");        
        txMgr.rollback(((SpringTransaction) ctx.transaction()).tx);
    }
}

我本来希望看到

INFO  com.mz.server.web.SpringTransactionProvider  - Ctor()
DEBUG com.mz.server.web.servlet.UserServletImpl    - Login request by userId: username
INFO  com.mz.server.web.SpringTransactionProvider  - #### begin ####
INFO  com.mz.server.web.service.UserService        - Yay!
INFO  com.mz.server.web.SpringTransactionProvider  - #### commit ####

但我只是得到

INFO  com.mz.server.web.SpringTransactionProvider  - Ctor()
DEBUG com.mz.server.web.servlet.UserServletImpl    - Login request by userId: username
INFO  com.mz.server.web.service.UserService        - Yay!

为什么SpringTrancationProvider 没有被使用?

【问题讨论】:

    标签: java sql spring jooq


    【解决方案1】:

    jOOQ 的TransactionProvider 为显式jOOQ transaction API 提供了一个实现,将其连接到Spring,您似乎没有使用它。使用显式 jOOQ 事务 API 的 addAdmin() 方法示例如下:

    // no @Transactional - no need for declarative transaction management
    public void addAdmin(String userId) {
        adminRepository.getCtx().transaction(configuration -> {
            DSL.using(configuration)
               .insertInto(Admin.ADMIN)
               .set(Admin.ADMIN.USER_NAME, userId)
               .execute();
        });
    }
    

    如果您使用 Spring 的声明式 @Transaction API,则不涉及 TransactionProvider。换句话说,你不需要它。

    【讨论】:

    • 啊好吧,我明白了!我想使用@Transactional 的原因是,例如在使用 Spring 的 Hibernate 中,没有它就没有会话。没有会话会引发异常。如果我在 jOOQ without @Transactional 中执行 INSERT 语句并抛出异常,则记录将被保留(不回滚)。但是 with @Transactional 会执行回滚。我不太清楚为什么会这样。
    • 所以主要问题是:我可以将 Springs 声明式注释与 jOOQ 一起使用并按照我的方式嵌套事务吗?如果可能的话,我更喜欢使用声明性事务而不是使用DSLContext.transaction(),以便拥有内部保存点和回滚。
    • 是的,您可以毫无问题地使用 Spring 的声明式事务。 jOOQ 只是类型安全的 JDBC,因此无论您在哪里编写 JDBC 语句,都可以编写 jOOQ 语句。 jOOQ 中的任何内容都不会妨碍它。只需为 jOOQ 提供来自 Spring 的任何 DataSource 即可。我怀疑 jOOQ 的 TransactionProvider 的意义是什么有点混乱......
    • 好的,我明白了!我想我对 Spring 如何处理嵌套事务也有错误的理解。很难同时学习三个大框架..我可以告诉..但是一如既往地感谢您的帮助! :)
    • 我同意。我学到了很多东西,但我是从 GWT、Hibernate 和 Spring 开始的。每个框架都有自己相当平坦的学习曲线,恕我直言 ^^ 现在我开始工作了,由于我在博客中阅读的内容,我离开了 Hibernate,现在我正在过渡到 jOOQ,这意味着我必须学习另一个框架.但我不是在抱怨 :D 只是大量的工作会扼杀大量的空闲时间。但就像你说的,这是一项很好的投资:)
    猜你喜欢
    • 2016-09-10
    • 2017-09-21
    • 1970-01-01
    • 2021-11-04
    • 2019-07-12
    • 2018-11-04
    • 2021-03-02
    • 1970-01-01
    • 2017-02-20
    相关资源
    最近更新 更多