前言
MySQL是一种开源的关系型数据库管理系统,它使用SQL作为其查询语言。MySQL是最流行的开源数据库之一,它具有高性能、可靠性和可扩展性。MySQL支持多用户、多线程和多表操作,可以在各种操作系统上运行。
MySQL最为最流行的开源数据库,其重要性不言而喻,也是大多数程序员接触的第一款数据库,深入认识和理解MySQL也比较重要。
本篇博客结合生活中常见的转账案例,分析了事务的案例,模拟网络失败情况下事务回滚的情况;分析了百万数据插入数据库时,如何借助提交模式来进行MySQL插入数据库的性能调优。
【合集】MySQL的入门进阶强化——从 普通人 到 超级赛亚人 的 华丽转身
1.结合生活中常见的转账案例,分析了事务的案例,模拟网络失败情况下事务回滚的情况;
2.分析了百万数据插入数据库时,如何借助提交模式来进行MySQL插入数据库的性能调优;
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);
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 增加
先把自动提交事务关闭
此时,执行sql语句,并没有自动提交,数据库数据不变化,当执行commit提交之后,数据库数据才变化。
模拟转账的时候,出现网络中断的情况,此时由于关闭了事务自动提交,因此,数据库的数据还没有更新
在自动提交模式下,rollback命令失效
程序中来实现。 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
转账失败,捕获异常,事务回滚
SHOW VARIABLES LIKE ‘autocommit’;
自动提交已经打开
假设现在要插入30000条,3万条数据,对比不同提交方式下的性能
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插入数据库的性能调优;