1.什么是事务
是并发控制的单元,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务, sql 能将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性。事务通常是以 begin transaction 开始,以 commit 或 rollback 结束。Commint 表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据 的更新写回到磁盘上的物理数据库中去,事务正常结束。Rollback 表示回滚,即在事务运行的过程中发生了某种故 障,事务不能继续进行,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态。设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:1 、更新客户所购商品的库存信息2 、保存客户付款信息 -- 可能包括与银行系统的交互3 、生成订单并且保存到数据库中4 、更新用户相关信息,例如购物数量等等正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致 交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导 致交易失败,那么必须保证这笔失败的交易不影响数据库的状态 -- 库存信息没有被更新、用户也没有付款,订单也没 有生成。否则,数据库的信息将会一片混乱而不可预测。 数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术
为什么要使用事务
1 、为了提高性能2 、为了保持业务流程的完整性3 、使用分布式事务
事务的特征
ACID1 - 原子性 ( atomicity )事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。2 、 一致性 ( consistency )事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。3 、 隔离性 ( isolation ) 一个事务的执行不能被其他事务所影响。企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。由数据库理论可知,由于并发访问,在不可预料的时刻可能引发如下几个可以预料的问题:(见 :事务的并发问题 )4 、 持久性 ( durability )一个事务一旦提交,事物的操作便永久性的保存在 DB 中。即使此时再执行回滚操作也不能撤消所做的更改
事务的并发问题
1 、 脏读 ( Dirty Read )一个事务读取到了另一个事务未提交的数据操作结果。这是相当危险的,因为很可能所有的操作都被回滚。2 、 不可重复读(虚读 )( NonRepeatable Read )一个事务对同一行数据重复读取两次,但是却得到了不同的结果。例如事务 T1 读取某一数据后,事务 T2 对其做了修 改,当事务 T1 再次读该数据时得到与前一次不同的值。3 、 幻读 ( Phantom Read )事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据,这是因为在两次查询过程中有另外一个事务插入数据造成的
事务的隔离级别
1、读未提交Read uncommitted :最低级别,以上情况均无法保证。2、读已提交Read committed :可避免脏读情况发生。4、可重复读Repeatable read :可避免脏读、不可重复读情况的发生。不可以避免虚读。8、串行化读 Serializable :事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重
名称 描述 default (默认值)(采用数据库的默认的设置) (建议) read-uncommited 读未提交 read-commited 读提交 (Oracle数据库默认的隔离级别) repeatable-read 可重复读 (MySQL数据库默认的隔离级别) serialized-read 序列化读
隔离级别由低到高为:read-uncommited < read-commited < repeatable-read < serialized-read
特性
安全性:级别越高,多事务并发时,越安全。因为共享的数据越来越少,事务间彼此干扰减少。
并发性:级别越高,多事务并发时,并发越差。因为共享的数据越来越少,事务间阻塞情况增多。
事务的配置流程
配置DataSourceTransactionManager
1.事务管理器,其中持有DataSource,可以控制事务功能(commit,rollback等)。
<!-- 1. 引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑 -->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
注意:DataSourceTransactionManager 和 SqlSessionFactoryBean 要注入同一个DataSource的Bean,否则事务控制失败!!!
2.配置事务通知
基于事务管理器,进一步定制,生成一个额外功能:Advice。
此Advice可以切入任何需要事务的方法,通过事务管理器为方法控制事务。
<tx:advice id="txManager" transaction-manager="tx">
<tx:attributes>
<!--<tx:method name="insertUser" rollback-for="Exception" isolation="DEFAULT"
propagation="REQUIRED" read-only="false"/>-->
<!-- 以User结尾的方法,切入此方法时,采用对应事务实行-->
<tx:method name="*User" rollback-for="Exception"/>
<!-- 以query开头的方法,切入此方法时,采用对应事务实行 -->
<tx:method name="query*" propagation="SUPPORTS"/>
<!-- 剩余所有方法 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
16.3.2 传播行为
propagation
传播行为当涉及到事务嵌套(Service调用Service)时,可以设置:
SUPPORTS = 不存在外部事务,则不开启新事务;存在外部事务,则合并到外部事务中。(适合查询)
REQUIRED = 不存在外部事务,则开启新事务;存在外部事务,则合并到外部事务中。 (默认值)(适合增删改)
16.3.3 读写性
readonly
读写性
true:只读,可提高查询效率。(适合查询)
false:可读可写。 (默认值)(适合增删改)
16.3.4 事务超时
timeout
事务超时时间当前事务所需操作的数据被其他事务占用,则等待。
100:自定义等待时间100(秒)。
-1:由数据库指定等待时间,默认值。(建议)
16.3.5 事务回滚
rollback-for
回滚属性
如果事务中抛出 RuntimeException,则自动回滚
如果事务中抛出 CheckException(非运行时异常 Exception),不会自动回滚,而是默认提交事务
处理方案 : 将CheckException转换成RuntimException上抛,或 设置 rollback-for="Exception"
事务的属性介绍:这里定义了传播行为、隔离级别、超时时间、是否只读
package org.springframework.transaction;
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0; //支持当前事务,如果不存在,就新建一个
int PROPAGATION_SUPPORTS = 1; //支持当前事务,如果不存在,就不使用事务
int PROPAGATION_MANDATORY = 2; //支持当前事务,如果不存在,就抛出异常
int PROPAGATION_REQUIRES_NEW = 3;//如果有事务存在,挂起当前事务,创建一个新的事物
int PROPAGATION_NOT_SUPPORTED = 4;//以非事务方式运行,如果有事务存在,挂起当前事务
int PROPAGATION_NEVER = 5;//以非事务方式运行,如果有事务存在,就抛出异常
int PROPAGATION_NESTED = 6;//如果有事务存在,则嵌套事务执行
int ISOLATION_DEFAULT = -1;//默认级别,MYSQL: 默认为REPEATABLE_READ级别 SQLSERVER: 默认为
READ_COMMITTED
int ISOLATION_READ_UNCOMMITTED = 1;//读取未提交数据(会出现脏读, 不可重复读) 基本不使用
int ISOLATION_READ_COMMITTED = 2;//读取已提交数据(会出现不可重复读和幻读)
int ISOLATION_REPEATABLE_READ = 4;//可重复读(会出现幻读)
int ISOLATION_SERIALIZABLE = 8;//串行化
int TIMEOUT_DEFAULT = -1;//默认是-1,不超时,单位是秒
//事务的传播行为
int getPropagationBehavior();
//事务的隔离级别
int getIsolationLevel();
//事务超时时间
int getTimeout();
//是否只读
boolean isReadOnly();
3.编制
将事务管理的Advice 切入需要事务的业务方法中
<aop:config>
<aop:pointcut expression="execution(* com.qf.spring.service.UserServiceImpl.*(..))" id="pc"/>
<!-- 组织切面 -->
<aop:advisor advice-ref="txManager" pointcut-ref="pc"/>
</aop:config>
下图是上一个事务案例加一点本节内容