MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第1张图片

前言

MySQL是一种开源的关系型数据库管理系统,它使用SQL作为其查询语言。MySQL是最流行的开源数据库之一,它具有高性能、可靠性和可扩展性。MySQL支持多用户、多线程和多表操作,可以在各种操作系统上运行。

MySQL最为最流行的开源数据库,其重要性不言而喻,也是大多数程序员接触的第一款数据库,深入认识和理解MySQL也比较重要。

本篇博客结合生活中常见的转账案例,分析了事务的案例,模拟网络失败情况下事务回滚的情况;分析了百万数据插入数据库时,如何借助提交模式来进行MySQL插入数据库的性能调优。

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第2张图片
本系列文章合集如下:

【合集】MySQL的入门进阶强化——从 普通人 到 超级赛亚人 的 华丽转身

目录

  • 引出
  • 转账业务事务问题
    • SQL实现
      • 例子:网络中断了
      • 例子:自动提交模式下失效
    • 程序实现
  • 百万数据的性能调优
    • 1.逐条提交
    • 2.积攒一批提交
    • 3.变成1次提交
  • 总结

引出


1.结合生活中常见的转账案例,分析了事务的案例,模拟网络失败情况下事务回滚的情况;
2.分析了百万数据插入数据库时,如何借助提交模式来进行MySQL插入数据库的性能调优;

转账业务事务问题

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第3张图片

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `cardId` int(0) NOT NULL,
  `money` int(0) NULL DEFAULT NULL,
  PRIMARY KEY (`cardId`) USING BTREE
) ;
INSERT INTO `user` VALUES (1, 1000);
INSERT INTO `user` VALUES (2, 1000);

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第4张图片

SQL实现

SHOW VARIABLES LIKE 'autocommit';  -- on就是自动提交事务,所以我们没法做回滚....
 COMMIT;  -- 手动提交事务 ,数据就是正式的了,没法回滚了。
 -- 手动关闭以下自动提交事务  0
 set autocommit = 0;
 
-- 1、转账业务事务问题
select * from `user`;

-- =================模拟正常转账,用户a给用户b转1000块钱================
update `user` set money = money - 1000  where cardId = 1;     -- 用户a 扣除
UPDATE `user` set money = money + 1000     where cardId = 2;     -- 用户b 增加

COMMIT; 
set autocommit = 1;

-- 手动关闭以下自动提交事务  0
set autocommit = 0;
-- ===========模拟转账失败,用户a给用户b转1000块钱过程中,突然发生不可预知的问题
update `user` set money = money - 1000  where cardId = 1;     -- 用户a 扣除  。 自动提交事务,也就意味这没法回滚了!!!!!

settt @m = 5 / 0; -- 模拟网络中断问题.   (解决方案:把上一句代码的更新给他还原回去,事务回滚) 

ROLLBACK;   -- 把上一次执行的语句全部还原。没效果。
UPDATE `user` set money = money + 1000     where cardId = 2;     -- 用户b 增加

先把自动提交事务关闭

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第5张图片

此时,执行sql语句,并没有自动提交,数据库数据不变化,当执行commit提交之后,数据库数据才变化。

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第6张图片

例子:网络中断了

模拟转账的时候,出现网络中断的情况,此时由于关闭了事务自动提交,因此,数据库的数据还没有更新

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第7张图片
数据库的数据还没变化

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第8张图片
然后rollback回滚,再手动提交,数据库就回滚了。

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第9张图片

例子:自动提交模式下失效

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第10张图片

在自动提交模式下,rollback命令失效

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第11张图片

程序实现

程序中来实现。 mysql存储引擎必须是innodb, 否则不支持事务

package com.tianju;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 模拟转账业务
 */
public class SQLTestDemo {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost:3306/car_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8";
        Connection conn = DriverManager.getConnection(url, "root", "123");
        // 手动关闭自动提交事务
        conn.setAutoCommit(false);
        try {
            PreparedStatement cmd1 = conn.prepareStatement("update `user` set money = money - 1000  where cardId = 1");
            cmd1.executeUpdate();

            // 模拟网络故障问题
            System.out.println(5 / 0);

            PreparedStatement cmd2 = conn.prepareStatement("update `user` set money = money + 1000  where cardId = 2");
            cmd2.executeUpdate();

            System.out.println("转账成功!!");
            conn.commit(); // 提交事务,让数据真正的持久化。(同时也不能回滚了!!!)

        } catch (Exception e) {
            System.out.println("转账失败.....");
            e.printStackTrace();
            // 回滚
            conn.rollback();
            System.out.println("事务已经回滚成功了.....");
        } finally {

            conn.setAutoCommit(true); //手动把自动提交事务打开,因为我们这个业务比较特殊,所以只是临时用一下而已。。。
            conn.close();  // 关闭连接
        }
    }
}

查看一下系统所支持的引擎类型

SHOW ENGINES

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第12张图片

转账失败,捕获异常,事务回滚

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第13张图片

百万数据的性能调优

SHOW VARIABLES LIKE ‘autocommit’;

自动提交已经打开

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第14张图片

假设现在要插入30000条,3万条数据,对比不同提交方式下的性能

1.逐条提交

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第15张图片

2.积攒一批提交

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第16张图片

3.变成1次提交

MySQL进阶(事务)——转账事务的问题 COMMIT,ROLLBACK & 百万条数据插入的性能调优=3万次提交变成1次_第17张图片

package com.tianju;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 性能调优演示
 */
public class TimeTestDemo {
    // 添加10万条数据到user表
    // 一条一条添加,总共耗时:74232
    // 每执行一条SQL语句,就和数据据交互
    // 解决方案:批量执行SQL语句
    public static void v1() throws SQLException {
        String url = "jdbc:mysql://localhost:3306/car_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8";
        Connection conn = DriverManager.getConnection(url, "root", "123");
        PreparedStatement cmd = conn.prepareStatement("insert into user values(? , ?)");
        int count = 30000;
        // 大忌:尽量避免在循环里面访问数据库.....
        for (int i = 1; i <= count ; i++) {
            cmd.setObject(1,i);
            cmd.setObject(2, 1000);
            cmd.executeUpdate();
        }
        conn.close();
    }


    /**
     * 第二个版本,批量执行SQL
     * 总共耗时:130346
     * @throws SQLException
     */
    public static void v2() throws SQLException {
        String url = "jdbc:mysql://localhost:3306/car_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8";
        Connection conn = DriverManager.getConnection(url, "root", "123");
        PreparedStatement cmd = conn.prepareStatement("insert into user values(? , ?)");
        int count = 30000;
        // 大忌:尽量避免在循环里面访问数据库.....
        for (int i = 1; i <= count ; i++) {
            cmd.setObject(1,i);
            cmd.setObject(2, 1000);
            cmd.addBatch(); // 积攒SQL,把SQL堆在一起
            if (i % 2000 == 0) { //优化算法,每积攒到2000条SQL的时候,批量执行一次
                cmd.executeBatch(); // 批量执行一堆SQL
                cmd.clearBatch(); // 清空SQL缓存
            }
        }
        conn.close();
    }


    // 终极版本。
    // 每更新一条数据,会自动提交事务。(提交很影响性能!!)
    // 一共要提交3万次事务.........
    // 要把3万次事务,变成1次!!
    // 总共耗时:5885  , 放到上百万的服务器,几毫秒
    public static void v3() throws SQLException {
        String url = "jdbc:mysql://localhost:3306/car_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8";
        Connection conn = DriverManager.getConnection(url, "root", "123");
        conn.setAutoCommit(false);
        PreparedStatement cmd = conn.prepareStatement("insert into user values(? , ?)");
        int count = 30000;
        // 大忌:尽量避免在循环里面访问数据库.....
        for (int i = 1; i <= count ; i++) {
            cmd.setObject(1,i);
            cmd.setObject(2, 1000);
            cmd.executeUpdate();
        }
        conn.commit();
        conn.setAutoCommit(true);
        conn.close();
    }



    public static void main(String[] args) throws SQLException {
        long start = System.currentTimeMillis(); // 开始时间
        v3();
        long end = System.currentTimeMillis(); // 结束时间
        System.out.println("总共耗时:" + (end - start));
    }
}

总结


1.结合生活中常见的转账案例,分析了事务的案例,模拟网络失败情况下事务回滚的情况;
2.分析了百万数据插入数据库时,如何借助提交模式来进行MySQL插入数据库的性能调优;

你可能感兴趣的:(#,Database,mysql,adb,数据库)