脏读、幻读、不可重复读和丢失更新实例
技术百科
PHP中文网
发布时间:2017-06-21
浏览: 次 2017年6月5日,天气——雨。
前两天整理之前的学习笔记时,发现对事务并发产生的问题——脏读、幻读、不可重复读和丢失更新这些概念有点模糊,于是又重新温习了一遍,现在把自己的一些理解归纳整理如下,方便大家学习。
锁就是防止其他事务访问指定资源的手段。锁是实现并发控制的主要方法,是多个用户能够同时操纵同一个数据库中的数据而不发生数据不一致现象的重要保障。 一般来说,锁可以防止脏读、不可重复读和幻读。
1.脏读(Dirty Read)——一个事务读取到了另外一个事务没有提交的数据。
详细解释:当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
事务T1:更新一条数据
-->事务T2:读取事务T1更新的记录
事务T1:调用commit进行提交
此时事务T2读取到的数据是保存在数据库内存中的数据,称为脏数据,这个过程称为脏读。
脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。
解决脏读问题:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事务操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题。但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。
2.幻读(Phantom)——同一事务中,用同样的操作读取两次,得到的记录数不相同。
详细解释:幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
事务T1:查询表中所有记录
-->事务T2:插入一条记录
-->事务T2:调用commit进行提交
事务T1:再次查询表中所有记录
此时事务T1两次查询到的记录是不一样的,称为幻读。
注意:幻读重点在新增或删除。
幻读发生在当两个完全相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同。
发生的情况:没有范围锁。
如何避免:实行序列化隔离模式,在任何一个低级别的隔离中都可能会发生。
解决幻读问题:采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻读问题。
3.不可重复读(Nonrepeatable Read)——在同一事务中,两次读取同一数据,得到内容不同。
事务T1:查询一条记录
-->事务T2:更新事务T1查询的记录
-->事务T2:调用commit进行提交
事务T1:再次查询上次的记录
此时事务T1对同一数据查询了两次,可得到的内容不同,称为不可重复读。
注意:不可重复读重点在修改。
在基于锁的并行控制方法中,如果在执行select时不添加读锁,就会发生不可重复读问题。
在多版本并行控制机制中,当一个遇到提交冲突的事务需要回退但却被释放时,会发生不可重复读问题。
有两个策略可以防止这个问题的发生:
(1) 推迟事务2的执行,直至事务1提交或者回退。这种策略在使用锁时应用。
(2) 而在多版本并行控制中,事务2可以被先提交,而事务1继续执行在旧版本的数据上。当事务1终于尝试提交时,数据库会检验它的结果是否和事务1、事务2顺序执行时一样。如果是,则事务1提交成功;如果不是,事务1会被回退。
解决不可重复读问题:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题。
4.丢失更新(Lost Update)
事务T1读取了数据,并执行了一些操作,然后更新数据。事务T2也做相同的事,则T1和T2更新数据时可能会覆盖对方的更新,从而引起错误。
5.处理以上隔离级别的问题,采用如下方法:
事务隔离五种级别:
(1)TRANSACTION_NONE 不使用事务。
(2)TRANSACTION_READ_UNCOMMITTED 允许脏读。
(3)TRANSACTION_READ_COMMITTED 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别。
(4)TRANSACTION_REPEATABLE_READ 可以防止脏读和不可重复读。
(5)TRANSACTION_SERIALIZABLE 可以防止脏
读,不可重复读取和幻读,(事务串行化)会降低数据库的效率。
以上的五个事务隔离级别都是在Connection接口中定义的静态常量,使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。
如:con.setTransactionIsolation(Connection.REPEATABLE_READ)。
注意:事务的隔离级别受数据库的限制,不同的数据库支持的的隔离级别不一定相同。
# 过程中
# 的是
# 就会
# 都是
# 第一个
# 第二个
# 还没有
# 两次
# 可以防止
# 另外一个
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Win10怎样安装Excel数据分析工具_Win1
- Win11快速助手怎么用_Win11远程协助连接教
- Go语言中slice追加操作的底层共享机制解析
- php本地部署支持nodejs吗_php与node
- PHP主流架构如何处理会话管理_Session与C
- Windows服务持续崩溃怎样修复_系统服务保护机
- 如何在Golang中引入测试模块_Golang测试
- c++怎么编写动态链接库dll_c++ __dec
- 如何在 PHP 单元测试中正确模拟带方法的图像处理
- LINUX下如何配置VLAN虚拟局域网_在LINU
- LINUX怎么进行文本内容搜索_Linux gre
- Win11怎么设置声音输出设备_Windows11
- Win11怎么开启远程桌面_Win11系统远程桌面
- c++中如何计算坐标系中两点间距离_c++勾股定理
- 如何从 Go 的 map[string]inter
- Win11触摸板没反应怎么办_开启Win11笔记本
- 如何在 Go 中正确测试带 Cookie 的 HT
- 短链接怎么自定义还原php_修改解码规则适配需求【
- PyTorch DDP 多进程训练在 Kaggle
- Win11怎么更改电脑名称_Windows 11修
- C++中的std::shared_from_thi
- 如何在 Pandas 中按元素交集合并两列字符串
- 如何使用Golang defer优化性能_减少不必
- 本地php环境出现502错误_nginx或apac
- c++怎么用jemalloc c++替换默认内存分
- php怎么下载安装后无法解析php文件_服务器配置
- Win11笔记本怎么看电池健康度_Win11电池报
- Win11如何连接Xbox手柄 Win11蓝牙连接
- php怎么操作Redis_Redis扩展连接与基本
- Python与MongoDB NoSQL开发实战_
- Windows10系统怎么查看显卡型号_Win10
- 如何在Golang中捕获结构体方法错误_Golan
- Python包结构设计_大型项目组织解析【指导】
- Win11怎么更改任务栏颜色_Windows11个
- C++ STL算法库怎么用?C++常用算法函数(s
- PHP 中如何在函数内持久修改引用变量所指向的目标
- Python网络异常模拟_测试说明【指导】
- 如何使用Golang操作指针变量_Golang解引
- Win11怎么设置默认邮件应用_Windows11
- Python爬虫项目实战教程_Scrapy抓取与存
- Python模块的__name__属性如何由导入方
- 电脑的“网络和共享中心”去哪了_Windows 1
- 如何在 Laravel 中通过嵌套关联关系进行 o
- Python字符串操作教程_切片拼接与格式化详解
- Mac的访达(Finder)怎么用_Mac文件管理
- Win11怎么设置任务栏对齐方式_Windows1
- Win10系统怎么查看网络连接状态_Windows
- 如何在Golang中实现并发消息队列消费者_Gol
- c++中的std::conjunction和std
- c++中如何使用std::variant_c++1

QQ客服