一、使用事务的目的
把多个操作(多行代码)绑在一起,要么一起执行成功,要么一起执行失败,保证数据的完整与安全(多与数据库打交道)。
二、事务的概念
1.事务的定义:事务值得是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。
2.四种事务特性(ACID):
(1)原子性 (atomicity):事务是一个不可分割的工作单位,事务中的操作要么都成功,要么都失败。
(2)一致性 (consistency):事务执行前后,数据保持一致,保证数据的完整性。
(3)隔离性 (isolation):多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务干扰。多个并发事务之间,数据要相互隔离。
(4)持久性(durability) :一个事务一旦执行完毕,它对数据库中数据的改变是永久性的,即使数据库发生故障也不应该对其有任何影响。
3.Spring事务管理高层抽象主要包括三个接口:
(1)PlatformTransactionManager:事务管理器
Spring为不同的持久化框架提供了不同的PlatformTransactionManager,如下
(2)TransactionDefinition:事务定义信息(隔离、传播、超时、只读)
(3)TransactionStatus:事务具体运行状态
4.五种隔离级别
(1)DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。(Mysql 默认repeatable_read, Oracle 默认read_commited)
(2)未提交读(read_uncommited)
(3)已提交读 (read_commited)
(4)可重复读 (repeatable_read)
(5)串行化的 (serializable)
如果不考虑隔离性引发安全性问题:
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
5.七种事务传播行为
//保证在同一个事务中
(1)PROPAGATION_REQUIRED:支持当前事务,如果不存在 就新建一个(默认)
(2)PROPAGATION_SUPPORTS: 支持当前事务,如果不存在,就不使用事务
(3)PROPAGATION_MANDATORY :支持当前事务,如果不存在,抛出异常
//保证不在同一个事务中
(4)PROPAGATION_REQUIRES_NEW: 如果有事务存在,挂起当前事务,创建一个新的事务
(5)PROPAGATION_NOT_SUPPORTED :以非事务方式运行,如果有事务存在,挂起当前事务
(6)PROPAGATION_NEVER: 以非事务方式运行,如果有事务存在,抛出异常
//嵌套事务执行
(7)PROPAGATION_NESTED:如果当前事务存在,则嵌套事务执行
三、事务的使用方法
1.编程式事务管理:通过TransactionTemplate手动管理事务,在实际应用中很少使用,具体使用方法,略。
2.声明式事务管理(需要使用xml配置):通过AOP实现事务管理,代码侵入性小,推荐使用。
方法一:基于TransactionProxyFactoryBean,为每个事务管理的类配置一个TransactionProxyFactoryBean,进行增强。(很少使用)
方法二:基于AspectJ,在xml里配置,不需要在类里修改代码。(经常使用)
- 相关xml文件: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:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.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>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.userName}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置业务层类 -->
<bean id="accountService" class="cn.muke.spring.demo3.AccountServiceImpl">
<property name="accountDAO" ref="accountDAO"></property>
</bean>
<!-- 配置DAO层类 -->
<bean id="accountDAO" class="cn.muke.spring.demo3.AccountDAOImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="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 :事务的隔离级别
* readOnly :只读
* rollback-for :发生哪些异常回滚
* no-rollback-for:发生哪些异常不回滚
* timeout :过期信息
-->
<tx:method name="transfer" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:pointcut
expression="execution(* cn.muke.spring.demo3.AccountService+.*(..))"
id="pointcut1" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1" />
</aop:config>
</beans>
方法三:基于注解,配置简单,需要在事务管理的类上添加@Transactional注解。(经常使用)
- 相关xml文件: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:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.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>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.userName}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置业务层类 -->
<bean id="accountService" class="cn.muke.spring.demo4.AccountServiceImpl">
<property name="accountDAO" ref="accountDAO"></property>
</bean>
<!-- 配置DAO层类 -->
<bean id="accountDAO" class="cn.muke.spring.demo4.AccountDAOImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
- 相关Java文件:AccountServiceImpl.java
package cn.muke.spring.demo4;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @author Administrator
* 转账案例的业务层实现类
* @Transactional(**)注解中的属性:
* propagation :事务的传播行为
* isolation :事务的隔离级别
* readOnly :只读
* rollbackFor :发生哪些异常回滚
* noRollbackFor:发生哪些异常不回滚
*/
@Transactional //要在哪个地方使用事务管理,就在哪个类上添加注解
public class AccountServiceImpl implements AccountService {
//注入DAO层类
private AccountDAO accountDAO;
public void setAccountDAO(AccountDAO accountDAO) {
this.accountDAO = accountDAO;
}
//注入事务管理模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
//out:转出账号,in:转入金额,money:转账金额
public void transfer(String out, String in, Double money) {
accountDAO.outMoney(out, money);
int i=1/0;
accountDAO.inMoney(in, money);
}
}