欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java的MyBatis框架中的事务处理

程序员文章站 2024-03-31 20:39:04
一、mybatis单独使用时,使用sqlsession来处理事务: public class mybatistxtest { private st...

一、mybatis单独使用时,使用sqlsession来处理事务:

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(); // 关闭会话,释放资源 
    } 
  } 
} 


二、和spring集成后,使用spring的事务管理:
一个使用mybatis-spring的主要原因是它允许mybatis参与到spring的事务管理中。而不是给mybatis创建一个新的特定的事务管理器,mybatis-spring利用了存在于spring中的datasourcetransactionmanager。
一旦datasourcetransactionmanager配置好了,你可以在spring中以你通常的做法来配置事务。@transactional注解和aop样式的配置都是支持的。在事务处理期间,一个单独的sqlsession对象将会被创建和使用。当事务完成时,这个session会以合适的方式提交或回滚。
一旦事务创建之后,mybatis-spring将会透明的管理事务。在你的dao或service类中就不需要额外的代码了。

1.标准配置
要开启spring的事务处理,在spring的xml配置文件中简单创建一个datasourcetransactionmanager对象:

<bean id="transactionmanager" class="org.springframework.jdbc.datasource 
  .datasourcetransactionmanager"> 
  <property name="datasource" ref="datasource"/> 
</bean> 

指定的datasource一般可以是你使用spring的任意jdbc datasource。这包含了连接池和通过jndi查找获得的datasource。
要注意,为事务管理器指定的datasource必须和用来创建sqlsessionfactorybean的是同一个数据源,否则事务管理器就无法工作了。
 
2.容器管理事务
如果你正使用一个jee容器而且想让spring参与到容器管理事务中,那么spring应该使用jtatransactionmanager或它的容器指定的子类来配置。做这件事情的最方便的方式是用spring的事务命名空间:

<tx:jta-transaction-manager/> 

在这种配置中,mybatis将会和其它由容器管理事务配置的spring事务资源一样。spring会自动使用任意存在的容器事务,在上面附加一个sqlsession。 如果没有开始事务,或者需要基于事务配置,spring会开启一个新的容器管理事务。
注意,如果你想使用容器管理事务,而不想使用spring的事务管理,你就必须配置sqlsessionfactorybean来使用基本的mybatis的managedtransactionfactory而不是其它任意的spring事务管理器: 

<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> 

 
3.编程式事务管理
mybatis的sqlsession提供指定的方法来处理编程式的事务。但是当使用mybatis-spring时,bean将会使用spring管理的sqlsession或映射器来注入。那就是说spring通常是处理事务的。你不能在spring管理的sqlsession上调用sqlsession.commit(),sqlsession.rollback()或sqlsession.close()方法。如果这样做了,就会抛出unsupportedoperationexception异常。注意在使用注入的映射器时不能访问那些方法。无论连接是否设置为自动提交,sqlsession数据方法的执行或在spring事务之外任意调用映射器方法都将会自动被提交。下面是一个编程式事务示例:

defaulttransactiondefinition def = new defaulttransactiondefinition(); 
def.setpropagationbehavior(transactiondefinition.propagation_required); 
transactionstatus status = txmanager.gettransaction(def); 
try{ 
  usermapper.insertuser(user); 
}catch(myexception ex){ 
  throw ex; 
} 
txmanager.commit(status); 

4.@transactional方式:

在类路径下创建beans-da-tx.xml文件,在beans-da.xml(系列五)的基础上加入事务配置:

<!-- 事务管理器 --> 
<bean id="txmanager" 
  class="org.springframework.jdbc.datasource.datasourcetransactionmanager"> 
    <property name="datasource" ref="datasource" /> 
</bean> 
 
<!-- 事务注解驱动,标注@transactional的类和方法将具有事务性 --> 
<tx:annotation-driven transaction-manager="txmanager" /> 
 
<bean id="userservice" class="com.john.hbatis.service.userservice" /> 

服务类:

@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) 
@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(); 
  } 
} 


5.transactiontemplate方式

在beans-da-tx.xml中添加:

<bean id="txtemplate" class="org.springframework.transaction.support.transactiontemplate"> 
  <constructor-arg type="org.springframework.transaction.platformtransactionmanager" ref="transactionmanager" /> 
</bean> 

在userservice类加入:

@autowired(required = false) 
transactiontemplate txtemplate; 
 
public int txupdateuserswhenexceptionviatxtemplate() { 
  int retval = txtemplate.execute(new transactioncallback<integer>() { 
 
    @override 
    public integer dointransaction(transactionstatus status) { // 事务操作 
      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; 
    } 
     
  }); 
  return retval; 
} 

在springintegratetxtest类中加入:

@test 
public void updateuserswhenexceptionviatxtemplatetest() { 
  userservice.txupdateuserswhenexceptionviatxtemplate(); //  
} 

注:不可catch exception或runtimeexception而不抛出:

@transactional 
public int txupdateuserswhenexceptionandcatch() { // 事务性操作,但是外围框架捕获不到异常,认为执行正确而提交。 
  try { 
    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; 
    } 
  } catch (exception e) { // 所有异常被捕获而未抛出 
    e.printstacktrace(); 
  } 
  return 0; 
}