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

一、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;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, spring
, mybatis
事务
mybatis事务配置详解、java mybatis事务回滚、java框架mybatis、java mybatis事务提交、java mybatis 事务,以便于您获取更多的相关知识。

时间: 2024-08-04 03:52:00

详解Java的MyBatis框架中的事务处理_java的相关文章

详解Java的MyBatis框架中SQL语句映射部分的编写_java

1.resultMapSQL 映射XML 文件是所有sql语句放置的地方.需要定义一个workspace,一般定义为对应的接口类的路径.写好SQL语句映射文件后,需要在MyBAtis配置文件mappers标签中引用,例如: <mappers> <mapper resource="com/liming/manager/data/mappers/UserMapper.xml" /> <mapper resource="com/liming/manag

详解Java的MyBatis框架中的缓存与缓存的使用改进_java

一级缓存与二级缓存MyBatis将数据缓存设计成两级结构,分为一级缓存.二级缓存: 一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存.一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改): 二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Appl

详解Java的Hibernat框架中的Map映射与SortedMap映射_java

Map映射Map映射是一个java集合存储在键 - 值对的元素,并且不允许在列表中重复的元素. Map接口提供三种collection视图,允许Map内容看作是一组键-值集合,或者设置键 - 值映射关系. Map被映射到映射表中一个<map>元素和无序的地图可以在java.util.HashMap中被初始化. 定义RDBMS表: 考虑一个情况,我们需要员工记录存储在EMPLOYEE表,将有以下结构: create table EMPLOYEE ( id INT NOT NULL auto_in

详解Java的MyBatis框架与Spring框架整合中的映射器注入_java

MyBatis-Spring允许你在Service Bean中注入映射器.当使用映射器时,就像调用DAO那样来调用映射器就可以了,但是此时你就不需要进行任何DAO实现的编码,因为MyBatis会为你进行. 使用注入的映射器,你的代码就不会出现任何MyBatis-Spring依赖和MyBatis依赖.在我们的应用中有这样一个简单的映射器.你也应该知道映射器仅仅是一个接口: public interface UserMapper { User getUser(String userId); } 这是

详解Java的Struts框架中栈值和OGNL的使用_java

值栈:值栈是一个集合中的几个对象保持下列对象提供的顺序: 值栈可以通过JSP,Velocity或者Freemarker的标签.有各种不同的标签在单独的章节中,我们将学习,用于获取和设置Struts 2.0 的值栈. ValueStack的对象里面可以得到动作如下: ActionContext.getContext().getValueStack() 一旦拥有了值对象,就可以用下面的方法来操纵该对象: OGNL:对象图形导航语言(OGNL)是一个功能强大的表达式语言是用来参考值栈上的数据和操纵.

详解Java的Hibernate框架中的Interceptor和Collection_java

Interceptor讲到Interceptor,相信熟悉struts2的童鞋肯定不会陌生了,struts2可以自定义拦截器进行自己想要的一系列相关的工作.而这里我们说的Interceptor也是差不多相似的功能.  废话不说,直接来代码:  下面这个是MyInterceptor类,它实现了Interceptor接口: public String onPrepareStatement(String arg0) { return arg0; } public boolean onSave(Obje

详解Java的Hibernate框架中的注解与缓存_java

注解Hibernate注解是一个没有使用XML文件来定义映射的最新方法.可以在除或替换的XML映射元数据使用注解. Hibernate的注解是强大的方式来提供元数据对象和关系表的映射.所有的元数据被杵到一起的代码POJO java文件这可以帮助用户在开发过程中同时要了解表的结构和POJO. 如果打算让应用程序移植到其他EJB3规范的ORM应用程序,必须使用注解来表示映射信息,但仍然如果想要更大的灵活性,那么应该使用基于XML的映射去. 环境设置Hibernate注释 首先,必须确保使用的是JDK

详解Java的Hibernate框架中的缓存与原生SQL语句的使用_java

Hibernate缓存缓存是所有关于应用程序的性能优化和它位于应用程序和数据库之间,以避免数据库访问多次,让性能关键型应用程序有更好的表现. 缓存对Hibernate很重要,它采用了多级缓存方案下文所述: 第一级缓存: 第一级缓存是Session的缓存,是一个强制性的缓存,通过它所有的请求都必须通过. Session对象不断自身的动力的对象,提交到数据库之前. 如果发出多个更新一个对象,Hibernate试图拖延尽可能长的时间做了更新,以减少发出的更新SQL语句的数量.如果您关闭会话,所有被缓存

详解Java的Hibernate框架中的缓存与二级缓存_java

缓存 今天我们就来讲一下hibernate中实体状态和hibernate缓存.  1)首先我们先来看一下实体状态:  实体状态主要分三种:transient,persitent,detached.  看英文应该就大概明白了吧.  transient:是指数据还没跟数据库中的数据相对应.  persistent:是指数据跟数据库中的数据相对应,它的任何改变都会反映到数据库中.  detached:是指数据跟数据库中的数据相对应,但由于session被关闭,它所做的修改不会对数据库的记录造成影响.