目标
1、事务回顾 :基本概念
2、Spring事务管理的一组API :通过api管理spring事务
3、Spring的编程式事务管理
4、Spring的声明式事务管理
1、事务回顾:
· 什么是事务?
事务指的是逻辑上的一组操作,这组操作要么全部成功,要不全部失败
·事务的特性:
原子性:原子性是指事务是一个不可分割的工作单位,事物中的操作要么都发生,要么都不发生
一致性:一致性指事务前后数据的完整性必须保持一致
隔离性:隔离性指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要互相隔离 (可设置隔离级别)
持久性:持久性是指一个事物一旦被提交,他对数据库中数据的改变就是永久性的,即使数据库发生故障也不应该对其有任何影响
· Spring 事务管理高层抽象主要包括3个接口
· Platform TransactionManager 事务管理器
管理事务— 提交、回滚
Spring为不同的持久化框架提供了不同PlatformTransactoinManager接口实现
· TransactionDefinition 事务定义信息(隔离、传播、超时、只读)
事务定义信息—隔离级别、传播行为、是否超时、是否只读
如果不考虑隔离性,会引发安全问题如下:
脏读:
一个事务读取了领一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:
在同一事务中,多次读取同一数据返回的结果有所不同
幻读:
一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。
再后来的查询中,第一个事务就会发现有些原来没有的记录
传播行为:
· TransactionStatus 事务具体运行状态
运行状态—是不是提交、有没有保存点、是不是新事务
Spring 支持两种方法的事务管理
-编程式的事务管理
· 在实际应用中很少使用
· 通过TransactionTemplate手动管理事务
· 在AccountService中使用TransactionTemplate
· TransactionTemplate依赖DataSourceTransactionManager
· DataSourceTransactionManager依赖DataSource构造
//注入转账的Dao的类
private AccountDao accountDao;
//注入事务管理的模板
private TransactionTemplate transactionTemplate;
/***
* Java
* @param out 转出账号
* @param in 转入账号
* @param money 转出金额
*/
@Override
public void transfer(final String out, final String in, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(out, money);
//int i=1/0;
accountDao.inMoney(in, money);
}
});
}
Spring 支持两种方法的事务管理
-编程式的事务管理
· 在实际应用中很少使用
· 通过TransactionTemplate手动管理事务
· 在AccountService中使用TransactionTemplate
· TransactionTemplate依赖DataSourceTransactionManager
· DataSourceTransactionManager依赖DataSource构造
<!-- applicationContext.xml -->
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置业务层类 -->
<bean id="accountService" class="cn.muke.spring.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
<!-- 注入事务的模板 -->
<property name="transactionTemplate" ref="transactionTemplate" />
</bean>
<!-- 配置Dao层类 -->
<bean id="accountDao" class="cn.muke.spring.demo1.AccountDaoImpl">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -编程式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务管理模板:Spring为了简化事务管理的代码所提供的类 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
</bean>
-使用XML配置声明式事务
· 开发中推荐使用(代码侵入性最小)
· Spring的声明式事务是通过AOP实现
/***
* 测试
* 转账案例测试类
* @author smallearly
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 200d);
}
}
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置业务层类 -->
<bean id="accountService" class="cn.muke.spring.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
</bean>
<!-- 配置Dao层类 -->
<bean id="accountDao" class="cn.muke.spring.demo2.AccountDaoImpl">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置业务层代理 -->
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置目标对象 -->
<property name="target" ref="accountService" />
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 注入事务属性 -->
<property name="transactionAttributes">
<props>
<!-- prop的格式
* PROPAGATION :事务的传播行为
* ISOLATION :事务的隔离级别
* readOnly :只读(不能 修改、插入、删除)
* -Exception :发生什么异常回滚事务
* +Exception :发生什么异常不回滚事务
-->
<prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
</props>
</property>
</bean>
</beans>