前言:
在之前的博客中已经说过了数据库的事务, 不过那里面更多的是说明事务的一些锁机制, 今天来说一下Spring管理事务的一些基础知识.
之前的文章: [数据库事务与锁]详解一: 彻底理解数据库事务一, 什么是事务
事务是逻辑上一组操作,这组操作要么全都成功,要么全都失败.
事务的属性: ACID
原子性(Atomicity): 事务作为一个整体被执行,包含在其中的对数据的操作要么全部被执行,要么都不执行.
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态. 一致状态的含义是数据库中的数据应满足为完整性约束.
隔离性(Isolation):多个事务并发执行时, 一个事务的执行不应该影响其他事务的执行.
持久性(Durability):一个事务一旦提交, 他对数据库的修改应该永久保存在数据库中.
二, Spring的事务管理
一类:编程式事务管理.手动编写代码管理事务.
二类:声明式事务管理.通过配置完成事务管理.(AOP) : 这里只说声明式的事务管理.
事务管理的API:
PlatformTransactionManager :平台事务管理器
* 是真正管理事务的对象.
TransactionDefinition :事务定义信息.
* 定义事务的(隔离级别,传播行为,超时信息,只读)
TransactionStatus :事务状态.
* 管理事务的过程中,事务有一些状态的改变.状态信息被记录在该对象中.
Spring根据TransactionDefinition中定义的信息使用PlatformTransactionManager管理事务,管理事务过程中产生状态,将状态记录到TransactionStatus中.
三, Spring相关API详解
1,PlatformTransactionManager
2,TransactionDefinition
常量:
* ISOLATION_*:定义事务的隔离级别.
* PROPAGATION_*:定义事务的传播行为.
* 超时信息:
方法:
Transaction事务状态:
|
Spring的事务传播行为:
PROPAGATION_REQUIRED :如果A,B操作,如果A有事务使用A的事务将B包含进来.如果A没有事务创建一个新事务将A,B包进来. PROPAGATION_SUPPORTS :如果A,B操作,如果A有事务,使用A的事务将B包含进来.如果A没有事务,不使用事务. PROPAGATION_MANDATORY :如果A,B操作,如果A有事务,使用A的事务将B包含进来.如果A没有事务,就会抛出异常. PROPAGATION_REQUIRES_NEW :如果A,B操作,如果A有事务,将A的事务挂起.创建一个新事务执行B操作. PROPAGATION_NOT_SUPPORTED :如果A,B操作,总是以非事务方式运行,如果A有,将A挂起. PROPAGATION_NEVER :如果A,B操作,总是以非事务方式运行,如果A有事务抛出异常. PROPAGATION_NESTED :嵌套事务.如果A,B操作,A有事务,在A执行完之后设置一个保存点.如果B执行没有问题,一起提交.如果B出现问题.允许用户自己控制回滚到最初还是回滚到保存点.
四, Spring事务管理实例(声明式事务管理)
Spring声明式事务管理又可分为三种:
1,基于TransactionProxyFactoryBean
2, 基于AspectJ的XML方式的事务管理
3, 基于AspectJ的注解方式事务管理
基于AspectJ的XML方式的事务管理:
1,引入开发包:
2,Service层代码:
AccountService.java
1 public interface AccountService { 2 3 /** 4 * 转账的方法 5 */ 6 public void transfer(String from,String to,Double money); 7 }
AccountServiceImpl.java:
1 private AccountDao accountDao; 2 3 public void setAccountDao(AccountDao accountDao) { 4 this.accountDao = accountDao; 5 } 6 7 @Override 8 /** 9 * 业务层转账的方法: 10 * from:转出账号 11 * to:转入账号 12 * money:转账金额 13 */ 14 public void transfer(final String from, final String to, final Double money) { 15 accountDao.outMoney(from, money); 16 int d = 1 / 0; 17 accountDao.inMoney(to, money); 18 } 19 20 }
3,DAO层代码
AccountDAO.java:
1 public interface AccountDao { 2 public void outMoney(String from, Double money); 3 4 public void inMoney(String to, Double money); 5 }
AccountDAOImpl.java:
1 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { 2 3 @Override 4 public void outMoney(String from, Double money) { 5 this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money,from); 6 } 7 8 @Override 9 public void inMoney(String to, Double money) { 10 this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,to); 11 } 12 13 }
4,配置文件
jdbc.properties:
jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring_transaction jdbc.user=root jdbc.password=123
applicationcontext.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xmlns:tx="http://www.springframework.org/schema/tx" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context.xsd 11 http://www.springframework.org/schema/aop 12 http://www.springframework.org/schema/aop/spring-aop.xsd 13 http://www.springframework.org/schema/tx 14 http://www.springframework.org/schema/tx/spring-tx.xsd"> 15 16 <context:property-placeholder location="classpath:jdbc.properties"/> 17 18 <!-- 配置C3P0连接池 --> 19 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 20 <property name="driverClass" value="${jdbc.driverClass}"/> 21 <property name="jdbcUrl" value="${jdbc.url}"/> 22 <property name="user" value="${jdbc.user}"/> 23 <property name="password" value="${jdbc.password}"/> 24 </bean> 25 <!-- 配置Service --> 26 <bean id="accountService" class="cn.augmentum.transaction.demo3.service.AccountServiceImpl"> 27 <property name="accountDao" ref="accountDao"/> 28 </bean> 29 30 <!-- 配置DAO --> 31 <bean id="accountDao" class="cn.augmentum.transaction.demo3.dao.AccountDaoImpl"> 32 <property name="dataSource" ref="dataSource"/> 33 </bean> 34 35 <!-- 配置事务管理器 --> 36 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 37 <property name="dataSource" ref="dataSource"/> 38 </bean> 39 40 <!-- 配置事务增强 --> 41 <tx:advice id="txAdvice" transaction-manager="transactionManager"> 42 <tx:attributes> 43 <!-- 44 propagation:事务传播行为: 45 isolation:隔离级别 46 read-only:是否为只读事务. 47 timeout :是否超时. 48 rollback-for:类似-Exception.发生哪些异常回滚事务. 49 no-rollback-for:类似+Exception.发生哪些异常不回滚. 50 --> 51 <tx:method name="transfer" propagation="REQUIRED"/> 52 </tx:attributes> 53 </tx:advice> 54 55 56 <!-- AOP的配置 --> 57 <aop:config> 58 <aop:pointcut expression="execution(* cn.augmentum.transaction.demo3.service.AccountServiceImpl.*(..))" id="pointcut1"/> 59 <aop:advisor advice-ref="txAdvice" pointcut-ref=""/> 60 </aop:config> 61 </beans>
5, 测试方法
SpringDemo.java:
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration("classpath:applicationContext.xml") 3 public class SpringDemo3 { 4 5 @Resource(name="accountService") 6 private AccountService accountService; 7 8 @Test 9 public void demo1(){ 10 accountService.transfer("老马", "凤姐", 1000d); 11 } 12 }
关于XML的声明式事务管理就这些了, 那么下面来看下更简单的关于注解的声明式事务管理的做法.;
这里只需要看Service层是如何加注解以及applicationcontext中是怎样配置的就行了.
AccountServiceImpl.java:
1 /** 2 * @Transactional中属性 3 * propagation:传播行为. 4 * readOnly:是否只读 5 * timeout:超时信息 6 * isolation:隔离级别 7 */ 8 @Transactional(propagation=Propagation.REQUIRED,readOnly=false,timeout=-1,isolation=Isolation.DEFAULT) 9 public class AccountServiceImpl implements AccountService { 10 private AccountDao accountDao; 11 12 public void setAccountDao(AccountDao accountDao) { 13 this.accountDao = accountDao; 14 } 15 16 @Override 17 /** 18 * 业务层转账的方法: 19 * from:转出账号 20 * to:转入账号 21 * money:转账金额 22 */ 23 public void transfer(final String from, final String to, final Double money) { 24 accountDao.outMoney(from, money); 25 int d = 1 / 0; 26 accountDao.inMoney(to, money); 27 } 28 }
applicationcontext.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xmlns:tx="http://www.springframework.org/schema/tx" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context.xsd 11 http://www.springframework.org/schema/aop 12 http://www.springframework.org/schema/aop/spring-aop.xsd 13 http://www.springframework.org/schema/tx 14 http://www.springframework.org/schema/tx/spring-tx.xsd"> 15 16 <context:property-placeholder location="classpath:jdbc.properties"/> 17 18 <!-- 配置C3P0连接池 --> 19 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 20 <property name="driverClass" value="${jdbc.driverClass}"/> 21 <property name="jdbcUrl" value="${jdbc.url}"/> 22 <property name="user" value="${jdbc.user}"/> 23 <property name="password" value="${jdbc.password}"/> 24 </bean> 25 <!-- 配置Service --> 26 <bean id="accountService" class="cn.augmentum.transaction.demo4.service.AccountServiceImpl"> 27 <property name="accountDao" ref="accountDao"/> 28 </bean> 29 30 <!-- 配置DAO --> 31 <bean id="accountDao" class="cn.augmentum.transaction.demo4.dao.AccountDaoImpl"> 32 <property name="dataSource" ref="dataSource"/> 33 </bean> 34 35 <!-- 配置事务管理器 --> 36 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 37 <property name="dataSource" ref="dataSource"/> 38 </bean> 39 40 <!-- 开启注解事务 --> 41 <tx:annotation-driven transaction-manager="transactionManager"/> 42 </beans>
注解方式的声明式事务管理也就是这么多, 看起来确实简单了很多.