Mysql 事务和锁的区别

Mysql 事务和锁的区别

  • 事务的4要素
  • 事务的隔离级别
    • 使用锁来保证幂等性

事务的4要素

事务是必须满足4个条件(ACID):

  • 原子性(Atomicity,或称不可分割性)
  • 一致性(Consistency)
  • 隔离性(Isolation,又称独立性)
  • 持久性(Durability)

一句话概括就是,事务中所有的DML,要么全部成功,要么全部失败

事务的隔离级别

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)

注意: 读已提交很多人叫他不可重复读,其实字面意思就是读已提交,很明显就是当前事务可以读取到其他事务已经提交的内容,比如乐观锁,必须使用这种方式

  • 表锁
  • 页锁
  • 行锁
  • 排他锁
  • 共享锁

很多人将事务和锁搞混,首先事务只是避免如果当前事务中某一个DML出错,导致的一致性错误,和锁其实没有什么关系

  • 举个例子 看下面的伪代码
    begin
    user1Money = “select money from user where id=1;”
    if user1Money>10
    update user set money = money-10 where id = 1;
    todo something
    代码出错
    update user set money = money+10 where id = 2;
    commit;
    出错rollback;
    如果出错,那么事务是不会真正修改这2个用户的金额
    但是这和锁没有任何关系,如果并发执行,2条线程当前都检查到用户1的金额确实>10,但是线程1先完成了,但是线程2突然被挂起了,还在等CPU的时间片段
    目前用户1金额是0了。
    线程2恢复,继续执行,成功-> 用户1金额成了-10.
    这并不是我们想要的结果
    所以会用到锁的机制

使用锁来保证幂等性

  • 这里不讨论交叉事务和分布式锁。
  • 乐观锁的方式 隔离级别必须为Read-Commited:
    begin
    while(conditionVariable)
    select version from user where id=1;
    if user1Money>10
    update user set money = money-10,version=version +1 where id = 1 and version = version;
    如果update 影响行数为1 让条件变量失效
    todo something
    update user set money = money+10 where id = 2;
    commit;
    代码中途出错rollback;

版本控制来进行不断尝试,如果当前用户被其他线程改过,那么进行重试

  • 悲观锁 InnoDB
    当select 使用for update时会进行行锁,前提是where条件必须是索引
    begin
    user1Money = "select money from user where id=1 for update;"
    if user1Money>10
    update user set money = money-10 where id = 1;
    todo something
    update user set money = money+10 where id = 2;
    commit;
    代码中途出错rollback;

简单说一下乐观锁和悲观锁的应用场景:
如果修改的数据并发非常高,那么建议使用悲观锁,性能会比乐观锁好很多
如果修改数据的并发不是很高,那么建议使用乐观锁

你可能感兴趣的:(Mysql 事务和锁的区别)