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

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

相关推荐

  • Java中JDBC事务与JTA分布式事务总结与区别

    Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务.常见的容器事务如Spring事务,容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现.所以本文暂不讨论容器事务.本文主要介绍J2EE开发中两个比较基本的事务:JDBC事务和JTA事务. JDBC事务 JDBC的一切行为包括事务是基于一个Connection的,在JDBC中是通过Connection对象进行事务管理.在JDBC中,

  • java Swing实现选项卡功能(JTabbedPane)实例代码

     Swing实现选项卡功能(JTabbedPane) 先创建JTabbedPane对象,构造函数可使用JTabbedPane(int tabPlacement).tabPlacement是JTabbedPane从接口 javax.swing.SwingConstants 继承的字段.可以是BUTTOM,TOP等.如下代码所示: JFrame jframe = new JFrame("TEST"); <a href="http://lib.csdn.net/base/do

  • Java Swing中的下拉式菜单(menu)、弹出式菜单(JPopupMenu)、选项卡窗体(JTabbedPane)组件使用案例

    菜单是GUI中最常用的组件,菜单不是Component类的子类,不能放置在普通容器中,不受布局管理器的约束,只能放置在菜单栏中. 菜单组件由菜单栏 (MenuBar).菜单(Menu)和菜单项(MenuItem)三部分组成. 一个菜单栏由若干个菜单组成,一个菜单又由若干个菜单项组成.一般菜单栏放 Frame 窗口中,只要调用 Frame 类的 setMenuBar()方法即可. 常用的菜单有:下拉式菜单和弹出式菜单(独立显示,可出现在任意地方). 一:下拉式菜单的创建步骤: 1.创建一个菜单栏.

  • 全面解析JTA 深度历险

    什么是事务处理 事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity ).一致性 ( Consistency ).隔离性 ( Isolation ) 和持久性 ( Durabilily ).关于事务最经典的示例莫过于信用卡转账:将用户 A 账户中的 500 元人民币转移到用户 B 的账户中,其操作流程如下 : 1. 将 A 账户中的金额减少 500 2. 将 B 账户中的金额增加 500 这两个操作必须保正 ACID 的事务属性:即要么全部成功,要么全部失败:假

  • Java Swing中的表格(JTable)和树(JTree)组件使用实例

    一:表格(JTable): 1.基本概念: 表格(JTable)是Swing 新增加的组件,主要是为了将数据以表格的形式显示.给显示大块数据提供了简单的机制. 2.常用构造方法: * JTable():使用系统默认的模型创建一个JTable 实例.  * JTable(int numRows,int numColumns):创建一个使用DefaultTableModel 指定行.列的空表格.  * JTable(Object[ ][ ] rowData,Object[ ][ ] columnNa

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

    一.MyBatis单独使用时,使用SqlSession来处理事务: public class MyBatisTxTest { private static SqlSessionFactory sqlSessionFactory; private static Reader reader; @BeforeClass public static void setUpBeforeClass() throws Exception { try { reader = Resources.getResourc

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

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

  • 详解Java的MyBatis框架中动态SQL的基本用法

    有些时候,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息.使用Oracle的序列.mysql的函数生成Id.这时我们可以使用动态sql.下文均采用mysql语法和函数(例如字符串链接函数CONCAT). selectKey 标签 在insert语句中,在Oracle经常使用序列.在MySQL中使用函数来自动生成插入表的主键,而且需要方法能返回这个生成主键.使用myBatis的select

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

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

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

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

  • 详解Java的Spring框架中的事务管理方式

    数据库事务是被当作单个工作单元的操作序列.这些操作要么全部完成或全部不成功.事务管理是面向企业应用程序,以确保数据的完整性和一致性RDBMS中的重要组成部分.事务的概念可以用下面的描述为ACID四个关键属性来描述: 原子性: 一个事务应该被视为单个操作单元表示的操作的任一整个序列是成功的或不成功的. 一致性: 这代表了数据库的参照完整性,在桌等唯一主键的一致性 隔离性: 可能有很多事务处理相同的数据集的同时,每个事务都应由他人隔离,以防止数据损坏. 持久性: 一旦事务完成,本次事务的结果必须作出

  • 详解Java的MyBatis框架和Spring框架的整合运用

    单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用spring来管理的事务,因此mybatis最好与spring集成起来使用. 版本要求 项目 版本 下载地址 说明 mybatis 3.0及以上 https://github.com/mybatis/mybatis-3/releases spring 3.0及以上 http://projects.spring.io/spring-framework/ mybatis-spring 1.0

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

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

  • 详解Java的Spring框架中bean的定义以及生命周期

    bean的定义 形成应用程序的骨干是由Spring IoC容器所管理的对象称为bean.bean被实例化,组装,并通过Spring IoC容器所管理的对象.这些bean由容器提供,例如,在XML的<bean/>定义,已经看到了前几章的形式配置元数据创建. bean定义包含所需要的容器要知道以下称为配置元数据的信息: 如何创建一个bean Bean 生命周期的详细信息 Bean 依赖关系 上述所有配置元数据转换成一组的下列属性构成每个bean的定义. Spring配置元数据 Spring IoC

  • 详解Java的Spring框架中bean的注入集合

    使用value属性和使用<property>标签的ref属性在你的bean配置文件中的对象引用,这两种情况下可以处理单值到一个bean,如果你想通过多元值,如Java Collection类型List, Set, Map 及 Properties.要处理这种情况,Spring提供了四种类型的如下集合的配置元素: 可以使用<list> 或<set> 来连接任何实现java.util.Collection或数组. 会遇到两种情况(a)将收集的直接的值及(b)传递一个bean

随机推荐