事务之间可能存在的三个问题:脏读取,不可重复读取和幻影行
PlatformTransactionManager接口:
Spring 事务管理的抽象关键在于PlatformTransactionManager接口的实现,通过依赖与PlatformTansactionManager接口和各种技术的实现,Spring提供开发者使用一致的编程模型,即使使用的是不同的事务管理技术。
public interface PlatformTransactionManager{
TansactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
TransactionException 是 Unchecked Exception,Spring不强迫开发者一定要处理,而是可以自行选择是否要捕捉异常。
TransactionDefinition 定义了事务的传播属性,隔离级别,只读和超时等属性。
TransactionStatus代表了一个新的事务或者已经存在的事务,通过它来控制事物的执行的状态。
Spring提供了编程式事务控制和声明式事务控制。
编程式事务控制可以清楚的控制事务的边界,也就是自行定义事务开始,撤销和结束等操作的时间,实现细粒度的事务控制。
声明式事务控制
声明式事务控制可以实现非侵入性的程序开发,通过配置文件将对象纳入到事务管理中。
Spring提供两种方式实现编程事务管理,一种是通过PlatformTransactionManager的实现,一种是通过org.springframework.transaction.support.TransactionTemplate
声明式事务管理:
1、通过纯粹的xml实现事务控制实例:
package com.highsoft.study.service;
public interface FooService {
public String getFooName();
public void insertFoo();
}
package com.highsoft.study.service;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;;
public class DefaultFooService implements FooService {
private Log log=LogFactory.getLog(this.getClass());
private JdbcTemplate jdbcTemplate;
@Autowired
public void init(DataSource dataSource){
jdbcTemplate = new JdbcTemplate(dataSource);
log.debug("init");
}
public String getFooName() {
return "Foo";
}
public void insertFoo() {
this.jdbcTemplate.update("insert into vets(id,first_name,last_name) values('8','11','22')");
this.jdbcTemplate.update("inser into vets(id,first_name,last_name) values('9','11','22')");
}
}
applicationContext.xml:
<import resource="applicationContext-dataSource.xml"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:annotation-config />
<bean id="fooService" class="com.highsoft.study.service.DefaultFooService"></bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.highsoft.study.service.*.*(..))" id="services"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="services"/>
</aop:config>
2、@Transactional注解
实例:
@Service
public class DefaultFooService implements FooService {
private Log log=LogFactory.getLog(this.getClass());
private JdbcTemplate jdbcTemplate;
@Autowired
public void init(DataSource dataSource){
jdbcTemplate = new JdbcTemplate(dataSource);
log.debug("init");
}
public String getFooName() {
return "Foo";
}
@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
public void insertFoo() {
this.jdbcTemplate.update("insert into vets(id,first_name,last_name) values('8','11','22')");
this.jdbcTemplate.update("inser into vets(id,first_name,last_name) values('9','11','22')");
}
}
applicationContext.xml:
<import resource="applicationContext-dataSource.xml"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<bean id="fooService" class="com.highsoft.study.service.DefaultFooService"></bean>
特别要注意的几个问题,这几个问题可能导致事务控制失败:
1、事务控制通过AOP来实现。
2、在applicationContext声明需要进行事务控制的bean,像fooService
3、事务控制的方法要进行回滚,要抛出异常,不能用try catch来进行处理。。像insertFoo方法
提示:如果用‘transactionManager’来定义PlatformTransactionManager bean的名字,就可以省略<tx:annotation-driven/>标签中的transaction-manager属性。如果用其他的名字,则必须在<tx:annotation-driven/>标签中定义transaction-manager属性。
在使用代理的时候,@Transactional注解应该只被应用到public方法中。如果非要注解非public方法的话,参考AspectJ。
@Transactional注解可以被应用在接口定义,接口方法,类定义和类方法上。Spring团队建议只讲@Transactional注解应用在具体的类上,而不应用在接口上。
只是应用@Transactional不会启用事务管理,正是<tx:annotation-driven/>标签开启了事务管理。
注意:在代理模式下(默认情况),只有从代理传过来的外部调用才会被拦截,“自我调用”是不会触发事务的。要实现“自我调用”也触发事务,使用AspectJ
<tx:annotation-driven/>的设置:
transaction-manager:事务管理器的名字,默认值:transactionManager
mode:模式,默认值:proxy
proxy-target-class:基于类代理还是基于接口代理,只对代理模式有效。默认false。。不设或者设为false,表示基于接口代理
order:顺序
@Transactional设置:
propagation:事务传播性设置,Propagation枚举类型。Spring支持的事务传播属性包括7种:
PROPAGATION_MANDATORY:方法必须在事务中执行,否则抛出异常。
PROPAGATION_NESTED:使方法运行在嵌套事务中,否则和PROPAGATION_REQUIRED一样。
PROPAGATION_NEVER :当前方法永远不在事务中运行,否则抛出异常。
PROPAGATION_NOT_SUPPORTED:定义为当前事务不支持的方法,在该方法执行期间正在运行的事务会被暂停
PROPAGATION_REQUIRED:当前的方法必须运行在事务中,如果没有事务就新建一个事务。新事务和方法一起开始,随着方法返回或者抛出异常时终止。
PROPAGATION_REQUIRED_NEW :当前方法必须新建一个事务,如果当前的事务正在运行则暂停。
PROPAGATION_SUPPORTS :规定当前方法支持当前事务,但是如果没有事务在运行就使用非事务方法执行。
isolation:事务隔离性级别设置,Isolation枚举类型
ISOLATION_DEFAULT :使用数据库默认的隔离级别
ISOLATION_COMMITTED:允许其他事务已经提交的更新(防止脏读取)
ISOLATION_READ_UNCOMMITTED:允许读取其他事务未提交的更新,会导致三个缺陷发生。执行速度最快
ISOLATION_REPEATABLE_READ :除非事务自身更改了数据,否则事务多次读取的数据相同(防止脏数据,多次重复读取)
ISOLATION_SERIALIZABLE:隔离级别最高,可以防止三个缺陷,但是速度最慢,影响性能。
readOnly:读写性事务,只读性事务,布尔型
对数据库的操作中,查询是使用最频繁的操作,每次执行查询时都要从数据库中重新读取数据,有时多次读取的数据都是相同的,这样的数据操作不仅浪费了系统资源,还影响了系统速度。对访问量大的程序来说,节省这部分资源可以大大提 升系统速度。
将事务声明为只读的,那么数据库可以根据事务的特性优化事务的读取操作
timeout:超时时间,单位秒
事务可能因为某种原因很长时间没有反应,这期间可能锁定了数据库表,影响性能。设置超时时间,如果超过该时间,事务自动回滚。
rollbackFor:一组异常类的实例,遇到时必须进行回滚
rollbackForClassname:一组异常类的名字,遇到时必须进行回滚
noRollbackFor:一组异常类的实例,遇到时必须不回滚
noRollbackForClassname:一组异常类的名字,遇到时必须不回滚