事务的隔离级别 另一种事务开启方式

Posted ludingchao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事务的隔离级别 另一种事务开启方式相关的知识,希望对你有一定的参考价值。

事务是有隔离级别

read uncommited (读未提交):不做任何隔离,具有脏读,不可重读对,幻读的问题

read committed (读提交):可以防止脏读,不能防止不可重复读和幻读的问题

repeated read(可重复读):可以防止脏读,不可重复读,不能放在幻读(mysql的默认隔离级别)

serializable(串行化):数据库运行为串行,以上问题都可以防止,但是性能低

下面的解释都用这个user表

技术图片

 

脏读(a,b同时开始事务,a,b再事务,没有哪一个结束,只有两个都进入事务后,才能结束期中一个事务,两个事务都是存活的)

1 a  开启事务  将jason的年龄改成 18岁,但是没有提交事务
2 b  开始事务  读取jason的年龄,发现是18岁。

上述的问题,
假设a事务回滚,b事务使用的数据就是错误的,就导致程序数据不正确。

不可重复度(a,b同时开始事务,a,b再事务,没有哪一个结束,只有两个都进入事务后,才能结束期中一个事务,两个事务都是存活的) read committed

1 a  开始事务  将jason的年龄改成18岁,但是提交了
2 b  开启事务  读取jason的年龄就能读取a事务修改后的jason年龄18岁。

# 如果a未提交,b读取jason年龄会卡死

可重读读(a,b同时开始事务,a,b再事务,没有哪一个结束,只有两个都进入事务后,才能结束期中一个事务,两个事务都是存活的) repeated read

1 a  开始事务  将jason的年龄改成18岁,但是提交了
2 b  开启事务  读取jason的年龄不能读取a事务修改后的jason年龄18岁。而是读取的是38岁

幻读(a,b同时开始事务,a,b再事务,没有哪一个结束,只有两个都进入事务后,才能结束期中一个事务,两个事务都是存活的) serializable解决幻读问题

#概念和不可重读有点像,不可重复度是站在修改的基础上,而幻读是站在新增的基础上
1 a  开始事务  将所有的的年龄改成18岁
2 b  开始事务  新增一条数据数据name=tank,age=19,而且提交了。
3 a  重新查, 发现有一条数据 的age=19,这就是所谓的幻读。

如何看msql的隔离级别

select @@global.tx_isolation;    # 默认为 REPEATABLE-READ

技术图片

如何修改事务的隔离级别

#修改配置文件     可在mysql文件夹中my.ini配置文件中查看
transaction-isolation=Read-Committed
#修改后一定要重启数据库    (删除后回复默认REPEATABLE-READ)

数据库的乐观锁与悲观锁(是建立再事务的基础上)

悲观锁

悲观锁的概念,他觉有人会修改我读的数据。那我就再查的时候,对数据进行锁定。
(悲观锁:假定会发送并发从图,屏蔽一切可能违反数据完整性的操作,理论上别人可以查)

select age from user where id=1 for update;
比如 上面的查出来的 age =18 
update age改成age = age+ 1
如果该次查询走了索引,那就是行锁,如果没有走索引就是表锁。

如何释放锁呢?结束事务就释放了锁。    (commit或者rollback)
django中的orm是如果用悲观锁?
user.objects.select_for_update().filter(id=1).first()

mysql使用悲观锁

原生的sql语句:
1 开启事务
2 查询的时候加锁---》select * from user where id =1 for update
3 当结束事务锁就被释放
django中的:
1 开始事务
2 在查询的时候 ----》 User.objects.select_for_update().filter(id =1 ).first()
3 可以对数据进行修改,数据永远不会被比如人修改,只有你自己能动
4 当结束事务锁就被释放

 

乐观锁

乐观锁的本质不是锁。他是通过代码来实现锁的。他觉的别人不会修改的他的数据。他就读数据不会背别人修改。最后再修改该条数据,再where条件中添加,之前查出来的数据。以保证数据的安全性
select age from user where id=1 ;
比如 上面的查出来的 age =18   
20 
update age改成age = age+ 1  ====》19

乐观锁:
update age改成age = age+ 1 where age =18 and id =1  ====》19
如果我发现不是18,上面的影响行数是0

#如果是可重复读,上面的乐观锁无效,必须改成read committed    *django2.0以后,用乐观锁不需要修改隔离级别(应该是局部修改)*
a update age改成age = age+ 1  ====》19 提交

b select age from user where id=1; --->18     # 可重复读隔离界别下的情况,乐观锁失效

update age改成age = age+ 1 where age =18 and id =1  ====》19  ---->数据已经被改

 mysql使用乐观锁(如果使用乐观锁,mysql隔离级别要变成read committed,在django2.0以后,用乐观锁不需要修改隔离级别

乐观本质不是锁,是通过代码级别实现数据安全
1 开始事务
2 查询的时候不要做任何操作data= User.objects.filter(id =1 ).first()将这个条数据中的age在原来的基础上加1
3 在修改数据的时候。User.objects.filter(id = 1 ,age = data.age).update(age = data.age+1)从而保证在我查询到我修改的这段时候,没有人动过我的数据。
4 如果3中的更新的影响行数为1,说明数据没有被别人改动,只我动,如果3中的影响行数为0,说明该数据已经被别人修改。这时我们想要改数据,就必须重复执行2-3两不,直到3有影响行数。

 

另一种事务开启方式

django transaction用法
from django.db import transaction
from django.http import HttpResponse
from django.utils.decorators import method_decorator


# 类中添加装饰器,保证在该类中所有的数据库操作都在一个事物中
@method_decorator(transaction.atomic, name=dispatch)
class MyView1(object):
    
    def get(self, request):
        return HttpResponse(GET)
    
    def post(self, request):
        return HttpResponse(POST)


class MyView2(object):
    
    # 保证在该函数中所有的数据库操作都在一个事物中
    @transaction.atomic
    def post(self, request):

        # 设置事物保存点(可设多个)
        t1 = transaction.savepoint()

        # 如果有异常情况可回滚到指定的保存点
        transaction.savepoint_rollback(t1)

        # 如果没有异常可提交事物
        transaction.savepoint_commit(t1)
        return HttpResponse(POST)

回滚点可以参考

https://blog.csdn.net/rockpk008/article/details/25437415

 

以上是关于事务的隔离级别 另一种事务开启方式的主要内容,如果未能解决你的问题,请参考以下文章

事务和锁机制是什么关系? 开启事务就自动加锁了吗?

Mysql事务-隔离级别

事务及事务隔离级别

MySQL:事务四大特性与隔离级别

事务及事务隔离级别

转事务及事务隔离级别