1.什么是事务?
事务是逻辑上的一组操作,这组操作要么全部成功,要么全部失败
2.事物具有四大特性ACID
说到事务,就不得不说其4大特性,主要如下
原子性:(atomicity)
原子性指的是事务是一个不可分割的工作单位,事务中的操作要么全部发生,要么都不发生
(就像物理中,原子是最小不可分割的单位)
一致性:(consistency)
一致性指的是事务前后数据的完整性必须保持一致(比如说,转账:张三账户有2000元,李四账户有2000元,一共4000元
张三项李四转账2000元后,一共还是4000元)
事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的
隔离性:(isolation)
隔离性指的是多个用户并发访问数据库是,一个用户的事务不能被其他用户的事务
干扰,多个并发事务之间相互隔离
持久性:(durability)。
持久性指的是一个事务一旦被提交,他对数据库中的数据的改变是永久的,即使数据库故障
也不应该对其有任何影响
3.Spring中事务的管理
Spring中主要提供了以下3个接口来对事务进行管理
PlatformTransactionManager 平台事务管理器
主要用于事务的提交,回滚等说明
TransactionDefintion 事务定义信息(隔离,传播,超时,只读)
主要用于事务的隔离,传播,只读等说明
TransactionStatus 事务具体运行状态
是否是一个新的事务,是否有保存点,事务是否完成等说明
主要用于事务的提交,回滚等说明
TransactionDefintion 事务定义信息(隔离,传播,超时,只读)
主要用于事务的隔离,传播,只读等说明
TransactionStatus 事务具体运行状态
是否是一个新的事务,是否有保存点,事务是否完成等说明
大致的运行过程:
首先通过TransactionDefinition定义了事务(隔离,传播,超时,只读)等信息后,再交给PlatformTransactionManager平台事务管理器进行真正的事务管理,之后事务会产生一些相应的状态,之后就会保存到TransactionStatus中。
首先通过TransactionDefinition定义了事务(隔离,传播,超时,只读)等信息后,再交给PlatformTransactionManager平台事务管理器进行真正的事务管理,之后事务会产生一些相应的状态,之后就会保存到TransactionStatus中。
3.1平台事务管理器PlatformTransactionManager
主要定义了各个不同的数据库平台的一些接口,针对不同的数据库平台进行事务管理
org.springframework.jdbc.datasource.DataSourceTransactionManager
使用jdbc或Mybatis进行持久化时使用
org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate3.0版本进行持久化数据时使用
org.springframework.orm.jdo.JdoTransactionManager 持久化机制为jdao
org.springframework.orm.jpa.JpaTransactionManager 使用jpa进行持久化
org.springframework.transaction.jta.JtaTransactionManager 使用JTA来实现事务管理,在一个事务跨越多个资源时必须使用
org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate3.0版本进行持久化数据时使用
org.springframework.orm.jdo.JdoTransactionManager 持久化机制为jdao
org.springframework.orm.jpa.JpaTransactionManager 使用jpa进行持久化
org.springframework.transaction.jta.JtaTransactionManager 使用JTA来实现事务管理,在一个事务跨越多个资源时必须使用
我们再使用不同的数据库时候,可以选择不同事务管理器,还有这里列举了一些常用的,还有其他的可以参见SpringApi说明,也可以查看在线api: http://tool.oschina.net/apidocs/#S
3.2事务定义信息接口 TransactionDefintion
主要用于声明事务的传播行为,和隔离级别等信息
假如一个事务不去考虑其隔离性,可能会引发如下问题(脏读,不可重复读,幻读)
3.2.1事务的脏读,不可重复读,幻读
脏读:一个事务读取到了一个事务 改写但是未提交的数据,如果这些数据回滚,则读取到的数据是无效的
不可重复读:在同一个事物中,多次读取同一数据,由于另外一个事务对该数据 修改提交,造成返回的结果不同。
幻读(虚读):一个事务读取几行记录后,另一个事务 插入或删除 了一些记录,导致再次读取的返回结果不同。
不可重复读:在同一个事物中,多次读取同一数据,由于另外一个事务对该数据 修改提交,造成返回的结果不同。
幻读(虚读):一个事务读取几行记录后,另一个事务 插入或删除 了一些记录,导致再次读取的返回结果不同。
不可重复读和幻读,很相似,只是侧重点不同:
相同点都是一个事务读取了另一个提交了的数据
不同点在于,不可重复读侧重点在于修改并提提交,幻读(虚度)在于删除或添加
不同点在于,不可重复读侧重点在于修改并提提交,幻读(虚度)在于删除或添加
可以参见博文:http://blog.csdn.net/v123411739/article/details/39298127
3.2.2 事务的隔离级别
为了解决上诉问题,Spring在接口TransactionDefintion中定义了4中隔离级别,如下:
DEFAULT 使用数据默认的隔离级别(由spring根据使用的数据决定)
READ_UNCOMMITED允许你读取还未提交的改变了的数据(可导致脏读,幻读,不可重复读)
READ_COMMINTED允许你读取事务已经提交后的数据(可防止脏读,但是幻读和不可重复读是有可能发生的)
REPEATABLE_READ对相同字段的多次读取是一致的,除非数据被事务本身改变(可防止脏读,不可重复读,当幻读任然可能发生)
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读,幻读,不可重复读。这在所有的隔离级别中是最慢的,他是典型的
通过完全锁定在事务中设计的数据表来完成的
READ_UNCOMMITED允许你读取还未提交的改变了的数据(可导致脏读,幻读,不可重复读)
READ_COMMINTED允许你读取事务已经提交后的数据(可防止脏读,但是幻读和不可重复读是有可能发生的)
REPEATABLE_READ对相同字段的多次读取是一致的,除非数据被事务本身改变(可防止脏读,不可重复读,当幻读任然可能发生)
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读,幻读,不可重复读。这在所有的隔离级别中是最慢的,他是典型的
通过完全锁定在事务中设计的数据表来完成的
提示:oracle默认的是:READ_COMMINTED
mysql默认是:REPEATABLE_READ,前边的3个是我们经常需要使用的
3.2.3事务的传播行为
一般我们的事务是在业务层中(Service)中使用的,假如遇到比较复杂的业务,需要在一个业务中调用另一个业务的方法:
如下:
业务逻辑ServiceA中的方法methoda()中的需要与业务逻辑ServiceB中的方法methodb()方法共同完成某个复杂的逻辑
假如都有事务,到底是使用谁的事务。
事务的传播行为,正是为了解决业务层中的方法相互调用的问题 的。
<span style="white-space:pre"> </span>ServiceA{
methoda(){//需要调用serviceB中的业务方法methodb()共同完成
dao1.xxmethod();
serviceB.methodb();
}
}
ServiceB{
methodb(){
dao2.yymethod();
}
}
DAO1{
xxmethod(){
}
}
DAO2{
yymethod(){
}
}
Spring的事务定义信息接口TransactionDefintion还定义了如下7中事务传播行为常量,我们可以分为3类,(同一事物中,不同事务中,嵌套事务中)
类一,两种在同一事物中
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则新建一个事务)
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则不使用事务)
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则抛出异常)
类二,两者不再同一个事物中
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。(就比如上边的场景,methoda假如有事务挂起该事物
不使用,而methodb新建一个事务)
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(就比如上边的场景,methoda假如有事务挂起该事物
不使用,而methodb不使用事务)
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。(就比如上边的场景,methoda假如有事务则抛出异常)
类三嵌套事务中
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行(如果在执行methoda完成的时候,就会使用事务设置一个保存点,再执行methodb,假如methodb没有异常,他们就一起提交了,如果
发生了异常,你可根据自己的设定你可选择回滚到保存点位置,也可以回滚到最初的状态)
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则新建一个事务)
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则不使用事务)
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。(就比如上边的场景,methoda假如有事务
则使用methoda的使用,假如methoda没有则抛出异常)
类二,两者不再同一个事物中
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。(就比如上边的场景,methoda假如有事务挂起该事物
不使用,而methodb新建一个事务)
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(就比如上边的场景,methoda假如有事务挂起该事物
不使用,而methodb不使用事务)
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。(就比如上边的场景,methoda假如有事务则抛出异常)
类三嵌套事务中
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行(如果在执行methoda完成的时候,就会使用事务设置一个保存点,再执行methodb,假如methodb没有异常,他们就一起提交了,如果
发生了异常,你可根据自己的设定你可选择回滚到保存点位置,也可以回滚到最初的状态)
3.3 事务具体运行状态接口 TransactionStatus
里边主要定义了事务运行过程的一些具体状态(如是否是新的事务,是否只读,是否设置保存点)等等,这些都是可以获得的
4.Spring中的事务实现方式
Spring主要通过如下两种方式进行事务管理
-编程式事务管理
主要通过TransactionTemplate手动管理事务,在实际开发中很少使用
-使用XML配置声明
主要通过Spring的AOP实现的,在开发中推荐使用(代码入侵性小)
主要通过TransactionTemplate手动管理事务,在实际开发中很少使用
-使用XML配置声明
主要通过Spring的AOP实现的,在开发中推荐使用(代码入侵性小)
4.1Spring的编程式事务管理
所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。
管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。
对于编程式事务管理,spring推荐使用TransactionTemplate。
管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。
对于编程式事务管理,spring推荐使用TransactionTemplate。
这里我们通过转账的小案例来实现:
account账户表:
create table account(
id number(20) primary key,
name varchar2(20),
money number
);
insert into account values(1,'张三',1000);
insert into account values(2,'李四',1000);
insert into account values(3,'王五',1000);
外部文件db.properties
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:XE
jdbc.username=xxx
jdbc.password=xxx
配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入外部文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置c3p0的连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!-- 配置业务层的类 -->
<bean id="accountService" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<!-- 注入事务管理模板 -->
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
<!-- 配置dao,Dao继承了JdbcDaoSupport后,只要注入了连接池就会有模板,就可以通过模板对数据库进行相应的操作,可以参见源码-->
<bean id="accountDao" class="com.xx.spring.chap5.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理模板,Spring为了简化事务管理的代码,提供了事务管理模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
</beans>
Service:业务逻辑接口
/**
* 转账的业务接口
* */
public interface AccountService {
/**
* @param out 转出的账户
* @param in 转入的账户
* @param money 转账金额
* */
public void transfer(String out,String in,Double money);
}
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.xxx.spring.chap5.dao.AccountDao;
import com.xxx.spring.chap5.service.AccountService;
/**
* 转账业务接口的具体实现
* */
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
private TransactionTemplate transactionTemplate; //事务管理模板
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(final String out, final String in, final Double money) {
//使用事务模板execute中需要传入TransactionCallback的实现类对象
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
});
}
}
持久层Dao层接口
/**
* 转账的dao层接口
* */
public interface AccountDao {
/**
* @param out 转出账户
* @param money 转账金额
* */
public void outMoney(String out,Double money);
/**
* @param in 转入账户
* @param money 转账金额
* */
public void inMoney(String in,Double money);
}
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.briup.spring.chap5.dao.AccountDao;
/**
* 转账的dao层接口实现
* Dao继承了JdbcDaoSupport后,只要注入了连接池就会有模板,就可以通过模板对数据库进行相应的操作,
* */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
@Override
public void outMoney(String out, Double money) {
String sql = "update account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql, money,out);
}
@Override
public void inMoney(String in, Double money) {
String sql = "update account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql, money,in);
}
}
测试:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xxx.spring.chap5.service.AccountService;
/**
* 转账测试类
* */
public class SpringTransactionTest {
@Test
public void test1() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext.xml");
AccountService accountService = ac.getBean("accountService",AccountService.class);
accountService.transfer("张三", "李四", 200.0);
}
}
数据库查询结果
1 张三 800
2 李四 1200
3 王五 1000
假如Service层转账接口出现异常
@Override
public void transfer(final String out, final String in, final Double money) {
//使用事务模板TransactionCallback
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.outMoney(out, money);
int i = 1/0;
accountDao.inMoney(in, money);
}
});
}
会发生异常java.lang.ArithmeticException: / by zero...
钱也不会转过去
4.2Spring中声明式事务管理
管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,
在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,
这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明
(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,
这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明
(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
这里主要说了解3中实现(基于代理实现,基于AspectJ实现,基于注解实现)
4.2.1声明式事务管理-基于代理实现
这种方式,主要是使用TransactionProxyFactoryBean代理拦截器实现,通过配置事务代理器从而实现事务管理
配置文件:applicationContext2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
<span style="white-space:pre"> </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明式事务管理-代理实现 -->
<!-- 引入外部文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置c3p0的连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!-- 配置业务层的类 -->
<bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">
<property name="accountDao" ref="accountDao2"></property>
</bean>
<!-- 配置dao,Dao继承了JdbcDaoSupport后,只要注入了连接池就会有模板,就可以通过模板对数据库进行相应的操作,可以参见源码-->
<bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置业务层的代理 -->
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置目标类 -->
<property name="target" ref="accountService2"></property>
<!-- 注入事物管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事物的相关属性,事物的隔离级别,传播行为等
key值为方法名可以使用通配符*
value值为
-->
<property name="transactionAttributes">
<props>
<!-- prop的格式
key为方法名,可以使用*通配符号
value值的格式:
1. PROPAGATION :事务的传播行为
2. ISOLATION :事务隔离级别
3. readOnly :只读
4. -Exception :发生那些异常回滚
5. +Exception :发生那些事务不回滚
之间使用,号隔开
-->
<prop key="trans*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
Service实现改为如下:
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.xxx.spring.chap5.dao.AccountDao;
import com.xxx.spring.chap5.service.AccountService;
/**
* 转账业务接口的具体实现
* */
public class AccountServiceImpl2 implements AccountService {
private AccountDao accountDao;
private TransactionTemplate transactionTemplate; //事务管理模板
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(final String out, final String in, final Double money) {
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
}
Dao层不变
测试类为:
/**
* 声明式事务管理--代理实现
* */
@Test
public void test2() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext2.xml");
AccountService accountService = ac.getBean("accountServiceProxy",AccountService.class);//代理对象
accountService.transfer("张三", "李四", 200.0);
}
查询结果:
<span style="white-space:pre"> </span>1 张三 800
2 李四 1200
3 王五 1000
假如Service中出现异常:
@Override
public void transfer(final String out, final String in, final Double money) {
accountDao.outMoney(out, money);
int i = 1/0;
accountDao.inMoney(in, money);
}
会抛出异常
java.lang.ArithmeticException: / by zero
但是钱没有多,也没有少,意思是本次操作失败会,保证账户的安全
4.2.2声明式事务管理-基于AspectJ实现
SpringAOP中可以通过在xml文件中配置事务通知来对事务进行管理,这是一种更常用的方式
配置文件:applicationContext3.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 基于AspectJ的声明式事务管理 -->
<!-- 引入外部文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置c3p0的连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!-- 配置业务层的类 -->
<bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">
<property name="accountDao" ref="accountDao2"></property>
</bean>
<!-- 配置dao,Dao继承了JdbcDaoSupport后,只要注入了连接池就会有模板,就可以通过模板对数据库进行相应的操作,可以参见源码 -->
<bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 设置事物属性 -->
<tx:attributes>
<!-- 设置各种方法的
propagation 为传播行为
isolation 事务的隔离级别
read-only 设置之都属性
rollback-for 发生生么异常回滚
no-rollback-for 发生那些异常不回滚
-->
<tx:method name="tran*" propagation="REQUIRED" read-only="true" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="save*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切入点,表示切入点为类AccountServiceImpl2下的所有方法 -->
<aop:pointcut
expression="execution(* com.xxx.spring.chap5.service.impl.AccountServiceImpl2.*(..))"
id="pointcut" />
<!-- 配置切面,表示AccountServiceImpl2下的所有方法都使用txAdivice增强 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
</aop:config>
</beans>
Service实现
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import com.xxx.spring.chap5.dao.AccountDao;
import com.xxx.spring.chap5.service.AccountService;
/**
* 转账业务接口的具体实现
*
* */
public class AccountServiceImpl2 implements AccountService {
private AccountDao accountDao;
private TransactionTemplate transactionTemplate; //事务管理模板
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(final String out, final String in, final Double money) {
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
}
测试:
/**
* 声明式事务管理-基于AspectJ实现
* */
@Test
public void test3() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext3.xml");
AccountService accountService = ac.getBean("accountService2",AccountService.class);
accountService.transfer("张三", "李四", 200.0);
}
查询结果:
1 张三 800
2 李四 1200
3 王五 1000
这种也是一种比较常见的使用,主要在xml文件中开始事务注解后,在需要使用事务的业务中添加@Transactionl注解
可以参见:http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html
配置文件:applicationContext4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 基于注解式事务管理 -->
<!-- 引入外部文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置c3p0的连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<!-- 配置业务层的类 -->
<bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">
<property name="accountDao" ref="accountDao2"></property>
</bean>
<!-- 配置dao,Dao继承了JdbcDaoSupport后,只要注入了连接池就会有模板,就可以通过模板对数据库进行相应的操作,可以参见源码 -->
<bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 注解事务管理器配置 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Sservice业务层实现:
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import com.xxx.spring.chap5.dao.AccountDao;
import com.xxx.spring.chap5.service.AccountService;
/**
* 转账业务接口的具体实现
*
* @Transactional中注解的属性:
* propagation:事务的传播行为
* isolation:事务的隔离级别
* readOnly:是否只读
* rollbackFor:发生那些异常回滚
* noRollbackFor:发生那些异常不回滚,这些默认可以不写使用@Transactional就行
* */
@Transactional(propagation=Propagation.REQUIRED,readOnly=true,rollbackFor={RuntimeException.class, Exception.class})
public class AccountServiceImpl2 implements AccountService {
private AccountDao accountDao;
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(final String out, final String in, final Double money) {
accountDao.outMoney(out, money);
accountDao.inMoney(in, money);
}
}
测试:
/**
* 4声明式事务管理-基于注解的实现
* */
@Test
public void test4() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext4.xml");
AccountService accountService = ac.getBean("accountService2",AccountService.class);
accountService.transfer("张三", "李四", 200.0);
}
查询结果:
1 张三 800
2 李四 1200
3 王五 1000