设为首页 加入收藏

TOP

并发下的事务处理(一)
2015-07-24 11:13:33 来源: 作者: 【 】 浏览:2
Tags:并发 事务 处理

事务保障,是软件行业必须要做的事情。很多金融公司,就是由于事务处理不得当而倒闭。

我们都知道,事务有四大特性:ACID。即:原子性、一致性、隔离性、持久性。

四大特性

原子性

事务是数据库的逻辑单位,事务总包括的诸操作那么全部执行,要么都不执行;

一致性

职务执行的结果,必须使数据库从一个一直状态、变到另一个一直状态。一致性与原子性紧密关联。

隔离性

一个事务的执行,不能被其他事务干扰

持久性

一个事务一旦提交,它对数据库中的数据改变就应该是永久性的。

这就是事务的四大特性。

隔离级别

下面,我们来具体来说一说隔离性

我们都知道,事务控制的太严格,程序在并发访问的情况下,会降低程序的性能。所以,人们总是想让事务为性能做出让步,那么就分出了四中隔离级别:

为提交读、提交读、重复读、序列化。

但是,由于隔离界别限制的程度不同,那么就会产生脏读、不可重复读、幻读的情况。

1. 脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

2. 不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以 避免该问题。

3.幻读 :是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。

下面看数据库事务的隔离级别,由低到高依次为未提交读、提交读、重复读、序列化。

这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。

√:可能出现 ×:不会出现

脏读

不可重复读

幻读

Read uncommitted

Read committed

×

Repeatable read

×

×

Serializable

×

×

×

注意:我们讨论隔离级别的场景,主要是在多个事务并发的情况下,因此,接下来的讲解都围绕事务并发。

未提交读

公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有2000元,singo空欢喜一场。

出现上述情况,即我们所说的脏读,两个并发的事务,“事务A:领导给singo发工资”、“事务B:singo查询工资账户”,事务B读取了事务A尚未提交的数据。

当隔离级别设置为Readuncommitted时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

读提交

singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为何......

出现上述情况,即我们所说的不可重复读,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。

当隔离级别设置为Readcommitted时,避免了脏读,但是可能会造成不可重复读。

大多数数据库的默认级别就是Readcommitted,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

重复读

当隔离级别设置为Repeatableread时,可以避免不可重复读。当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。

虽然Repeatableread避免了不可重复读,但还有可能出现幻读。

singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额(select sum(amount) from transaction where month =本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction... ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出现了幻觉,幻读就这样产生了。

注:Mysql的默认隔离级别就是Repeatableread。

序列化

Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。

PS:大多数数据库都是使用提交读,作为默认的隔离级别,如Oracle、SqlServer。因为在数据量访问的情况下,这种方式性能较好,同时防止了脏读的情况发生,尽管有不可重复读的情况,但是在可承受的范围内;也有一些数据采用重复读,作为默认的隔离级别。如果采用默认配置,那么使用MySql的性能会稍低一些。MySql隔离级别的默认配置实现,原理是数据访问时加了读写锁,并发读取时,分别加锁,但是只有第一个加锁的事务,才能修改事务,其他事务不能修改,它避免了可重复读的情况。序列化同样是加锁,但是它加的是独占锁,无论哪个线程读取到数据,立马会将其霸占,直至其操作完成。这种方式一致性高,但是并发性不好,很少使用。

事务的传播特性

在开发中,我们一个action中,可能调用多个Service,那么这种情况,是如何保证事务的呢?事务的传播特性。下面我们来看看Spring事务的传播特性:

1. PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2. PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
3. PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
4. PROPAGATION_REQUIRES_NEW:新建事务,如果

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇数据库迁移:文件系统迁至ASM 下一篇Oracle11g错误:ORA-28002:thepa..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·用 C 语言或者限制使 (2025-12-25 08:50:05)
·C++构造shared_ptr为 (2025-12-25 08:50:01)
·既然引用计数在做 GC (2025-12-25 08:49:59)
·Java 编程和 c 语言 (2025-12-25 08:19:48)
·. net内存管理宝典这 (2025-12-25 08:19:46)