繁体   English   中英

Spring JDBC事务性副作用

[英]Spring JDBC Transactional side effects

我有一个带有2个MySQL表的安装程序:Job和Summaries。

我正在尝试检查事务管理是否确实按预期工作:

以下是功能:

@Transactional("mysqlTransactionManager")
public void sumLicenseDayUsage(List<LicenseUsage> usages)
{
        Job job = startJob();

        calculateDailyUsage(usages);

        updateJob(usages, job);
        completeJob(job);
}

我确保calculateDailyUsage()引发异常。 此处的不同功能将MyBatis映射器用于实际的SQL命令。

我希望当引发异常时,尽管在startJob()中创​​建了行,但Job Table中将不存在任何行。 仍然总是创建一行,并且从不回滚。

我认为我是根据文档在书中使用它的,但显然我一定会丢失一些东西。

与我使用MyBatis的事实有关吗? 还是事实是有2个表,因此有2个不同的映射器? 从文档和进行各种测试来看,IT看起来都不像。

这是我的XML配置:

<tx:annotation-driven transaction-manager="mysqlTransactionManager"/>

<bean id="mysqlBuilder" class="com.company.project.mysqlutils.EmbeddedMysqlDatabaseBuilder">
    <constructor-arg value="sql/create_sum_tables.sql"/>
</bean>


<bean id="billingDB" class="com.company.project.mysqlutils.EmbeddedMysqlDatabase" factory-bean="mysqlBuilder" factory-method="build"
      destroy-method="shutdown"/>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="billingDB" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="billingDB" />
    <property name="mapperLocations" value="classpath*:META-INF/mappers/mysql/**.xml" />
</bean>

<bean id="mysqlTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="billingDB" />
</bean>

<bean id="sumLicenseDayMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.company.project.sumtables.mappers.SumLicenseDayMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

<bean id="jobsMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.company.project.sumtables.mappers.JobsMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

提前Thx

回答我自己的问题,因为我认为这个问题被很多人忽略了,并且可能对应用程序的事务处理方案产生巨大的影响

事实证明,该问题与Spring如何管理事务无关。 实际上效果很好。

但是,数据库(在这种情况下为MySQL)的行为是导致事务过早提交的原因。

根据http://dev.mysql.com/doc/refman/5.5/zh-CN/implicit-commit.html上的MySQL文档,某些DML和DDL语句导致当前事务的隐式提交。

基于Oracle和Postgres的文档,这似乎是正确的,而且MySQL报告的bug /功能也表明Oracle的行为相同: http : //bugs.mysql.com/bug.php?id=22857

就我而言,函数calculateDailyUsage()中包含一个“ CREATE TABLE”语句,该语句导致隐式提交,因此不可能回滚之前发生的所有SQL语句,以防万一该语句之后出现问题。

为了进一步说明它的重要性,假设我们设计了一个计费应用程序,在该应用程序中,超额计费是最糟糕的情况,请参见下面的示例:

@Transactional("mysqlTransactionManager")
public void sumLicenseDayUsage(List<LicenseUsage> usages)
{
        insertBillingData();

        createIntermediateTable();

        summarizeData();
}

在上面的代码中,如果summaryData()中出现问题,我们肯定希望回滚insertBillingData()插入的数据。 但这实际上不会发生,因为中间语句createIntermediateTable()实际上会提交事务,summaryData()将在不同的事务中完成。 这非常糟糕,设计人员应注意这一点,因为在应用程序中创建临时表是很常见的。

解决方法和解决方法是将所有DDL / DML语句放在函数的开头,以便它们在其事务中执行,而函数的其余部分在另一个事务中完成,可以在其中正确回滚出现问题的情况如下:

@Transactional("mysqlTransactionManager")
public void sumLicenseDayUsage(List<LicenseUsage> usages)
{
        createIntermediateTable();

        insertBillingData();

        summarizeData();
}

最后,要记住的一件事是,有时文档是不准确的,例如MySQL文档指出“ CREATE TEMPORARY TABLE”并没有进行隐式提交,尽管在我对其进行了全面测试之后才这样做。

希望能有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM