Spring+mybatis中事务管理

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

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

上面都是我找到资料,一大堆,总之使用声明式事务,而且是比较灵活的基于@Transaction注解。如果是需要项目清晰,还是推荐使用标签式声明事务,编程式事务就不特别的解释了,因为用的少。

基于@Transaction注解

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

public interface PlatformTransactionManager {

  TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

  void commit(TransactionStatus status) throws TransactionException;

  void rollback(TransactionStatus status) throws TransactionException;
}

其中TransactionDefinition接口定义以下特性:

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。

- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。

- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。

- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。

默认为读写事务。

spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。

可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。

还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

@Transactional属性

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

用法

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional
注解,这将被忽略,也不会抛出任何异常。

默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

基于XML标签

<tx:advice id="userTxAdvice" transaction-manager="transactionManager">
  <tx:attributes>
       <tx:method name="delete*" propagation="REQUIRED" read-only="false"  rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />
       <tx:method name="insert*" propagation="REQUIRED" read-only="false"  rollback-for="java.lang.RuntimeException" />
       <tx:method name="update*" propagation="REQUIRED" read-only="false"  rollback-for="java.lang.Exception" />
       <tx:method name="find*" propagation="SUPPORTS" />
       <tx:method name="get*" propagation="SUPPORTS" />
       <tx:method name="select*" propagation="SUPPORTS" />
  </tx:attributes>
 </tx:advice>

属性和基于注解一个意思,只不过俩者的区别就是上面是可以随心所欲的修改,而下面就是一个模板,每次声明事务就不需要设定属性了。

此次项目所用的代码:

	<context:property-placeholder location="classpath:jdbc.properties" />

	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<property name="initialSize" value="${jdbc.initialSize}" />
		<property name="maxTotal" value="20" />
	</bean>

	<!-- spring容器 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 加载mybatis -->
		<!-- <property name="configLocation" value="classpath:mybatis.xml"/> -->
		<property name="dataSource" ref="dataSource" />
		<property name="typeAliasesPackage" value="com.yc.crm.entity" /> <!--指定类的别名 -->
		<property name="mapperLocations" value="classpath:com/yc/crm/entity/*.xml" /> <!-- 指定扫描所有指定路径的所有映射文件 -->
	</bean>

	<!-- 加载所有映射接口bean bean的id为接口名的首字母小写 为UserMapper 和 MsgMapper这些类注入参数 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.yc.crm.mapper" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>

	<!-- 事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- way01:基于注解 -->
	<tx:annotation-driven transaction-manager="transactionManager" />

	<!-- way02:基于xml标签
	<tx:advice id="userTxAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="delete*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />
			<tx:method name="insert*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.RuntimeException" />
			<tx:method name="update*" propagation="REQUIRED" read-only="false"
				rollback-for="java.lang.Exception" />
			<tx:method name="find*" propagation="SUPPORTS" />
			<tx:method name="get*" propagation="SUPPORTS" />
			<tx:method name="select*" propagation="SUPPORTS" />
		</tx:attributes>
	</tx:advice> -->

参考文章:

http://www.cnblogs.com/xusir/p/3650522.html

http://www.360doc.com/content/14/0606/23/13272601_384429908.shtml

我是菜鸟,我在路上。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-02 23:07:08

Spring+mybatis中事务管理的相关文章

Spring.NET中事务管理【转】

http://www.cnblogs.com/GoodHelper/archive/2009/11/16/springnet_transaction.html 浏览了下写的比较清楚. 在.NET FCL中,有三类API可以执行事务管理,分别是ADO.NET.企业服务和System.Transactions.Spring.NET中对三种都提供了支持.

Spring Transaction + MyBatis SqlSession事务管理机制研究学习

线上的系统中,使用的是Spring+Mybatis+Mysql搭建的框架,由于客户需要,最近一直在对性能提升部分进行考虑,主要是涉及Mysql的一些重要参数的配置学习,以及Spring事务管理机制的学习,因为通过观察服务器日志,发现在这两部分的时候耗时比较严重,特别是进行mysql事务提交的时候,项目源码中使用了Spring的声明式事务,即通过@Transactional注解来控制事务的开启与提交,这两天看了一些关于Spring Transaction事务的一些文章,也debug了源码,总算有点

spring boot配置mybatis和事务管理

spring boot配置mybatis和事务管理 一.spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下: <!-- Spring Boot 启动父依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId>

在Spring多数据源中事务管理

  今天在做Spring3+MyBatic3项目中,使用事务管理数据插入.但在异常情况下不回滚,找了会才发现原来是在配置事务管理器DataSourceTransactionManager时配置的数据源是另一个库的数据源. <bean id="transactionManagerLte" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <propert

Spring对Hibernate事务管理【转】

在谈Spring事务管理之前我们想一下在我们不用Spring的时候,在Hibernate中我们是怎么进行数据操作的.在Hibernate中我们每次进行一个操作的的时候我们都是要先开启事务,然后进行数据操作,然后提交事务,关闭事务,我们这样做的原因是因为Hibernate默认的事务自动提交是false,他是需要我们人为的手动提交事务,假如你不想每次都手动提交事务的话,你可以在hibernate.cfg.xml我文件中把它设置为事务自动提交: <property name="hibernate

Spring声明式事务管理(基于注解方式实现)

----------------------siwuxie095 Spring 声明式事务管理(基于注解方式实现) 以转账为例 1.导入相关 jar 包(共 10 个包) (1)导入核心 jar 包和日志相关的 jar 包 (2)导入 JdbcTemplate 的 jar 包 (3)导入 MySQL 的 JDBC 驱动包 mysql-connector-java 下载链接: https://dev.mysql.com/downloads/connector/j/ (4)导入 AOP 的 jar

spring 声明式事务管理

简单理解事务: 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元:如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元.所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的. 当这两个步骤提交了,执行完毕

spring 声明式事务管理注解方式实现

使用注解实现Spring的声明式事务管理,更加简单! 步骤: 1) 必须引入Aop相关的jar文件 2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类 3)在需要添加事务控制的地方,写上: @Transactional @Transactional注解: 1)应用事务的注解 2)定义到方法上: 当前方法应用spring的声明式事务 3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理; 4)定义到父类上: 当执行父类的方法时候应用事务. 案例: 1.

Spring框架的事务管理及应用

Spring框架简介 Spring框架是一个2003年2月才出现的开源项目,该开源项目起源自Rod Johnson在2002年末出版的<Expert One-on-One J2EE Design and Development>一书中的基础性代码.在该书中,Rod Johnson倡导J2EE实用主义的设计思想,而Spring框架正是这一思想的更全面和具体的实现.Spring框架由一个容器,一个配置和组织组件的框架,和一组内置的为事务.持久化和Web用户接口提供的服务组成.作为一种轻量级的J2E