首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

事务的隔离级别和幻读有关问题

2012-08-31 
事务的隔离级别和幻读问题? 事务的隔离级别,是一个很基本的概念,从自己的角度整理一下.?分为两部分,一个是

事务的隔离级别和幻读问题

?

事务的隔离级别,是一个很基本的概念,从自己的角度整理一下.

?

分为两部分,一个是事务.一个是隔离级别.

?

第一个:事务

ACID是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:

原子性(Atomicity)

一致性(Consistency)

隔离性(Isolation)

持久性(Durability)

?

一个用户的操作可能要修改两张数据表,这个操作对应程序中的方法.以下是示例代码,没有真实意义,只是为了说明.

?

  /**     * 更新项目的站点,示例代码没有意义     * @param pid 项目ID     * @param lid 站点ID     * @return     */    public String updateProject(Integer projectId,Integer siteId){        projectDAO.updateProjectLogicSite(projectId, siteId);        siteDAO.addProject(projectId, siteId);    }

?如果下面的站点加入项目失败

siteDAO.addProject(projectId, siteId);?  //失败,DB中没有生效

但是下面的代码生效了

projectDAO.updateProjectLogicSite(projectId, siteId);//这个DB中生效了

?

因为上面的两句代码是两个事务了.使这个方法整体作为一个事务,(spring事务管理,使用注释方式)

/**     * 更新项目的站点     * @param pid 项目ID     * @param lid 站点ID     * @return     */    @Transactional(isolation=Isolation.REPEATABLE_READ)    public String updateProject(Integer pid,Integer lid){        projectDAO.updateProjectLogicSite(pid, lid);        siteDAO.addProject(pid, lid);    }

?那么,第二个更新站点失败,第一个更新项目也会一起回滚.

具体可以参考spring,和db的事务概率.

?

第二个 隔离级别

那么使用哪个隔离级别呢?

Spring提供了五个可选参数,对应了事务的四个隔离级别(怎么5个对应4个呢?看了就知道)

@Transactional(isolation=Isolation.DEFAULT)  //默认使用DB的隔离级别,如果是mysql的innodb默认是REPEATABLE_READ@Transactional(isolation=Isolation.READ_UNCOMMITTED)@Transactional(isolation=Isolation.READ_COMMITTED)@Transactional(isolation=Isolation.REPEATABLE_READ)@Transactional(isolation=Isolation.SERIALIZABLE)

?每个隔离级别的意思和介绍很多书和文章都讲解的很好,我就不重复了,下面按我自己的思路理一下

?

假设有TA和TB两个方法.都假设一个方法中有两个或者多个DB操作.

从两方面来说明.

A.是否阻塞其他事务往下执行

?

?? 1.TA是读操作先执行?? TB是读操作后执行? 无论两个方法的隔离级别是什么都不影响.

?? 2.TA是读操作先执行?? TB是写操作后执行 只有TA是SERIALIZABLE才会被阻塞.其他时候都不会被阻塞.

?? 3.TA是写操作先执行???TB是读操作后执行? 只有TB是SERIALIZABLE才会被阻塞.其他时候都不会被阻塞.

?? 4.TA是写操作先执行?? TB是写操作后执行? 只有TA没有事务,TB不会被阻塞,其他时候都要等TA操作完成.

?

注意(第4点,这里更严格的表示应该是TA的这个方法没有执行完,TB会被阻塞,方法没有声明为一个事务的时候TA一个DB操作就是一个事务,这个DB操作的时候,是会阻塞TA的写操作的)

?

B.读到的数据

首先假设一个场景是,TA是读操作先执行? 然后TB是写操作,TA再次读取读到的是什么.其实只有这一个场景有问题,其他时候都是正常的操作.或者说TA先写,TB读,这个时候其实是第一个场景的后半部分.下面来列出什么情况读到什么.

TA1和TA2是TA这个方法中的两个读方法

1.TA没有事务?? 无论TB这个事务是否提交 TA2读到的都是TB写的数据.(更新丢失)

2.TA有事务,隔离级别READ_UNCOMMITTED? 无论TB是否提交 TA2读到的都是TB写的数据? (和上面的区别是没有第一中更新丢失,但是TB回滚TA2会脏读)

3.TA有事务,隔离级别READ_COMMITTED? TA2读到的都是TB事务提交后的数据,没有提交读不到.(没有脏读,TA1读和TA2读到的不一致)

4.TA有事务 隔离级别REPEATABLE_READ?? TA2读到的数据和TA1一样无论TB是否有提交(所以可以重复读,这里有幻读的问题,下面专门介绍幻读)

5.TA有事务 隔离级别SERIALIZABLE? TA2读到的和TA1一样,幻读都没有,看阻隔就知道,有写的时候都是排队来的.

幻读

专门理一下幻读,幻读发生在读一张表中不同行的数据时.

比如TA1读操作 ?select * from project where create_date > '20100101' 第一次查询有2条记录.

TB写操作???? 插入一条记录创建时间大于20100101的记录

TA2 再读 就读出3条记录了,这个时候就幻读了.

因为REPEATABLE_READ的时候TB是可以同时写的就有这个问题.

SERIALIZABLE是排队的,TB只有在TA的两次读操作都完成后才可以写,所以是完全没有问题的.

?

幻读导致的问题1

比如注册用户,希望用户名不重名.

TA和TB要注册用户gtbald.

TA1查询不存在gtbald.

TB1查询不存在gtbald.

TA2插入gtbald

TB2插入gtblad.

有两个gtbald了.

目前我知道的解决办法可以是DB用户名加上唯一索引.或者业务中注册事务隔离级别设为SERIALIZABLE(性能差).

?

幻读导致的问题2

比如报名人数限制为100人

TA和TB都要提交报名人

TA1查询总报名人数99人

TB1查询总报名人数99人

TA2增加报名一人 现在总报名人数100人

TB2增加报名一人? 现在总报名人数101人

?

目前我知道的解决办法:报名务隔离级别设为SERIALIZABLE(性能差).

接下来研究幻读问题的解决方案.

热点排行