事务具备最重要的两个特性:Spring事务的传播级别和数据库事务的隔离级别。传播级别定义控制范围,隔离级别定义数据库的读写等方面。spring
Spring事务的传播级别:数据库
1. PROPAGATION_REQUIRED: 若是存在一个事务,则支持当前事务。若是没有事务则开启,。适用与大多数场景。缓存
2. PROPAGATION_SUPPORTS: 若是存在一个事务,支持当前事务。若是没有事务,则非事务的执行。 并发
3. PROPAGATION_MANDATORY: 若是已经存在一个事务,支持当前事务。若是没有一个活动的事务,则抛出异常。 框架
4. PROPAGATION_REQUIRES_NEW: 老是开启一个新的事务。若是一个事务已经存在,则将这个存在的事务挂起。新建事务完成以后再恢复执行。 性能
5. PROPAGATION_NOT_SUPPORTED: 老是非事务地执行,并挂起任何存在的事务。 spa
6. PROPAGATION_NEVER: 老是非事务地执行,若是存在一个活动事务,则抛出异常 rest
7. PROPAGATION_NESTED:若是一个活动的事务存在,则运行在一个嵌套的事务中, 若是没有活动事务,则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。orm
数据库事务的隔离级别:xml
事务的隔离级别是基于并发状况下操做数据遇到的异常而言的。这些异常状况有:
一、 Dirty reads---读脏数据:也就是说,事务A的未提交(还依然缓存)的数据被事务B读走,若是事务A失败回滚,会致使事务B所读取的的数据是错误的。
二、 non-repeatable reads---数据不可重复读:好比事务A中两处读取数据-total-的值。在第一读的时候,total是100,而后事务B就把total的数据改为200,事务A再读一次,结果就发现,total居然就变成200了,形成事务A数据混乱。
三、 phantom reads---幻读数据:和non-repeatable reads类似,也是同一个事务中屡次读不一致的问题。可是non-repeatable reads的不一致是由于他所要取的数据集被改变了(好比total的数据)
四、 Lost update---更新丢失:两个事务都同时更新一行数据可是第二个事务却中途失败退出致使对数据两个修改都失效了这是系统没有执行任何锁操做所以并发事务并无被隔离开来.
五、 Second lost updates problem---两次更新:没法重复读取的特例,有两个并发事务同时读取同一行数据,而后其中一个对它进行修改提交而另外一个也进行了修改提交,这就会形成第一次的写操做失效
对于解决以上问题,数据库设置了隔离级别相应的来处理这些问题:
×:表示解决的问题 √:表示可能引发的问题
各级别详解:
第1级别:Read Uncommitted (读取未提交内容)
(1) 全部事务均可以看到其余未提交事务的执行结果
(2) 本隔离级别不多用于实际应用,由于它的性能也不比其余级别好多少
(3) 该级别引起的问题是——脏读(Dirty Read):读取到了未提交的数据
#首先,修改隔离级别 set tx_isolation='READ-UNCOMMITTED'; select @@tx_isolation; +-------------------------------+ | @@tx_isolation | +-------------------------------+ | READ-UNCOMMITTED | +-------------------------------+
|
#事务A:启动一个事务 start transaction; select * from tx; +---------+--------+ | id | num | +---------+--------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +---------+--------+ |
#事务B:也启动一个事务,在事务B中执行更新语句,不提交 start transaction; update tx set num=10 where id=1; select * from tx; +--------+--------+ | id | num | +---------+--------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +---------+--------+ |
#事务A:那么这时候事务A能看到这个更新了的数据吗? select * from tx; +--------+--------+ | id | num | +---------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +->能够看到,说明咱们读到了事务B尚未提交的数据 |
#事务B:事务B回滚,仍然未提交 rollback; select * from tx; +--------+--------+ | id | num | +---------+---------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----------+--------+ |
#事务A:在事务A里面看到的也是B没有提交的数据 select * from tx; +---------+--------+ | id | num | +---------+--------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +-->脏读意味着我在这个事务中(A中),事务B虽然没有提交,但它任何一条数据变化,我均可以看到! |
第2级别:Read Committed(读取提交内容)
(1) 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)
(2) 它知足了隔离的简单定义:一个事务只能看见已经提交事务所作的改变
(3) 这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着咱们在同一个事务中执行彻底相同的select语句时可能看到不同的结果。
致使这种状况的缘由可能有:①有一个交叉的事务有新的commit,致使了数据的改变; ②一个数据库被多个实例操做时,同一事务的其余实例在该实例处理其间可能会有新的commit。
#修改隔离级别 set tx_isolation='read-committed'; select @@tx_isolation; +--------------------------+ | @@tx_isolation | +--------------------------+ | READ-COMMITTED | +---------------------------+ |
#事务A:启动一个事务 start transaction; select * from tx; +---------+---------+ | id | num | +---------+---------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +---------+--------+ |
#事务B:也启动一个事务,在这事务中更新数据,不提交 start transaction; update tx set num=10 where id=1; select * from tx; +---------+---------+ | id | num | +---------+---------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +---------+---------+ |
第3级别:Repeatable Read(可重读)
(1) 这是MySQL的默认事务隔离级别;
(2) 它确保同一事务的多个实例在并发读取数据时,会看到一样的数据行;
(3) 此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另外一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行;
(4) InnoDB和Falcon存储引擎经过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
#更改隔离级别 set tx_isolation='repeatable-read'; select @@tx_isolation; +------------------------+ | @@tx_isolation | +-------------------------+ | REPEATABLE-READ | +-------------------------+ |
#事务A:启动一个事务 start transaction; select * from tx; +--------+---------+ | id | num | +--------+---------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +--------+---------+ |
#事务B:开启一个新事务,在事务B中更新数据,并提交 start transaction; update tx set num=10 where id=1; select * from tx; +--------+---------+ | id | num | +--------+---------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +--------+---------+ commit; |
#事务A:这时候即便事务B已经提交了,但A不能看到数据变化 select * from tx; +--------+---------+ | id | num | +--------+---------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +-> (这个级别2不同,也说明级别3解决了不可重复读问题) |
#事务A:只有当事务A也提交了,它才可以看到数据变化 commit; select * from tx; +--------+---------+ | id | num | +--------+---------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +--------+---------+ |
第4级别:Serializable(可串行化)
(1) 这是最高的隔离级别;
(2) 经过强制事务排序,使之不可能相互冲突,从而解决幻读问题。它是在每一个读的数据行上加上共享锁;
(3) 在这个级别,可能致使大量的超时现象和锁竞争。并发量大的时候,就会死掉。
#首先修改隔离级别 set tx_isolation='serializable'; select @@tx_isolation; +----------------------+ | @@tx_isolation | +-----------------------+ | SERIALIZABLE | +-----------------------+ |
#事务A:开启一个新事务 start transaction; |
#事务B:在A没有commit以前,这个交叉事务是不能更改数据的 start transaction; insert tx values('4','4'); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction update tx set num=10 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
小结:在项目中配置事务------注释方式
一、配置文件
<!-- 定义事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!--使用注释事务 --> <tx:annotation-driven transaction-manager="transactionManager" /> |
注意:使用不一样的orm框架,事务管理器类class就不一样
二、在项目中加@Transactional注释:
(1)放在类名称上,这样配置的@Transactional 对这个类中的全部public方法都起做用;
(2)Transactional 在方法名上,只对这个方法有做用,但必须是public的方法;
三、事物中的属性配置:
(1)事务的传播性:@Transactional(propagation=Propagation.REQUIRED)
(2)事务的超时性:@Transactional(timeout=30) //默认是30秒
(3)事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
(4)事务:
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:
@Transactional(rollbackFor={RuntimeException.class, Exception.class})
(5)只读(true表示只读,默认false表示可读写):ransactional(readOnly=true)
注意:
在spring配置文件中引入<tx:>命名空间: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" 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/context ttp://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> |