事务的出现是为了保证数据的完整性和一致性,为了防止意外的中断致使数据出现错误.spring
在Spring中事务的主要使用方式有两种,一种是编程式事务管理另外一种是声明式事务管理.编程式事务使用的是JDBC的原生API须要编写大量代码太过麻烦。所以如今Spring主要使用的是声明式事务编程,Spring中的声明式事务编程是基于AOP模式的,也就是在@before以前建立一个事物,@AfterRetuning以前确认一下事务是否须要回滚.声明式事务的最大优势就是不用写一堆代码而能够直接经过注解(基于@Transaction注解)和配置文件(基于tx和aop命名空间)完成事务管理.数据库
XML文件express
<!--引入事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="pooledDataSource"></property> </bean> <!--依赖tx名称空间,开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
@Transaction注解主要是添加在Service组件的方法下编程
@Transactional(propagation=Propagation.REQUIRES,isolation=READ_COMMITTED) public void updateBook(String name,int price){ libaryDao.updateBook(name, price); }
<!--引入事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="pooledDataSource"></property> </bean> <aop:config> <!-- 配置事务切入点,哪些类哪些方法须要切入事务--> <aop:pointcut expression="execution(* com.libary.service*.*.*(..))" id="Point"/> <aop:advisor advice-ref="MyTx" pointcut-ref="Point"/> </aop:config> <!-- 配置事务管理器 --> transaction-manager="transactionManager": <tx:advice id="MyTx" transaction-manager="transactionManager"> <!--事务的属性 --> <tx:attributes> <!--tx:method 指定了哪些方法须要加事务 --> <tx:method name="*"/> <tx:method name="update" propagation="REQUIRED" timeout="-1"/> <tx:method name="query*" read-only="true"/> </tx:attributes> </tx:advice>
与Aop的使用相同,事务使用的思想应该是,重要的事务使用xml配置,不重要的事务使用@Transaction.并发
noRollbackFor:指定异常事务不回滚.
rollbackFor:指定异常事务回滚(编译时错误原本不回滚使其回滚,编译时错误默认是不回滚的除非使用try catch捕捉错误,可是运行错误是必定进行回滚)
timeout:事务超出指定时间即回滚,防止事务占用资源.
readOnly:只能够添加在查询事务上,能够优化事务的查询速度.
isolation:隔离级别下面重点提到.
propagation:传播行为下面重点提到.
多种事务嵌套运行时,下面的事务服从顶层事务的属性.框架
事物的传播行为主要是为了处理当有多个事务嵌套执行时,其中某个事务出现了错误,有哪些事务须要进行回滚.
如如下状况优化
TestTx() { A事务(REQUIRED) { B事务(REQUIRED_NEW) { C事务(REQUIRED) { } } D事务(REQUIRED) { E事务(REQUIRED) { } } F事务(REQUIRED_NEW) } }
平常事务管理中主要特别注意的事务是REQUIRED和REQUIRED_NEW
REQUIRED。
REQUIRED:REQUIRED的意思是与他的上层事务同生共死,你们共用一个事物。即如上代码,若是D出现错误了A也出现错误,你们一块儿进行rollback。
REQUIRED_NEW:REQUIRED_NEW的意思是我本身玩我本身的,我本身有一个事物,例如F出现错误了,与A事务有太多关系。F进行rollback,A不rollback。
特殊状况:如上代码,若是D出现错误了,那么即使F是REQUIRED_NEW也不会执行,由于到D已经就直接抛出错误了。
重要的一点:
1.无论哪里出错,已经执行完的REQUIRED_NEW都不会出错。
2.嵌套事务中由最顶层事务来决定Timeout等属性。spa
例:x=10; A事务修改x=5但还未commit; B读出x=5; A进行rollback,x=10; B读出的x=5是假数据
例:x=10; B事务读取x=10; A事务修改x=5并commit; B再次读取x=5,两次读取x不一样;
例:x=10; B事务读取x=10; A事务添加y=20,i=30; B再次读取读出x=10,,y=20,i=30.多出大量数据。
使用@Transaction的isolation=Propagation.?属性设置隔离级别.代理
例:@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=READ_COMMITTED)
READ_UNCOMMITTED(读未提交):容许脏读、不可重读读、幻读.
READ_COMMITTED(读已提交):容许不可重读和幻读,不容许脏读.
REPEATABLE READ(可重复读):容许幻读,不容许脏读和不可重复读.
SERIALIZABLE(串行化):不容许脏读、不可重复读、幻读.code
最后特别要注意的是千万不要在某个Service组件中调用Service的事务方法(即不要调用本类方法),要记住Spring中的事物使用是基于AOP的,因此事务须要用代理对象,而直接在本类中调用的方法是没法进行事务的。本类方法的嵌套无论调用多少个都是单个事务.
例: @Service public class LibaryService{ @Autowired LibaryDao libaryDao; @Transaction(propagation=Propagation.REQUIRES_NEW) public int updateBook(String name,int price) { libaryDao.update(name,price); } @Transaction(propagation=Propagation.REQUIRES_NEW) public Book QueryBook(int Id) { libaryDao.QueryBook(Id); } //如下代码只有errorway()会被当成一个事物。而下方的updateBook()和QueryBook()由于是调用了本类方法,没有使用代理对象,因此不会通过事务处理。 @Transaction public void errorway() { updateBook("三毛流浪记",56); QueryBook("射雕英雄传"); }