数据库中的事务隔离级别

数据库是要被广大的用户所运行的,不同的用户在同时运行不同的一组命令(事务),数据库要保证这些事务之间不能互相影响。

在开始之前我们要明白几个概念:

脏读: 假如现在有2个并行的事务A和事务B。 此时事务A将 x的值更改成x1,但是尚未提交。但是事务B此时读取x的值读取到了x1,然后呢。事务A此时又将刚才的操作回滚,即事实上,x的值依然是x,但是事务B读到的了x1,是个无效的值。和数据库里存放的真实的值不匹配。

不可重复读:

事务A读取了 Y 的值,是100,事务B 将Y的值更改成了20,事务A再次读取Y的值,和第一次读取的数不一致。(这个很容易和脏读搞混,假如 A此时的事务里有2条查询语句,第一次我们读到的是100,然后在这期间,我们人为的(并行的事务B)将数据库里的100改成了20,下一条查询语句查到的却是20了。 一个事务里,竟然2次的值不一样。)

幻读:
假设这个事务里依然有2条查询的语句,在第一次查询所有的时候,发现里面只有3条记录,查询了出来。但是此时(并行的事务B干的)我们人为的往里面又插入了3条记录。导致表里共有6条数据,但是事务A却只查到了3条。

为了避免可能产生的各种并发问题。在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。

读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。

//就是 事务A 可以读取到事务B修改但是未提交后的数据信息,所以会可能产生 脏读、不可重复读和幻读问题。

读已提交(Read Committed):允许不可重复读,但不允许脏读取。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。(《Oracle数据库的默认隔离级别》)

//因为必须是读且提交,所以此种方式可以避免 脏读、但是还是避免不了 不可重复读和幻读问题。

可重复读(Repeatable Read):禁止不可重复读,和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。(《Mysql数据库的默认隔离级别》)

//避免了脏读和不可查重复读,但是避免不了 幻读。

序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

//全部避免。

MySQL 对这4种隔离级别是全部支持的,默认是Repeatable Read , 而Oracle是只支持 Read Committed  和Serializable。开发中常常使用 Read Committed  ,因为它在并发性能不错的同时可以避免脏读,尽管可能会产生 不可重复读和幻读问题,但是这可以通过悲观锁和乐观锁来控制。,

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,对性能影响也越大,具体要用哪种隔离级别而言还是得看情况。

================================================================================================那假如当前事务1里正在运行一个方法,可是运行在当前事务1里的这个方法也开启了事务2呢(这就是事务的传播),那此时是使用事务1呢还是用事务2呢?还是再开启一个事务?

Spring里的支持的事务传播行为有7种: (我们可以通过propagation来指定,isolation来指定事务的隔离级别)

PROPAGATION_REQUIRED :事务2的方法运行在了事务1里,则使用原来的事务,即事务1。    (默认的!)

PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

PROPAGATION_REQUIRES_NEW :将之前的事务挂起,开启一个新的事务。

PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。

PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常

PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

猜你喜欢

转载自blog.csdn.net/Akanarika520/article/details/84826655