天温习spring的事务处理机制,总结如下
对于SQL事务的概念以及ACID性质,可以参见我的另一篇博文 http://kingj.iteye.com/admin/blogs/1675011
spring的管理的事务可以分为如下2类:逻辑事务 在spring中定义的事务通常指逻辑事务,提供比物理事务更抽象,方便的事务配置管理,但也基于物理事务
物理事务 特定于数据库的事务
spring中支持一下2中事务声明方式编程式事务 当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务
声明式事务 当系统对于事务的控制粒度较粗时,应该选择申明式事务
无论你选择上述何种事务方式去实现事务控制,spring都提供基于门面设计模式的事务管理器供选择,如下是spring事务中支持的事务管理器
事务管理器实现(org.springframework.*)
使用时机
jdbc.datasource.DataSourceTransactionManager
使用jdbc的抽象以及ibatis支持
orm.hibernate.HibernateTransactionManager
使用hibernate支持(默认3.0以下版本)
orm.hibernate3.HibernateTransactionManager
使用hibernate3支持
transaction.jta.JtaTransactionManager
使用分布式事务(分布式数据库支持)
orm.jpa.JpaTransactionManager
使用jpa做为持久化工具
orm.toplink.TopLinkTransactionManager
使用TopLink持久化工具
orm.jdo.JdoTransactionManager
使用Jdo持久化工具
jms.connection.JmsTransactionManager
使用JMS 1.1+
jms.connection.JmsTransactionManager102
使用JMS 1.0.2
transaction.jta.OC4JJtaTransactionManager
使用oracle的OC4J JEE容器
transaction.jta.WebLogicJtaTransactionManager
在weblogic中使用分布式数据库
jca.cci.connection.CciLocalTransactionManager
使用jrping对J2EE Connector Architecture (JCA)和Common Client Interface (CCI)的支持
UML结构图如下
4、各种事务管理器的定义如下
JdbcTransactionManager定义如下
Xml代码
hibernate事务管理器配置如下
Xml代码
hibernate的事务管理器会注入session会话工厂,然后将事务处理委托给当前的transaction对象,事务提交时,调用commit()方法,回滚时调用rollback()方法
jpa事务管理器配置如下
Xml代码
其余事务管理器可参见spring in action中说明
5、申明式事务配置
spring特有的事务传播行为,spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的事务边界控制)下图所示为7钟事务传播机制
传播行为
含义
PROPAGATION_REQUIRED(XML文件中为REQUIRED)
表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
PROPAGATION_SUPPORTS(XML文件中为SUPPORTS)
表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY(XML文件中为MANDATORY)
表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_NESTED(XML文件中为NESTED)
表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同PROPAGATION_REQUIRED的一样
PROPAGATION_NEVER(XML文件中为NEVER)
表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
PROPAGATION_REQUIRES_NEW(XML文件中为REQUIRES_NEW)
表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。
PROPAGATION_NOT_SUPPORTED(XML文件中为NOT_SUPPORTED)
表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行
6、spring中的事务隔离级别
spring的事务隔离级别其实本质上是对SQL92标准的4种事务隔离级别的一种封装,具体参加我的博文:http://kingj.iteye.com/admin/blogs/1675011
spring的事务隔离级别如下表所示
隔离级别
含义
ISOLATION_DEFAULT
使用数据库默认的事务隔离级别
ISOLATION_READ_UNCOMMITTED
允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
ISOLATION_READ_COMMITTED
允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
ISOLATION_REPEATABLE_READ
对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE
完全服从ACID隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
7、spring事务只读属性
spring事务只读的含义是指,如果后端数据库发现当前事务为只读事务,那么就会进行一系列的优化措施。它是在后端数据库进行实施的,因此,只有对于那些有可能启动一个新事务的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,才有意义。(测试表明,当使用JDBC事务管理器并设置当前事务为只读时,并不能发生预期的效果,即能执行删除,更新,插入操作)
8、spring的事务超时
有的时候为了系统中关键部分的性能问题,它的事务执行时间应该尽可能的短。因此可以给这些事务设置超时时间,以秒为单位。我们知道事务的开始往往都会发生数据库的表锁或者被数据库优化为行锁,如果允许时间过长,那么这些数据会一直被锁定,影响系统的并发性。
因为超时时钟是在事务开始的时候启动,因此只有对于那些有可能启动新事物的传播行为(REQUIRED,REQUIRES_NEW,NESTED)的方法来说,事务超时才有意义。
9、事务回滚规则
spring中可以指定当方法执行并抛出异常的时候,哪些异常回滚事务,哪些异常不回滚事务。
默认情况下,只在方法抛出运行时异常的时候才回滚(runtime exception)。而在出现受阻异常(checked exception)时不回滚事务,这个ejb的回滚行为一致。
当然可以采用申明的方式指定哪些受阻异常像运行时异常那样指定事务回滚。
10、spring申明式事务配置
将aop,tx命名空间添加到当前的spring配置文件头中
定义一个事务AOP通知
Xml代码
定义一个事务切面,即应该在哪些类的哪些方法上面进行事务切入
Xml代码
11、结合具体的代码实现讲解spring的7种事务传播机制效果
准备环境
我们采用JDBC+ORACLE实现具体操作,首先搭建好spring的开发环境,配置好数据源,建立好Test
创建数据库结构,创建一个用户表和Book表
Sql代码
CREATE TABLE T_USER(
ID INT,
NAME VARCHAR2(200)
);
CREATE TABLE T_BOOK(
ID INT ,
NAME VARCHAR2(200)
);
搭建好的结构如下
Xml代码
destroy-method="close">
在spring包下面建立3个service
BookService
Java代码
package com.zx.spring;
import org.springframework.jdbc.core.JdbcTemplate;
public class BookService {
public static final String ADD_BOOK="insert into t_book(id,name) values(1,'duck-j2ee')";
private JdbcTemplate jdbcTemplate;
public void addBook() throws Exception{
this.jdbcTemplate.execute(ADD_BOOK);
throw new RollbackException("跳出执行");
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
UserService
Java代码
package com.zx.spring;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserService {
public static final String ADD_USER="insert into t_user(id,name) values(1,'duck')";
private BookService bs;
private JdbcTemplate jdbcTemplate;
public void addUser()throws Exception {
this.bs.addBook();
this.jdbcTemplate.execute(ADD_USER);
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public BookService getBs() {
return bs;
}
public void setBs(BookService bs) {
this.bs = bs;
}
}
创建一个ServiceFacade门面,将UserService和BookService包装起来
Java代码
package com.zx.spring;
public class ServiceFacade {
private BookService bs;
private UserService us;
public BookService getBs() {
return bs;
}
public void setBs(BookService bs) {
this.bs = bs;
}
public UserService getUs() {
return us;
}
public void setUs(UserService us) {
this.us = us;
}
public void addUserBook()throws Exception{
bs.addBook();
us.addUser();
}
}
上面我们配置了3个service接口,并在spring中配置了申明式事务。
Xml代码