前言
事务确保应用程序数据的完整性和一致性
1、 事务四大特性
特性 | 说明 |
原子性(Atomicity) | 一个事务是一个不可分割的工作单位,事务中包括的动作要么都做要么都不做。 |
一致性(Consistency) | 事务必须保证数据库从一个一致性状态变到另一个一致性状态,一致性和原子性是密切相关的。 |
隔离性(Isolation) | 一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相打扰。 |
持久性(Durability) | 持久性也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就是永久性的,后面的其它操作和故障都不应该对其有任何影响。 |
2、事务管理方式
事务管理方式 | 说明 |
编程式事务管理 | 编程式事务管理是通过编写代码实现的事务管理。这种方式能够在代码中精确地定义事务的边界,我们可以根据需求规定事务从哪里开始,到哪里结束。 |
声明式事务管理 | Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。 |
3、事务管理级别
3.1、脏读
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
3.2、不可重复读
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
与此同时,
事务B把张三的工资改为8000,并提交了事务。
随后,
在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
3.3、幻读
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
此时,
事务B插入一条工资也为5000的记录。
这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
方法 | 说明 |
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 允许读取尚未提交的更改,可能导致脏读、幻读和不可重复读 |
ISOLATION_READ_COMMITTED | Oracle 默认级别,允许读取已提交的并发事务,防止脏读,可能出现幻读和不可重复读 |
ISOLATION_REPEATABLE_READ | MySQL默认级别,多次读取相同字段的结果是一致的,防止脏读和不可重复读,可能出现幻读 |
ISOLATION_SERIALIZABLE | 完全服从 ACID 的隔离级别,防止脏读、不可重复读和幻读 |
3.4、事务传播行为
事务传播行为(propagation behavior)指的是,当一个事务方法被另一个事务方法调用时,这个事务方法应该如何运行。例如,事务方法 A 在调用事务方法 B 时,B 方法是继续在调用者 A 方法的事务中运行呢,还是为自己开启一个新事务运行,这就是由事务方法 B 的事务传播行为决定的。
名称 | 说明 |
PROPAGATION_MANDATORY | 支持当前事务,如果不存在当前事务,则引发异常。 |
PROPAGATION_NESTED | 如果当前事务存在,则在嵌套事务中执行。 |
PROPAGATION_NEVER | 不支持当前事务,如果当前事务存在,则引发异常。 |
PROPAGATION_NOT_SUPPORTED | 不支持当前事务,始终以非事务方式执行。 |
PROPAGATION_REQUIRED | 默认传播行为,如果存在当前事务,则当前方法就在当前事务中运行,如果不存在,则创建一个新的事务,并在这个新建的事务中运行。 |
PROPAGATION_REQUIRES_NEW | 创建新事务,如果已经存在事务则暂停当前事务。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果不存在事务,则以非事务方式执行。 |
4、基于xml事务管理
4.1、增加tx命名空间
<?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.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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.xsd ">
4.2、配置事务管理
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
4.3、配置事务通知
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="10"/> </tx:attributes> </tx:advice>
<tx:method> 元素包含多个属性参数,可以为某个或某些指定的方法(name 属性定义的方法)定义事务属性,如下表所示。
事务属性 | 说明 |
propagation | 指定事务的传播行为。 |
isolation | 指定事务的隔离级别。 |
read-only | 指定是否为只读事务。 |
timeout | 表示超时时间,单位为“秒”;声明的事务在指定的超时时间后,自动回滚,避免事务长时间不提交会回滚导致的数据库资源的占用。 |
rollback-for | 指定事务对于那些类型的异常应当回滚,而不提交。 |
no-rollback-for | 指定事务对于那些异常应当继续运行,而不回滚。 |
4.4、配置切点切面
<!--配置切点切面--> <aop:config> <!--配置切点--> <aop:pointcut id="txPointCut" expression="execution (* com.hqyj.spring.service.impl.*(..))"/> <!--配置切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
5、基于注解事务管理
5.1、配置文件配置
<!--开启注解事务--> <tx:annotation-driven/> <!--开启组件扫描--> <context:component-scan base-package="com.xxxx.spring"></context:component-scan> <!--引入 jdbc.properties 中的配置--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--定义数据源 Bean--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!--数据库连接地址--> <property name="url" value="${jdbc.url}"/> <!--数据库的用户名--> <property name="username" value="${jdbc.username}"/> <!--数据库的密码--> <property name="password" value="${jdbc.password}"/> <!--数据库驱动--> <property name="driverClassName" value="${jdbc.driver}"/> </bean> <!--定义 JdbcTemplate Bean--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--将数据源的 Bean 注入到 JdbcTemplate 中--> <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"></tx:annotation-driven>
5.2、@Transactional 注解
@Transactional 注解,加在需要事务处理的方法上。它包含多个属性,其中常用属性如下表。
事务属性 | 说明 |
propagation | 指定事务的传播行为。 |
isolation | 指定事务的隔离级别。 |
read-only | 指定是否为只读事务。 |
timeout | 表示超时时间,单位为“秒”;声明的事务在指定的超时时间后,自动回滚,避免事务长时间不提交会回滚导致的数据库资源的占用。 |
rollback-for | 指定事务对于那些类型的异常应当回滚,而不提交。 |
no-rollback-for | 指定事务对于那些异常应当继续运行,而不回滚。 |