mybatis框架学习(3) - 开启事务

事务

一个使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。

一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional 注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

事务配置好了以后,MyBatis-Spring 将会透明地管理事务。这样在你的 DAO 类中就不需要额外的代码了。

 

Spring JDBC事务

标准配置

要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <constructor-arg ref="dataSource" />
</bean>
@Bean
public DataSourceTransactionManager transactionManager() {
  return new DataSourceTransactionManager(dataSource());
}

传入的 DataSource 可以是任何能够与 Spring 兼容的 JDBC DataSource。包括连接池和通过 JNDI 查找获得的 DataSource。

注意:为事务管理器指定的 DataSource 必须和用来创建 SqlSessionFactoryBean 的是同一个数据源,否则事务管理器就无法工作了。

 

如果添加@EnableTransactionManagement注解,并且引入spring-boot-starter-jdbc包,就会引入DataSourceTransactionManager。

Spring使用以下代码打印PlatformTransacationManager的类型,DataSourceTransactionManager为JDBC事务。

@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager) {
    System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
    return new Object();
}

>>>>>>>>>>org.springframework.jdbc.datasource.DataSourceTransactionManager

在配置事务的时候连续执行2次Mapper观察日志,每次执行都是创建一个新的sqlSession。一个sqlSession属于一个事务。

@Override
public void save() {
    sysUserMapper.save();
    sysUserMapper.save2();
    if (true) {
        throw new RuntimeException();
    }
}

2019-05-30 09:48:14.042 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2019-05-30 09:48:14.046 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d7ce1f7] was not registered for synchronization because synchronization is not active
2019-05-30 09:48:14.091 [http-nio-8080-exec-1] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
2019-05-30 09:48:14.660 [http-nio-8080-exec-1] DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@3f73faa9] will not be managed by Spring
2019-05-30 09:48:14.663 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - ==>  Preparing: insert into sys_user(user_id, user_name) values(-998, '用户1') 
2019-05-30 09:48:14.681 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - ==> Parameters: 
2019-05-30 09:48:14.751 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - <==    Updates: 1
2019-05-30 09:48:14.751 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1d7ce1f7]
2019-05-30 09:48:14.752 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2019-05-30 09:48:14.752 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@28b107b9] was not registered for synchronization because synchronization is not active
2019-05-30 09:48:14.752 [http-nio-8080-exec-1] DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@3f73faa9] will not be managed by Spring
2019-05-30 09:48:14.752 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - ==>  Preparing: insert into sys_user(user_id, user_name) values(-997, '用户2') 
2019-05-30 09:48:14.752 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - ==> Parameters: 
2019-05-30 09:48:14.822 [http-nio-8080-exec-1] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - <==    Updates: 1
2019-05-30 09:48:14.822 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@28b107b9]

添加了@Transactional后在save()方法内就属于一个事务了,当事务完成sqlSessoin就会提交或回滚。jdbc事务配置成功。

@Transactional
@Override
public void save() {
    sysUserMapper.save();
    sysUserMapper.save2();
    if (true) {
        throw new RuntimeException();
    }
}

2019-05-30 09:53:36.452 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2019-05-30 09:53:36.452 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47]
2019-05-30 09:53:36.453 [http-nio-8080-exec-4] DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@5e898c28] will be managed by Spring
2019-05-30 09:53:36.454 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - ==>  Preparing: insert into sys_user(user_id, user_name) values(-998, '用户1') 
2019-05-30 09:53:36.454 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - ==> Parameters: 
2019-05-30 09:53:36.517 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save - <==    Updates: 1
2019-05-30 09:53:36.517 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47]
2019-05-30 09:53:36.517 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47] from current transaction
2019-05-30 09:53:36.517 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - ==>  Preparing: insert into sys_user(user_id, user_name) values(-997, '用户2') 
2019-05-30 09:53:36.517 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - ==> Parameters: 
2019-05-30 09:53:36.580 [http-nio-8080-exec-4] DEBUG com.pss.mybatis_spring.dao.SysUserMapper.save2 - <==    Updates: 1
2019-05-30 09:53:36.580 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47]
2019-05-30 09:53:36.580 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47]
2019-05-30 09:53:36.580 [http-nio-8080-exec-4] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@437d1c47]
2019-05-30 09:53:36.682 [http-nio-8080-exec-4] ERROR o.a.c.c.C.[.[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException] with root cause

注:集成Springboot话不需要配置也能生效,否则需要配置扫描事务AOP

<context:component-scan base-package="com.pss"/>

<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut expression="execution(* com.pss.helloworld.service.impl..*.*(..))" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

 

交由容器管理事务

如果使用多数据源且数据源事务,SysUser会回滚而untiveAdvisor不会回滚,所以需要使用容器管理事务

@Transactional
public void save(SysUser sysUser) {
    sysUserMapper.save(sysUser);
    unitiveAdvisorMapper.save(new UnitiveAdvisor());
    if (true) {
        throw new RuntimeException("自定义报错");    
    }
}

如果你正使用一个 JEE 容器而且想让 Spring 参与到容器管理事务(Container managed transactions,CMT)的过程中,那么 Spring 应该被设置为使用 JtaTransactionManager 或由容器指定的一个子类作为事务管理器。最简单的方式是使用 Spring 的事务命名空间或使用 JtaTransactionManagerFactoryBean:

@Bean
public JtaTransactionManager transactionManager() {
  return new JtaTransactionManagerFactoryBean().getObject();
}

在这个配置中,MyBatis 将会和其它由容器管理事务配置的 Spring 事务资源一样。Spring 会自动使用任何一个存在的容器事务管理器,并注入一个 SqlSession。如果没有正在进行的事务,而基于事务配置需要一个新的事务的时候,Spring 会开启一个新的由容器管理的事务。
 

接下来试验一下

创建XA协议数据源和SessionFactory

<bean id="xaDataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource">
    <property name="url" value="jdbc:mysql://localhost:3306/db1"/>
    <property name="user" value="root"/>
    <property name="password" value="root"/>
</bean>

<bean id="xaDataSource2" class="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource">
    <property name="url" value="jdbc:mysql://localhost:3306/db2"/>
    <property name="user" value="root"/>
    <property name="password" value="root"/>
</bean>

<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean">
    <property name="xaDataSource" ref="xaDataSource"/>
    <property name="uniqueResourceName" value="dataSource"/>
</bean>

<bean id="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean">
    <property name="xaDataSource" ref="xaDataSource2"/>
    <property name="uniqueResourceName" value="dataSource2"/>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath*:mapper/*.xml"/>
    <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <property name="mapUnderscoreToCamelCase" value="true"/>
        </bean>
    </property>
</bean>

<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource2"/>
    <property name="mapperLocations" value="classpath*:mapper2/*.xml"/>
    <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <property name="mapUnderscoreToCamelCase" value="true"/>
        </bean>
    </property>
</bean>

创建transactionMananger

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
    <description>UserTransactionManager</description>
    <property name="forceShutdown">
        <value>true</value>
    </property>
</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    <property name="transactionTimeout" value="90000" />
</bean>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager">
        <ref bean="atomikosTransactionManager" />
    </property>
    <property name="userTransaction">
        <ref bean="atomikosUserTransaction" />
    </property>
    <property name="allowCustomIsolationLevels" value="true" />
</bean>

<bean id="transactionManager2" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager">
        <ref bean="atomikosTransactionManager" />
    </property>
    <property name="userTransaction">
        <ref bean="atomikosUserTransaction" />
    </property>
    <property name="allowCustomIsolationLevels" value="true" />
</bean>
@Transactional
public void save(SysUser sysUser) {
    sysUserMapper.save(sysUser);
    unitiveAdvisorMapper.save(new UnitiveAdvisor());
    if (true) {
        throw new RuntimeException("自定义报错");
    }
}

[springmvc_mybatis_demo][DEBUG] [2019-06-01 20:22:42] com.atomikos.logging.Slf4jLogger.logDebug(32) | XAResource.rollback ( 3139322E3136382E332E33352E746D313535393339313736303631333030303031:3139322E3136382E332E33352E746D31 ) on resource dataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@5e268ce6
[springmvc_mybatis_demo][DEBUG] [2019-06-01 20:22:42] com.atomikos.logging.Slf4jLogger.logDebug(32) | XAResource.rollback ( 3139322E3136382E332E33352E746D313535393339313736303631333030303031:3139322E3136382E332E33352E746D32 ) on resource dataSource2 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@15bc339
[springmvc_mybatis_demo][DEBUG] [2019-06-01 20:22:42] com.atomikos.logging.Slf4jLogger.logDebug(32) | rollback() done of transaction 192.168.3.35.tm155939176061300001
[springmvc_mybatis_demo][DEBUG] [2019-06-01 20:22:42] com.atomikos.logging.Slf4jLogger.logDebug(32) | rollback() done of transaction 192.168.3.35.tm155939176061300001

看日志2个数据源都一起回滚了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
将SSM框架中的MyBatis升级到MyBatis-Plus是可行的,可以实现共存。SSM框架由Spring、Spring MVC和MyBatis组成,而MyBatis-Plus是对MyBatis的增强扩展。下面将介绍如何将它们共存。 首先,需要将MyBatis升级到MyBatis-Plus。可以将MyBatis-Plus的依赖项添加到项目的pom.xml文件中,替换原有的MyBatis依赖。然后,需要对原有的MyBatis配置文件进行修改。MyBatis-Plus提供了一些方便的功能和特性,如自动填充、逻辑删除等,可以根据项目需求选择开启或关闭。 在SSM框架中,MyBatis-Plus可以与原有的Spring框架和Spring MVC框架完美共存。Spring框架负责管理和配置各种Bean,MyBatis-Plus可以与Spring框架一起使用,将其作为DAO层的组件进行管理。在Spring的配置文件中,可以将MyBatis-Plus的配置文件加入到配置中。 在Spring MVC框架中,可以继续使用原有的控制器、服务和视图解析器等组件。MyBatis-Plus可以与Spring MVC框架无缝集成,通过Spring MVC接收请求,然后调用MyBatis-Plus进行数据访问和处理。 在具体开发过程中,可以利用MyBatis-Plus提供的一些特性简化开发工作。例如,可以使用MyBatis-Plus的代码生成器来自动生成DAO、实体类和Mapper等代码,减少手动编写的工作量。 总结来说,将SSM框架中的MyBatis升级到MyBatis-Plus是完全可以实现的,它们可以共存并完美集成。通过使用MyBatis-Plus,我们可以更加便捷地开发和管理数据库操作,提高开发效率和代码质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值