mysql数据库insert update delete操作数据是否是原子性操作?能否实现乐观锁?

小伍
  • 27

mysql数据库insert update delete操作数据是否是原子性操作?

假如update user set age=age+5 where id=1;只修改1条数据,是原子性吗?

再假如update user set age=age+5 where sex=1;会修改一百条数据,是原子性吗?

insert update delete的操作是不是一样的机制?

因为考虑使用如下方式能否正确实现乐观锁?
update user set age=age+5, version=version+1 where id=1 and version=1;

回复
阅读 13.5k
4 个回答

DML语句默认就是一个事务的,是原子操作。

update user set age=age+5, version=version+1 where id=1 and version=1;

可以实现乐观锁。

豆腐居士
  • 835

原子性是针对事务来说的,它是事务的特性之一:是指一个事务包含多个操作,这些操作要么全部执行,要么全都不执行!

乐观锁,是通过类似版本号的机制来实现锁,防止同一记录被其他的会话修改

原子性,这里借用了物理学上的语义。历史上一度认为原子是不可再分割的。原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断。
多个线程并发的对同一个资源进行访问,经常会造成严重的后果,比如各线程之间相互覆盖共享数据,造成被访问数据处于不一致状态等等。
代码的原子性,与代码的长度不是同一个问题,比如说

count++;
1
1
看上去只是一行代码,一个操作,但是,这个操作不是原子性,因为这行代码并不会作为一个不可分割的操作来执行。
这一行代码,包含了三个独立的操作:读取count的值,将值加1,将计算结果写入count。
由于count++这行代码不是原子性的,当多个线程访问count++这行代码时,count的值可能就不是我们期望的结果了。

在Linux内核中,提供了一组实现原子操作的接口。Java.util.current.atomic包中包含了一些原子变量类,这些原子变量类能够便捷帮助程序开发者实现在数值和对象引用上的原子状态转换。

单个变量的原子性得到保障之后,还有一种情况经常遇见,既要保障一系列操作的原子性,将共享数据想象成一个只接受2P的妓女,如果我们开发了一个线程去嫖她,前戏进入高潮,这一系列过程,我肯定不想被其他线程(嫖客)横插一屌。程序当中,一些共享的数据,如果并发的访问,会造成程序错误。那怎样才能取保只有一个执行线程在访问共享的数据呢?——–各种锁机制。
锁,将共享数据挡在身后。在一个指定的时间内,只能有一个执行线程访问共享数据。

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。那么我们如何实现乐观锁呢,一般来说有以下2种方式:
1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。用下面的一张图来说明:

clipboard.png

如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。

2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

我也很好奇呀!
从感觉上无非就这么几种答案!

线程A:update了1条记录
线程B:update了100条记录(这个记录包含者线程A所要update的记录)
线程B在线程A执行后执行!(假如他们发生了冲突)

如果DML含事务的话,mysql控制事务的方式,无非就是悲观和乐观的方式(自我感觉,求指教)
悲观的方式:
情况1,如果A在B前先把记录锁住,那么B回滚
情况2,如果A在B前先把记录锁住,那么B在A执行完后,接着执行
乐观的方式:
情况3,A先与B更新记录,那么B发现A更新了记录,全部回滚!
情况4,A先于B更新记录,那么B发现A更新了记录,继续执行,覆盖A记录!

情况2和情况4都会发生脏读,且情况4要不要乐观锁都一样!
基本能确定情况1和情况3了,但是具体哪种情况,我也不大清楚,希望能有大神接着下去分析,或者给出更好的结论

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏