-
Notifications
You must be signed in to change notification settings - Fork 0
innodb lock
标签(空格分隔): 数据库
在查django transaction.atomic()
配合 select_for_update
使用的过程中,学到了很多东西,记录如下
事务最基本的功能就是保证一批操作要么都成功,要么都失败.值得注意的是, 在一个事务里, 之前的操作对之后的操作是有影响的, 换句话说, 事务里的语句也是一条一条被执行, 而不是等待事务结束后全部执行!
也就是说
with transaction.atomic():
s = Settlement.objects.first()
print s.id # 这条会执行数据库查询操作
sleep(10)
问题: 会读到其他事务还没有提交的改动
优点: Read Uncommitted这种级别,数据库一般都不会用,而且任何操作都不会加锁,这里就不讨论了。 优点就是不用讨论,哈哈哈~
优点: 不会读到其他事务还没有commit的改动
问题: 其他事务commit之后会对其造成影响, 即不可重复读, 第一次读和第二次读中间如果有另外一个事务commit了,第二次的结果可能会与第一次不一样
优点: 第一次查到的数据都会被锁上,其他事务不能更改,所以该事务每次读到的都一样.
问题: 会出现"幻读", 这个名字起得不好, 其实也是两次读到的东西不一样,只不过是因为其他事务insert了新行.只有类似count(*)
这样操作的时候才会和之前不一样.
很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。
sql 标准里重复读是不能解决幻读问题的, 但是mysql innode引擎通过MVVP解决了这个问题.mysql 提供了Next-Key锁: 一种行锁和GAP(间隙锁)的合并,行锁上文已经介绍了,接下来说下GAP间隙锁。
GAP锁能够按照区间锁定, 比如你count(*)
那就把整个表的间隙都锁住, 其他事务就不能insert到这个区间,从而解决了幻读问题.
这个级别很简单,读加共享锁,写加排他锁,读写互斥。使用的悲观锁的理论,实现简单,数据更加安全,但是并发能力非常差。如果你的业务并发的特别少或者没有并发,同时又要求数据及时可靠的话,可以使用这种模式。
这里要吐槽一句,不要看到select就说不会加锁了,在Serializable这个级别,还是会加锁的!
悲观锁: 它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
乐观锁: 通过版本号(创建出若干个快照)解决多事务,并发修改访问问题.
为了保证并发操作, UPDATE 操作都会加上一个读锁, 其他事务不能修改该条记录.
在查询的时候就加一个悲观锁(x锁), 直到本事务结束 这样就不会有人来修改这条数据了.(在少量并发情况下,完美解决问题)
因为innode实现了版本控制的并发机制, 所以能够提供一种任意时刻都可以读的方法(SERIALIZABLE下,所有无格式SELECT语句被 隐式转换成SELECT ... LOCK IN SHARE MODE。):
select . from .;
两种加锁读:
SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;
在共享模式执行一个读意味着我们读最新的可用数据,并在我们读的行设置一个共享锁定。共享模式锁防止其它人更新或删除我们已读的行。同时,如果最新的数据属于其它客户端尚未提交的事务,我们等着知道那个事务被提交。这种模式用途是用来检测一条语句存不存在, 如果存在则能保证不会被删掉.不存在保证别人插不进去(Next-Key).
select . from . for update;
读最新的可见数据,在每个它读取的行设置独占锁定。因此,它设置与搜索的SQL UPDATE可能会在行上设置的锁定同样的锁定。
能解决自己问题的文章难找啊!!!