这里写目录标题

  • 问题
    • 什么是事务
    • 为什么需要事务
      • 创建账户表
      • 插入数据
      • 无事务资金出入账
      • 有事务资金出入账
  • 事务死锁
    • 死锁出现的原因
    • 解决事务死锁
      • 查看表级锁
      • 查询表锁进程
      • 查询行级锁
    • 杀死行锁进程

问题

最近使用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事务死锁 如何解除死锁 资金出入账相关推荐

  1. oracle 事务未正常回滚,Spring事务没有回滚异常(Oracle JNDI数据源)

    我在 Spring MVC 3.1项目中使用基于注释的事务,并且在抛出异常时我的事务没有被回滚. 这是我的服务代码 @Service public class ImportService { @Aut ...

  2. java事务什么时候回滚_spring事务什么时候会自动回滚

    在java中异常的基类为Throwable,他有两个子类xception与Errors.同时RuntimeException就是Exception的子类,只有RuntimeException才会进行回 ...

  3. SQL service的事务提交和回滚

    SQL service的事务提交和回滚 //开始事务,并且在事务后面紧跟您需要写的sql语句(我这里写的是一条修改语句) BEGIN TRANUPDATE UCML_Organize SET Pare ...

  4. Spring不同事务管理方式与声明式事务管理局部回滚处理方案

    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分.  DataS ...

  5. php中对MYSQL操作之事务控制,回滚

    <?php //事务控制,回滚 //创建一个mysqli对象 $mysqli = new MySQLi("主机名","mysql用户名","密码 ...

  6. mysql回滚与错误提示_对mysql事务提交、回滚的错误理解 – jae – 博客园

    一.起因 begin或者START TRANSACTION开始一个事务 rollback事务回滚 commit 事务确认 人们对事务的解释如下:事务由作为一个单独单元的一个或多个 这句话本身没有什么问 ...

  7. mysql数据库回滚日志_MySQL中是如何实现事务提交和回滚的?

    什么是事务 事务是由数据库中一系列的访问和更新组成的逻辑执行单元 事务的逻辑单元中可以是一条SQL语句,也可以是一段SQL逻辑,这段逻辑要么全部执行成功,要么全部执行失败 举个最常见的例子,你早上出去 ...

  8. mysql更新数据能回滚吗_mysql更新数据能回滚吗?如何实现呢?

    不熟悉使用mysql数据库的朋友们,可能会对其有非常多的小问题,例如说,mysql更新数据可以回滚吗?我们应该如何去实现呢? 操作数据库时候难免会因为"大意"而误操作,需要快速恢复 ...

  9. JUnit测试类完成后事务是默认 回滚的。只能查询数据,不能增删改。

    JUnit测试类完成后事务是默认 回滚的.只能查询数据,不能增删改. 在测试类或者测试方法上面加上注解 @Rollback(false)  表示事物不回滚,这样数据就可以提交到数据库中了. 转载于:h ...

最新文章

  1. win8--PPTP教程
  2. Spark On K8S 在有赞的实践与经验
  3. flutter 富文本编辑器选择图片模糊_Flutter 到底香不香?看完这几个开源项目再做决定...
  4. 浙江理工大学电信宽带校园网访问添加路由表命令(2020.10)(Windows和Liunx)
  5. boost::python::pointee相关的测试程序
  6. Springcloud中的region和zone的使用
  7. [剑指offer]面试题1:赋值运算符函数
  8. Atom飞行手册翻译: 2.6 代码段
  9. 少数人知道的公式+思路,财务报表自动生成,财务总监用了5年
  10. 【金融】【python】处理表格(*.xlsx)形式的期货数据
  11. Jenkins linux 操作系统一键部署多节点
  12. 从身份证号获取身份证信息
  13. 怎么_如何制作h5页面?
  14. 常见的打印机无法打印问题
  15. 使用jmeter进行压测
  16. flex布局HTML实例,Flex常见布局实例
  17. matplotlib总结
  18. iis 6.0部署asp网站
  19. 【Sprite Atlas】Unity新图集系统SpriteAtlas超详细使用教程
  20. 嵌入式系统大作业——基于QT的3D模型展示

热门文章

  1. 彝文计算机,计算机彝文信息处理主流技术的分析与探讨
  2. 如何在Excel中使用数据透视表计算百分比变化
  3. lin通信ldf文件解析_LIN通讯机制
  4. Beacon模式下的设置!
  5. 操作系统期末知识点总结
  6. buck降压斩波电路
  7. 百度AI开放平台人体分析_人像分割的Python示例代码
  8. VC驿站全套视频在线观看(B站)
  9. 苹果“面目全非”的 iOS7
  10. 逍遥情缘服务器维护没通告,《逍遥情缘》铁匠惨遭失业 玩家居然打造合成修理样样精通...