什么是事务?
事务是将一系列sql语句组合成一个逻辑处理单元,那么这一系列得sql语句需要满足事务的ACID属性:
1.原子性(因为事务是组合在一起的,期望应该是同时执行,要么全成功,要么都不成功)
2.一致性(事务开始到结束数据值一致,如开始获取a为1,在修改之前不能变成其他值,否则不满足事务一致性)
3.隔离性(事务操作期间内部数据对于外部是不可见的,不受外部影响)
4.持久性(事务的数据提交后,对数据改变是永久的)
为什么要使用事务?
业务情况决定,保证操作的原子性比如:
经典业务场景转账:a 转账给 b 1000元
1.a判断有没有1000余额
2.a的余额-1000
3.b的余额增加1000,转账完成
问题:
如果 第二步完成了,第三步发现b的卡注销了,首先转账没有完成,但是a的钱已经被扣掉了
解决办法就是使用事务:
将整个转账的业务写成一个整体,所有操作成功才算完成,然后提交事务,其中一步出错全部回退所有操作
使用事务的问题
如果只是单个操作,那么上面那个问题其实就完成了,但是如果多线操作(并发)会出现那些问题呢?
脏写:事务之间相互隔离,同时操作同一行,结果覆盖
如:两个事务同时去获取a的余额(5000),一个是转账1000出去,一个转账500出去
第一个事务-1000 剩4000,操作完成,第二个事务-500 剩4500,操作完成,结果是
4500,明显不是我们要的结果,称为脏写
脏读:b事务读取a事务未提交的数据称为脏读
如:a事务给a账号-1000,但是还没有提交内容,b事务获取到了4000去做对应操作
a事务发现操作有误,回滚了事务,那么b读到的就是脏数据
不可重复读:相同语句查询到不同内容
如:a事务开始查询a账号5000,此时b事务读取并且很快修改了a的余额为4000.
a事务操作比较慢,修改之前再查询了一下余额,发现两个不一致了,此为不可重复读
幻读:a事务读取到b事务提交了的新数据
幻读感觉上和脏读有点类似,用例子来区分下:
还是a事务,读取a账户的交易记录,第一次默认查7天交易记录,10条。此时b事务
a的老婆用银行卡刷了两条购物出来,而且交易完成,事务提交。然后a又查询了一下,
发现多了两条交易出来,同样查询7天记录,跟出现幻觉一样多了两条,称为幻读
ps:以上所有情况都指的是在事务中的情况,就是开启了begin然后做的操作
有问题就需要处理
数据为了处理以上问题,就出现了事务隔离级别:
以上四种隔离级别就是数据库提供给我们处理上述问题的,隔离级别越高,并发的影响就越小,但是相应的代价就越大
首先我们来看下关于mysql事务隔离级别的设置:
查看当前级别:show variables like 'tx_isolation'
设置事务隔离级别:set tx_isolation='READ-COMMITTED'
上图隔离级别的四个 READ-UNCOMMITTED,READ-COMMITTED
REPEATABLE-READ,SERIALIZABLE
PS:mysql 默认是可重复读
读未提交:a事务读取到b事务未提交的数据
读已提交:a事务读取到b事务提交的事务(满足同一事务中业务数据不要随意变动)
可重复读:a事务读取不到b事务提交的数据,但是能够在更新时感知数据。默认
间隙锁:只在可重复读有效,范围内的值都会加锁(某种程度上可以解决幻读问题)
临键锁:行锁与间隙锁的组合
可串行化:select也会加锁,其他事务无法操作,没有并发问题,但是效率极低
锁是用来协调多个进程或者线程,并发操作同一资源的一种机制,用来保证并发情况下数据不出现问题。
锁的分类:
悲观锁和乐观锁
乐观锁: 开始事务认为没有竞争,更新的时候才去做校验,成功则提交,失败则回滚,实际操作一般用版本控制,如开始获取数据为第一版,后续更新如果版本不变则成功提交,如果版本改变表示被其他操作了,重新获取数据再走业务
悲观锁: 开始事务直接锁定数据,不让其他人操作,完成后再释放
读锁和写锁(都属于悲观锁)
读锁(共享锁):针对同一数据,多个读操作同时进行互不影响
写锁(排他锁):当前写操作未完成,阻断其他写锁与读锁
表锁与行锁
字面理解,一个锁表,一个锁行数据
区别:
表锁加锁快,开销小,不会死锁,并发低,一般表迁移用
行锁加锁慢,开销大,会死锁(a获取b,b获取a,相互获取不到,等待,就死锁了)并发度高
Myisam 数据库引擎一般是表锁,不支持行锁与事务
InnoDB 数据库引擎支持行锁与事务
总结:
mylsam在执行增删改查时都会加对应读锁或写锁
innoDB查询不加锁(不是串行化隔离级别),更新会加行锁
innerDB的行锁是针对索引加的,不是针对数据,如果索引失效,行锁会升级为表锁
锁优化的建议:
1.尽可能让数据检索都通过索引,避免行锁升级
2.合理设计索引,尽量缩小锁的范围
3.减少条件范围。避免间隙锁
4.控制事务大小,减少锁定的资源与时间,加锁的sql能放事务的后面
5.低级别的事务隔离(减少表的锁定)