MyBatis事务处理

一.MyBatis单独使用时,使用SqlSession来处理事务

使用MyBatis,你可以写代码去控制事务操作。例如,提交事务和回滚事务。

public class MyBatisTxTest { 
 
  private static SqlSessionFactory sqlSessionFactory; 
  private static Reader reader; 
 
  @BeforeClass 
  public static void setUpBeforeClass() throws Exception { 
    try { 
      reader = Resources.getResourceAsReader("Configuration.xml"); 
      sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); 
    } finally { 
      if (reader != null) { 
        reader.close(); 
      } 
    } 
  } 
   
  @Test 
  public void updateUserTxTest() { 
    SqlSession session = sqlSessionFactory.openSession(false); // 打开会话,事务开始 
     
    try { 
      IUserMapper mapper = session.getMapper(IUserMapper.class); 
      User user = new User(9, "Test transaction"); 
      int affectedCount = mapper.updateUser(user); // 因后面的异常而未执行commit语句 
      User user = new User(10, "Test transaction continuously"); 
      int affectedCount2 = mapper.updateUser(user2); // 因后面的异常而未执行commit语句 
      int i = 2 / 0; // 触发运行时异常 
      session.commit(); // 提交会话,即事务提交 
    } finally { 
      session.close(); // 关闭会话,释放资源 
    } 
  } 
} 

xml配置文件:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
  <property name="dataSource" ref="dataSource"/> 
  <property name="transactionFactoryClass"> 
    <value>org.apache.ibatis.transaction.managed.ManagedTransactionFactory"/> 
  </property> 
</bean> 

缺点:可能会在每一个方法中,都需要添加事务的提交、回滚、关闭等,过于繁琐。

二.和Spring集成后,使用Spring的事务管理

事务管理方式:spring支持编程式事务管理和声明式事务管理两种方式。

1、@ Transactional  声明式事务处理

(1)为了使用Spring的事务处理能力,我们需要配置TransactionManager在Spring的配置文件中。

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

(2)一旦DataSourceTransactionManager配置好了,你可以在Spring中以你通常的做法来配置事务。在事务处理期间,一个单独的SqlSession对象将会被创建和使用。当事务完成时,这个session会以合适的方式提交或回滚。这个dataSource涉及到的需要事务处理的相同的dataSource,这个将会用到SqlSessionFactory的bean中。

基于注解的事务处理特性,Spring需要先使用下面的配置:

<!-- 事务管理器 --> 
<bean id="transactionManager" 
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 
 
<!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 --> 
<tx:annotation-driven transaction-manager="transactionManager" /> 
 
<!-- 业务逻辑服务 -->
<bean id="userService" class="com.john.hbatis.service.UserService" /> 

 现在你可以在Spring的服务的Bean中注解@ Transactional。这个注解表明每个方法都是Spring来管理的。如果方法成功处理,那么Spring就会提交事务;如果在处理过程出现了错误,那么事务就会被回滚。当然,Spring将会关心MyBatis的转换过程是否出现Exceptons的DataAccessExceptions的异常栈。

@Service("userService") 
public class UserService { 
 
  @Autowired 
  IUserMapper mapper; 
 
  public int batchUpdateUsersWhenException() { // 非事务性 
    User user = new User(9, "Before exception"); 
    int affectedCount = mapper.updateUser(user); // 执行成功 
    User user2 = new User(10, "After exception"); 
    int i = 1 / 0; // 抛出运行时异常 
    int affectedCount2 = mapper.updateUser(user2); // 未执行 
    if (affectedCount == 1 && affectedCount2 == 1) { 
      return 1; 
    } 
    return 0; 
  } 
 
  @Transactional 
  public int txUpdateUsersWhenException() { // 事务性 
    User user = new User(9, "Before exception"); 
    int affectedCount = mapper.updateUser(user); // 因后面的异常而回滚 
    User user2 = new User(10, "After exception"); 
    int i = 1 / 0; // 抛出运行时异常,事务回滚 
    int affectedCount2 = mapper.updateUser(user2); // 未执行 
    if (affectedCount == 1 && affectedCount2 == 1) { 
      return 1; 
    } 
    return 0; 
  } 
} 

在测试类中加入:

@RunWith(SpringJUnit4ClassRunner.class)  // 测试运行器,基于spring mvc模式
@ContextConfiguration(locations = { "classpath:beans-da-tx.xml" }) // 引入配置文件
public class SpringIntegrateTxTest { 
 
  @Resource 
  UserService userService; 
 
  @Test 
  public void updateUsersExceptionTest() { 
    userService.batchUpdateUsersWhenException(); 
  } 
 
  @Test 
  public void txUpdateUsersExceptionTest() { 
    userService.txUpdateUsersWhenException(); 
  } 
} 

(3)下面是配置applicationContext.xml的文件:

<beans>
        <context:annotation-config />
        <context:component-scan base-package="com.owen.mybatis" />
        <context:property-placeholder
            location="classpath:application.properties" />
        <tx:annotation-driven transaction-manager="transactionManager"/>
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.
            DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.owen.mybatis.mappers" />
        </bean>
        <bean id="sqlSession"
            class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg index="0" ref="sqlSessionFactory" />
        </bean>
        <bean id="sqlSessionFactory"
            class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="typeAliases"
                value="com.owen.mybatis.domain.Student,
                com.owen.mybatis.domain.Tutor"/>
            <property name="typeAliasesPackage"
                value="com.owen.mybatis.domain"/>
            <property name="typeHandlers"
                value="com.owen.mybatis.typehandlers.PhoneTypeHandler"/>
            <property name="typeHandlersPackage"
                value="com.owen.mybatis.typehandlers"/>
            <property name="mapperLocations"
                value="classpath*:com/mybatis3/**/*.xml" />
        </bean>
        <bean id="dataSource"
            class="org.springframework.jdbc.datasource.
            DriverManagerDataSource">
            <property name="driverClassName"
                value="${jdbc.driverClassName}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
    </beans>

2、transactionTemplate  编程式事务处理

在spring配置文件中写入:

<!-- jdbc事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
    </bean>
    <!--事务模板 -->
    <bean id="transactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager">
            <ref local="transactionManager" />
        </property>
        <!--ISOLATION_DEFAULT 表示由使用的数据库决定  -->
        <property name="isolationLevelName" value="ISOLATION_DEFAULT"/>
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
          <!-- <property name="timeout" value="30"/> -->
    </bean>
    <!-- 启动使用注解实现声明式事务管理的支持
    <tx:annotation-driven transaction-manager="txManager" /> -->

示例代码:

public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionTemplate transactionTemplate;
......
public boolean transfer(final Long fromId, final Long toId, final double amount) {
    return (Boolean) transactionTemplate.execute(new TransactionCallback(){
       public Object doInTransaction(TransactionStatus status) {
       Object result;
           try {
                result = bankDao.transfer(fromId, toId, amount);
           } catch (Exception e) {
                status.setRollbackOnly();
                result = false;
                System.out.println("Transfer Error!");
           }
                return result;
           }
      });
   }
}

扩展:Spring中的事务分为物理事务和逻辑事务;
物理事务:就是底层数据库提供的事务支持,如JDBC或JTA提供的事务;
逻辑事务:是Spring管理的事务,不同于物理事务,逻辑事务提供更丰富的控制,而且如果想得到Spring事务管理的好处,必须使用逻辑事务,因此在Spring中如果没特别强调一般就是逻辑事务;  

优点:一旦事务创建之后,MyBatis-Spring将会透明的管理事务。在你的DAO或Service类中就不需要额外的代码了。

原文地址:https://www.cnblogs.com/xsl1995/p/9805112.html