Heim >Datenbank >MySQL-Tutorial >并发操作与数据的不一致性
最近做的《选修课系统》需要考虑这样一个问题:数据库的并发操作带来的数据库数据不一致问题因为是全校性选修课,同一时间点大批学生选课,那么必然存在多名学生同时对同一数据进行操作是的问题,如果这种并发操作不加以控制的话,必会造成数据的不一致。 一
最近做的《选修课系统》需要考虑这样一个问题:数据库的并发操作带来的数据库数据不一致问题——因为是全校性选修课,同一时间点大批学生选课,那么必然存在多名学生同时对同一数据进行操作是的问题,如果这种并发操作不加以控制的话,必会造成数据的不一致。
一直知道有这种问题,并且知道这种问题的解决方法——加锁;但是有些东西之前了解的并不是很透彻,于是好好研究了一天,觉得理解的还可以,先总结一部分。
数据库的一个重要特征是:支持数据共享,也就是说允许多个用户程序并行地存取数据库中的数据;那么,多用户或多事物可能同时对同一数据进行操作,这成为并发操作。
如果不对并发操作进行控制的话,那么就会存取不正确的数据,破坏数据的完整性。——为什么这么说?下面进行介绍
在此之前,先说一下事务的概念。
对一件完整的事儿,要么做完整,要么都不做。例如:学生选课—学生选上课时,需要将选课信息写入选课表的同时,更新课程表中的课程余量;如果在添加选课信息时,中断了(不能进行余量更新),那么就会事务回滚,即,数据回滚到没选课之前。
Begin Transaction
选课表中添加选课信息;
更新课程表中的课程余量;
Commit
RollBac
事务的SQL语句:
Begin Transaction开始事务
Commit提交事务
RollBack回滚
(注:事务中的多条SQL语句也是一条条执行的,当所有语句执行完后,提交事务,如果其中一条中断,则事务回滚所有操作回到语句执行之前)
事务的并发主要是为了提高效率,但是,同时它也带来了一定问题
之前讲过并发操作——多用户或多事务同时对同一数据进行操作;
因为事务中的语句也是一条条执行的,所以存在多用户多事务同时对同一数据进行操作的情况;
并发操作带来的问题:
(1)丢失修改
(2)脏读
(3)不可重复读
当两个或多个事务(或两个或多个用户)选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在(或每个用户操作时并不会考虑同一时刻是否有别的用户进行着同样的操作)。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。
例子1:事务T1,事务T2,数据库中数据R=1000
a.t1时刻,事务T1读取R=1000;
b.过了一会儿 t2时刻,事务T2读取R=1000;
c.t3时刻,事务T1修改R=R-200(那么R=800)写入数据库(此时,数据库中R=800);
d.过了一会儿 t4时刻,事务T2修改R=R-100(因为在t2时刻读到的数据为R=1000,那么修改后R=900)写入数据库(此时,数据库中R=900)
那么最终,数据库中R=900;数据对吗?当然不对,因为T1、T2分别对R进行了-200 -100操作,最终数据应为R=700;事务T2的修改覆盖了T1的修改 ——丢失修改问题
例子2:选课:学生A、学生B、课程1的余量=20
a.学生A选择课程1时,先读出课程余量20
b.然而同一时刻(也可是不同时刻,只要在学生A更新数据之前),学生B也读出了课程1的余量20,
c.学生A选择此课程,课程1余量-1,写入数据库,此时课程1的余量=19;
d.学生B选择此课程,课程1余量-1(因为之前读出的课程1余量为20,-1后为19),写入数据库,此时课程1的余量=19;
课程余量=19 数据正确吗?不正确。实际情况课程余量应更新为18;——B的修改覆盖了A的修改 —— 丢失修改问题。
解决办法:加锁,只允许并发一个更新事务。
当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,
另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个
事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
例子1:事务T1,事务T2,数据库中数据R=1000;
T1:
Begin Transaction开始事务T1
ReadR=1000;(1)
R=R-200;(2)此时R=800
R=R+100;(3)此时R=900
Commit提交事务T1
a.当事务T1进行到第(2)后,即,数据库中的数据R=800时;
b.事务T2开始读R的值,读出的值为R=800;但此时事务T1还没有进行完整,还未提交事务;
c.之后事务T1进行第(3)步R=R+100,此时R=900 事务T1提交,此时数据库中R=900;
那么在事务T1提交事务之前,事务T2读出的数据(R=800)为脏数据;
例子2:
a.张三的工资为2000,元老板把张三的工资改为了8000元(但未提交事务)
2.张三查看自己的工资 ,发现工资变为了8000元
3.而后老板发现改错了,回滚了事务,张三的工资又变回了2000元
那么,张三读取的工资8000元就是脏数据。
解决办法:如果在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。
当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。
在一个事务中前后两次读取的结果并不致,导致了不可重复读。
例子1:事务T1、事务T2、张三的工资=1000
a.事务T1中,张三读取了自己的工资为1000元,操作并没有完成
b.此时(事务T1读取了张三工资为1000元)事务2中,修改了张三的工资为2000元,并提交了事务.
c.此时(事务T1读取了张三工资为1000元,事务T2修改了张三的工资为2000元)在事务1中,张三再次读取自己的工资时,工资变为了2000
那么,同一个事务中,前后读取的数据不一致 —— 不可重复读问题。
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
(1)事务的并发主要是为了提高效率,但是,同时它也带来了一定问题——丢失修改、读脏数据、不可重复读
(2)结合生活中实例,理解丢失修改、读脏数据、不可重复读问题。
个人理解,如果哪里有理解偏差,忘纠正!
下篇博客会总结“锁”的概念,并解释“锁”是如何解决并发造成的数据不一致问题。