mysql事务 mysql事务回滚 MySQL事务死锁 如何解除死锁 资金出入账
这里写目录标题
- 问题
- 什么是事务
- 为什么需要事务
- 创建账户表
- 插入数据
- 无事务资金出入账
- 有事务资金出入账
- 事务死锁
- 死锁出现的原因
- 解决事务死锁
- 查看表级锁
- 查询表锁进程
- 查询行级锁
- 杀死行锁进程
问题
最近使用golang做资金账户,目前涉及到这两个问题
- 资金入账时,可能存在提现【出账】
- 资金提现时,可能存在资金入账
因而,为了保证资金的正确性,这里需要事务操作。
什么是事务
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
为什么需要事务
以上面资金出账和入账为例子,写出如下没有事务的代码:
创建账户表
mysql> create table account (-> id int(11) primary key not null auto_increment comment '账户自增主键id',-> userId int(11) not null comment '用户id',-> balance int(11) not null DEFAULT 0 comment '账户余额,默认为0'-> ) ENGINE = 'INNODB';
Query OK, 0 rows affected (0.06 sec)
由Query OK, 0 rows affected (0.06 sec)
可知,account
表创建成功。
插入数据
mysql> insert into account(userId,balance) values(1223,444),(1224,666);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
由Query OK, 2 rows affected (0.01 sec)
可知,数据插入成功。
无事务资金出入账
- 假设
用户1223
给用户1224
转账100元。 - 若转账成功,
用户1223
的账户余额为344元,用户1224
的账户余额为766元。 - 如果转账失败,
用户1223
给用户1224
的账户余额不变。
按照这个想法,设计如下SQL语句,此时是没有事务的:
-- 执行用户1223的出账,用户1224的入账
mysql> update account set balance = balance -100 where userId = 1223;update account set balance = balance + 100 where useId = 1224 ;Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0ERROR 1054 (42S22): Unknown column 'useId' in 'where clause'
在两条SQL语句中,用户1223
出账SQL语句正确,即其账户余额为344元;用户1224
入账SQL语句错误,因为account表
中没有useId
这个字段,因而其账户余额不变,仍旧是666元,如下SQL所示:
mysql> select * from account;
+----+--------+---------+
| id | userId | balance |
+----+--------+---------+
| 1 | 1223 | 344 |
| 2 | 1224 | 666 |
+----+--------+---------+
2 rows in set (0.00 sec)
这就和我们的预期不同,此时,我们使用如下SQL恢复用户1223
的账户余额:
mysql> update account set balance = balance + 100 where userId = 1223 ;Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
然后使用事务,再次执行上述SQL。
有事务资金出入账
依旧是``用户1223给
用户1224```转账100元,如下所示:
-- 开启事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)-- 执行用户1223的出账,用户1224的入账
mysql> update account set balance = balance -100 where userId = 1223;update account set balance = balance + 100 where useId = 1224 ;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0ERROR 1054 (42S22): Unknown column 'useId' in 'where clause'-- 出现错误语句,回滚金额
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)-- 查询回滚后的账户余额
mysql> select * from account;
+----+--------+---------+
| id | userId | balance |
+----+--------+---------+
| 1 | 1223 | 444 |
| 2 | 1224 | 666 |
+----+--------+---------+
2 rows in set (0.00 sec)
- 首先,开启事务
- 执行
用户1223
的出账,用户1224
的入账 用户1223
的出账SQL正确,用户1224
的入账SQL错误- 出现错误的SQL语句,事务回滚
- 查询账户余额,发现账户余额不变,符合我们的预期。
因而,为了保证资金的正确性,我们必须使用事务。
事务死锁
死锁出现的原因
在事务的情况下,给某个账户加上行级锁。
我使用的是for update
的悲观行级锁,但前置条件是,当前账户要存在,否则,行级锁就会变成表解锁,锁粒度就会增加。
比如,在提现时,需要判断当前账户是否绑卡,如果没有绑卡,就抛出您尚未绑卡的toast
。一般情况下都绑了卡,但就怕特殊情况,真的是想啥来啥。恰巧遇到某用户没有绑卡,抛出您尚未绑卡的toast之后,再次访问就报出如下问题:
于是去排查问题,发现在抛出尚未绑卡的异常时,没有将事务回滚,于是,此处添加事务回滚tx.rollBack
。
如果不进行事务回滚,那么当前行就不释放锁,相同的请求SQL过来,就会不停地尝试连接,,如果连接不成功,则会抛出连接超时的问题。
当前行不释放锁,新的SQL请求加锁,便出现了死锁的情况。
解决事务死锁
查看表级锁
如果行级锁不存在,使用SQLshow OPEN TABLES where In_use > 0
查看是否存在表级锁,如下SQL所示:
mysql> show OPEN TABLES where In_use > 0;
Empty set (0.00 sec)
查询表锁进程
其次,查询进程(如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程)show processlist
,最后杀死【kill】
进程id
查询行级锁
使用sql语句SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
查看当前存在锁的事务,如下图存在一个事务死锁:
杀死行锁进程
杀死锁进程,我们可以使用命令: kill trx_mysql_thread_id
比如杀死如上的行级死锁,找到trx_mysql_thread_id
的数值,执行命令:kill 4314823
mysql事务 mysql事务回滚 MySQL事务死锁 如何解除死锁 资金出入账相关推荐
- oracle 事务未正常回滚,Spring事务没有回滚异常(Oracle JNDI数据源)
我在 Spring MVC 3.1项目中使用基于注释的事务,并且在抛出异常时我的事务没有被回滚. 这是我的服务代码 @Service public class ImportService { @Aut ...
- java事务什么时候回滚_spring事务什么时候会自动回滚
在java中异常的基类为Throwable,他有两个子类xception与Errors.同时RuntimeException就是Exception的子类,只有RuntimeException才会进行回 ...
- SQL service的事务提交和回滚
SQL service的事务提交和回滚 //开始事务,并且在事务后面紧跟您需要写的sql语句(我这里写的是一条修改语句) BEGIN TRANUPDATE UCML_Organize SET Pare ...
- Spring不同事务管理方式与声明式事务管理局部回滚处理方案
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataS ...
- php中对MYSQL操作之事务控制,回滚
<?php //事务控制,回滚 //创建一个mysqli对象 $mysqli = new MySQLi("主机名","mysql用户名","密码 ...
- mysql回滚与错误提示_对mysql事务提交、回滚的错误理解 – jae – 博客园
一.起因 begin或者START TRANSACTION开始一个事务 rollback事务回滚 commit 事务确认 人们对事务的解释如下:事务由作为一个单独单元的一个或多个 这句话本身没有什么问 ...
- mysql数据库回滚日志_MySQL中是如何实现事务提交和回滚的?
什么是事务 事务是由数据库中一系列的访问和更新组成的逻辑执行单元 事务的逻辑单元中可以是一条SQL语句,也可以是一段SQL逻辑,这段逻辑要么全部执行成功,要么全部执行失败 举个最常见的例子,你早上出去 ...
- mysql更新数据能回滚吗_mysql更新数据能回滚吗?如何实现呢?
不熟悉使用mysql数据库的朋友们,可能会对其有非常多的小问题,例如说,mysql更新数据可以回滚吗?我们应该如何去实现呢? 操作数据库时候难免会因为"大意"而误操作,需要快速恢复 ...
- JUnit测试类完成后事务是默认 回滚的。只能查询数据,不能增删改。
JUnit测试类完成后事务是默认 回滚的.只能查询数据,不能增删改. 在测试类或者测试方法上面加上注解 @Rollback(false) 表示事物不回滚,这样数据就可以提交到数据库中了. 转载于:h ...
最新文章
- win8--PPTP教程
- Spark On K8S 在有赞的实践与经验
- flutter 富文本编辑器选择图片模糊_Flutter 到底香不香?看完这几个开源项目再做决定...
- 浙江理工大学电信宽带校园网访问添加路由表命令(2020.10)(Windows和Liunx)
- boost::python::pointee相关的测试程序
- Springcloud中的region和zone的使用
- [剑指offer]面试题1:赋值运算符函数
- Atom飞行手册翻译: 2.6 代码段
- 少数人知道的公式+思路,财务报表自动生成,财务总监用了5年
- 【金融】【python】处理表格(*.xlsx)形式的期货数据
- Jenkins linux 操作系统一键部署多节点
- 从身份证号获取身份证信息
- 怎么_如何制作h5页面?
- 常见的打印机无法打印问题
- 使用jmeter进行压测
- flex布局HTML实例,Flex常见布局实例
- matplotlib总结
- iis 6.0部署asp网站
- 【Sprite Atlas】Unity新图集系统SpriteAtlas超详细使用教程
- 嵌入式系统大作业——基于QT的3D模型展示