MySQL事务
MySQL事务的介绍
1) 事务概念
一组mysql语句,要么执行,要么全不不执行。
2) 事务的特点
1、原子性:一组事务,要么成功;要么撤回。
2、稳定性 :有非法数据(外键约束之类),事务撤回。
3、隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
4、可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项 决定什么时候吧事务保存到日志里。
3) 事务控制语句
-
开启事务:BEGIN或START TRANSACTION;显式地开启一个事务;
-
提交事务:COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改称为永久性的;
-
回滚:ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的务,并撤销正在进行的所有未提交的修改;
-
保存节点:SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
-
删除事务:RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
-
回滚到保存的节点:ROLLBACK TO identifier;把事务回滚到标记点;
4) mysql事务隔离级别
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
-
(1)Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
-
(2)Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
-
(3)Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
-
(4)Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
- 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
-
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
-
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几行(Row)数据,而另一个事务却在此时插入了新的几行数据,先前的事务在接下来的查询中,就会发现有几行数据是它先前所没有的。
5) 设置mysql事务的隔离级别
打开mysql配置文件: sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf, 添加如下行。
保存配置文件,重启mysql服务。
sudo service mysql restart
django中使用事务
下面以天天生鲜项目中的订单提交为例,说明django中事务的使用:
from django.db import transaction class OrderCommitView(View): '''订单创建''' @transaction.atomic ## 使用事务 def post(self,request): '''订单创建''' ## 判断用户是否登录 user = request.user if not user: return JsonResponse({'res':0,'errmsg':'用户未登录'}) ## 1、接收数据 pay_method = request.POST.get('pay_method') addr_id = request.POST.get('addr_id') skus_id = request.POST.get('skus_id') ## 将skus_id的格式转化成列表形式 skus_id = skus_id.split(',') ## 2、校验数据 if not all([pay_method,addr_id,skus_id]): return JsonResponse({'res':1,'errmsg':'数据不完整'}) skus = [] for sku_id in skus_id: ## 遍历skus_id,从数据库中查询sku try: sku = GoodsSKU.objects.get(id=sku_id) skus.append(sku) except GoodsSKU.DoesNoExist: return JsonResponse({'res':2,'errmsg':'商品不存在'}) try: addr = Address.objects.get(id=addr_id) except Address.DoesNoExist: return JsonResponse({'res':3,'errmsg':'地址不存在'}) ## 校验支付方式 if str(pay_method) not in OrderInfo.PAY_METHODS.keys(): return JsonResponse({'res':4,'errmsg':'错误的支付方式'}) ## 设置事务的节点 save_id = transaction.savepoint() ## 3、业务处理 ########## (1)先向订单数据库中添加一条数据,准备数据:order_id、user、addr、pay_method、total_count、total_price、transit_price ## 计算total_count和total_price,先初始化为0,后面查询各个商品的数量和价格之后再进行累加,以及重新保存 try: total_count = 0 total_price = 0 ## 生成order_id:格式:当前的时间+sku_id order_id = datetime.now().strftime('%Y%m%d%H%M%S') + str(user.id) ## 添加数据,创建新的订单数据 order = OrderInfo.objects.create(order_id=order_id, user=user, addr=addr, pay_method=pay_method, total_count=total_count, total_price=total_price, transit_price=10) ########## (2)向商品订单中添加多条数据,准备数据:order、sku、count、price conn = get_redis_connection('default') cart_key = 'cart_%d'%user.id for sku in skus: count = conn.hget(cart_key,sku.id) price = sku.price OrderGoods.objects.create(order=order, sku=sku, count=count, price=price) if sku.stock < int(count): ## 业务失败时,回滚事务 transaction.rollback(save_id) return JsonResponse({'res':6,'errmsg':'库存不足'}) ## MySQL数据库的库存减少,销量增加 sku.stock -= int(count) sku.sales += int(count) sku.save() ## 删除Redis数据库中添加到订单中的数据 conn.hdel(cart_key,sku.id) ## 累加total_count 和total_price total_count += int(count) total_price += int(count)*int(price) ## 重新更新订单中的total_count和total_price order.total_count = total_count order.total_price = total_price order.save() except Exception: ## 业务失败时,回滚事务 transaction.rollback(save_id) return JsonResponse({'res':7,'errmsg':'订单创建失败'}) ## 4、返回应答 return JsonResponse({'res':5,'message':'创建订单成功'})
参考文档:数据库事务
原文地址:https://www.cnblogs.com/maoxinjueluo/p/12883162.html
- Gym 100952A&&2015 HIAST Collegiate Programming Contest A. Who is the winner?【字符串,暴力】
- [开源,学习,分享]UWP第三方简书客户端分享
- HDU 1024 Max Sum Plus Plus【动态规划求最大M子段和详解 】
- 51 Nod 1057 N的阶乘【Java大数乱搞】
- 2017 Multi-University Training Contest - Team 1 1011&&HDU 6043 KazaQ's Socks【规律题,数学,水】
- 2017 Multi-University Training Contest - Team 1 1001&&HDU 6033 Add More Zero【签到题,数学,水】
- 51 Nod 1005 大数加法【Java大数乱搞,python大数乱搞】
- 51 Nod 1029 大数除法【Java大数乱搞】
- 51 Nod 1027 大数乘法【Java大数乱搞】
- SQL常用的基础语法
- 51 Nod 1028 大数乘法 V2【Java大数乱搞】
- Gym 100952J&&2015 HIAST Collegiate Programming Contest J. Polygons Intersection【计算几何求解两个凸多边形的相交面积板子题
- Windows下Cygwin可以使用哪些Linux命令
- Codeforces Round #426 (Div. 2)【A.枚举,B.思维,C,二分+数学】
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- RecyclerView+PagerSnapHelper实现抖音首页翻页的Viewpager效果
- android中使用react-native设置应用启动页过程详解
- 面试官问我单例模式真的安全吗?我懵逼了
- 详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能
- Android自定义控制条效果
- Android使用MediaPlayer和TextureView实现视频无缝切换
- Android实现静默拍照功能
- Android实现动态体温计
- Android实现倾斜角标样式
- 浅谈Flutter 中渐变的高级用法(3种)
- Android实现左上角(其他边角)倾斜的标签(环绕效果)效果
- Android开发中Button组件的使用
- Android开发之基于RecycleView实现的头部悬浮控件
- Android如何通过命令行操作Sqlite3数据库的方法
- Android实现沉浸式状态栏功能