2019独角兽企业重金招聘Python工程师标准>>>

MySQL/InnoDB的并发插入Concurrent Insert

表people建表语句:ENGINE=InnoDB

CREATE TABLE people  (person_id BIGINT NOT NULL AUTO_INCREMENT,first_name VARCHAR(20),last_name VARCHAR(20),PRIMARY KEY (person_id)
);

两个会话:会话一和会话二

会话一中,执行如下sql语句:

mysql> use local_database;
Database changed
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)mysql> select * from people;
+-----------+------------+-----------+
| person_id | first_name | last_name |
+-----------+------------+-----------+
|         1 | 1111       | 1111      |
+-----------+------------+-----------+
1 row in set (0.00 sec)mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> insert into people (first_name,last_name) values ('1111','1111');
Query OK, 1 row affected (0.12 sec)mysql> select * from people;
+-----------+------------+-----------+
| person_id | first_name | last_name |
+-----------+------------+-----------+
|         1 | 1111       | 1111      |
|         3 | 1111       | 1111      |
+-----------+------------+-----------+
2 rows in set (0.00 sec)

上面这些sql 语句最终的操作就是手动开启了一个事务,然后提交了一个insert语句,注意没有手动提交事务。。

此时在另一个会话二中进行如下操作

mysql> use local_database;
Database changed
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)mysql> select * from people;
+-----------+------------+-----------+
| person_id | first_name | last_name |
+-----------+------------+-----------+
|         1 | 1111       | 1111      |
+-----------+------------+-----------+
1 row in set (0.00 sec)mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> insert into people (first_name,last_name) values ('2222','2222');
Query OK, 1 row affected (0.00 sec)mysql> select * from people;
+-----------+------------+-----------+
| person_id | first_name | last_name |
+-----------+------------+-----------+
|         1 | 1111       | 1111      |
|         4 | 2222       | 2222      |
+-----------+------------+-----------+
2 rows in set (0.00 sec)

上面的sql语句最终的操作是手动开启了一个事务,执行了insert语句,而没有提交事务,然后select查看只会看到当前会话的操作结果,而没有会话一的操作结果。这就是mysql默认事务隔离级别——可重复读。

做到这里,我验证的不是可重复读的事务隔离级别,我其实想验证的是会话在事务内执行insert语句会不会给表加锁(会给表加锁,AUTO-INC lock),通过结果显示,可知,不同的会话在事务内执行insert语句,而不会阻塞其他会话事务内的insert语句

但最终我产生了疑问,MySQL/InnoDB是如何处理并发插入的。

MySQL/InnoDB的并发插入

说起auto_increment的并发插入,就要理解auto_increment的机制了。见文章:

http://my.oschina.net/xinxingegeya/blog/341991

http://my.oschina.net/xinxingegeya/blog/342075

下面我写了两个程序测试并发插入,一个是单线程的写入10w条数据,一个是100条线程单个线程写入1000条数据。可以运行一下程序做一个对比。

建表语句

CREATE TABLE people_thread  (person_id BIGINT NOT NULL AUTO_INCREMENT,first_name VARCHAR(20),last_name VARCHAR(20),thread_name VARCHAR(20),PRIMARY KEY (person_id)
);

总之还是多线程的效率比较高:测试数据如下

单线程的运行时间为:-- 16656ms

多线程的最长的运行时间为:-- 12632ms

JDBCTest2.java

package com.lyx.other;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class JDBCTest2 {public static void main(String args[]) throws SQLException {long startTime = System.currentTimeMillis(); // 获取开始时间Connection conn = null;PreparedStatement ps = null;String sql = "insert into people_thread (first_name ,last_name ,"+ "thread_name) values (?,?,?)";try {conn = getConnection();conn.setAutoCommit(false);ps = conn.prepareStatement(sql);for (int i = 0; i < 100000; i++) {ps.setString(1, Integer.toString(i));ps.setString(2, Integer.toString(i));ps.setString(3, Integer.toString(i));ps.addBatch();// 一批提交一次if (i % 10 == 0) {ps.executeBatch();ps.clearBatch();}}ps.executeBatch();conn.commit();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}long endTime = System.currentTimeMillis(); // 获取结束时间System.out.println("程序运行时间: " + (endTime - startTime) + "ms");}/* 获取数据库连接的函数 */public static Connection getConnection() {Connection con = null; // 创建用于连接数据库的Connection对象try {Class.forName("com.mysql.jdbc.Driver");// 加载Mysql数据驱动con = DriverManager.getConnection("jdbc:mysql://localhost:3306/local_database", "root","034039");// 创建数据连接} catch (Exception e) {System.out.println("数据库连接失败" + e.getMessage());}return con; // 返回所建立的数据库连接}}

JDBCTest3.java

package com.lyx.other;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class JDBCTest3 {public static void main(String[] args) {// 创建10个线程执行插入操作for (int i = 0; i < 100; i++) {final int n = i;Runnable task = new Runnable() {public void run() {Thread.currentThread().setName("thread_" + n);insertByBatch(Thread.currentThread().getName());}};Thread thread = new Thread(task);thread.start();}}public static void insertByBatch(String name) {long startTime = System.currentTimeMillis(); // 获取开始时间Connection conn = null;PreparedStatement ps = null;String sql = "insert into people_thread (first_name ,last_name ,"+ "thread_name) values (?,?,?)";try {conn = getConnection();conn.setAutoCommit(false);ps = conn.prepareStatement(sql);for (int i = 0; i < 1000; i++) {ps.setString(1, Integer.toString(i));ps.setString(2, Integer.toString(i));ps.setString(3, name);ps.addBatch();// 一批提交一次if (i % 10 == 0) {ps.executeBatch();ps.clearBatch();}}ps.executeBatch();conn.commit();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}long endTime = System.currentTimeMillis(); // 获取结束时间System.out.println("程序运行时间: " + (endTime - startTime) + "ms");}/* 获取数据库连接的函数 */public static Connection getConnection() {Connection con = null; // 创建用于连接数据库的Connection对象try {Class.forName("com.mysql.jdbc.Driver");// 加载Mysql数据驱动con = DriverManager.getConnection("jdbc:mysql://localhost:3306/local_database", "root","034039");// 创建数据连接} catch (Exception e) {System.out.println("数据库连接失败" + e.getMessage());}return con; // 返回所建立的数据库连接}}

============END============

转载于:https://my.oschina.net/xinxingegeya/blog/342123

MySQL/InnoDB的并发插入Concurrent Insert相关推荐

  1. MySQL中添加或插入语句(Insert)的几种使用方式

    1.各大培训机构,价格10万的视频 Java架构师视频免费送 2.各种电子书籍经典Java书籍免费送 3.关注下方我的公众号进行免费获取 MySQL中添加或插入语句(Insert)的几种使用方式 1. ...

  2. MySQL中的锁机制、MyISAM表锁、MyISAM表级锁争用情况、MyISAM并发插入Concurrent Inserts、MyISAM的锁调度

    前言: 关于读锁.写锁.乐观锁.悲观锁.行锁.表锁的理解可以看看以前我写的: 读锁.写锁.乐观锁.悲观锁.行锁.表锁 内部锁:在MySQL服务器内部执行的锁,以管理多个会话对表内容的争用.这种类型的锁 ...

  3. 论 MySql InnoDB 如何通过插入意向锁控制并发插入

    前言 在讲解之前,先来思考一个问题--假设有用户表结构如下: MySql,InnoDB,Repeatable-Read:users(id PK, name, age KEY) id name age ...

  4. 〖Python 数据库开发实战 - MySQL篇㉔〗- 数据插入操作 - INSERT语句

    万叶集

  5. mysql内嵌插入语句_MySQL中添加或插入语句(Insert)的几种使用方式

    MySQL中添加或插入语句(Insert)的几种使用方式 1.INSERT 简写方式插入数据(不推荐) 1.先看一下表中有那些数据 2.使用Inset into 表名 values(值1,值2)进行插 ...

  6. mysql innodb 排他锁_MySQL 针对 InnoDB 引擎锁的种类:行锁(共享锁和排他锁)和表锁(意向共享锁和意向排他锁)...

    InnoDB 锁快速到底 行锁:共享锁(S).排他锁(X) 表锁:意向共享锁(IS).意向排他锁(IX) 下面主要针对 MySQL 中行级锁中的共享锁(S)与排他锁(X)进行分析 共享锁又称为读锁,简 ...

  7. mysql innodb 并发插入问题_包大量死锁错误_mysql innodb 并发插入问题,包大量死锁错误...

    开了10个并发写线程,没1000条记录批量提交一次,结果mysql包大量死锁错误! "Deadlock found when trying to get lock; try restarti ...

  8. mysql innodb 多线程插入_mysql innodb 并发插入问题,包大量死锁错误

    开了10个并发写线程,没1000条记录批量提交一次,结果mysql包大量死锁错误! "Deadlock found when trying to get lock; try restarti ...

  9. mysql innodb 并发 插入 慢_InnoDB并发插入,居然使用意向锁?

    今天,将要介绍InnoDB另外三种:共享/排他锁,意向锁,插入意向锁. 一,共享/排它锁(Shared and Exclusive Locks) < InnoDB并发为何这么高? >一文介 ...

  10. MySQL自增字段并发插入导致死锁

    MySQL带自增字段的表在并发插入时发生死锁 问题 'int' object has no attribute 'encode'", <class 'mysql.connector.e ...

最新文章

  1. 深度学习在不同领域的应用,我去,这也行!?
  2. Oracle Study之--Oracle等待事件(2)
  3. Call 从一个批处理程序调用另一个批处理程序,并且不终止父批处理程序。
  4. Extjs日期格式问题
  5. 【POJ - 3468 】 A Simple Problem with Integers (线段树模板 区间更新 + 区间和查询)(不能树状数组或差分数组)
  6. PHP 程序员如何设计一个爬虫程序
  7. 中考计算机flash试题及答案,2015中考信息技术试题Flash操作题2-25(终)
  8. 解决Matlab画图直接保存.eps格式而导致图不全的问题
  9. 服务器增加驱动器,向存储空间直通添加服务器或驱动器
  10. VC中ComboBox控件用法详解
  11. /usr/include/pcap/pcap.h源码
  12. 检测和语义分割_分割和对象检测-第4部分
  13. Redis持久化 - 邱乘屹的个人技术博客
  14. 新版本Google在安装外部扩展插件的时候会提示“程序包”无效的解决方法
  15. 11.21的自动锁屏 ios_iPhone11 的新手小技巧
  16. 负数补码(16进制转10进制的负数)
  17. 微众AI产品经理熊猫杨:AI产品设计的6点心得体会
  18. ABBYY OCR SDK免费试用了!
  19. 怎么用python制作随机点名软件_如何用python编写一个简易的随机点名软件
  20. 【调研学习】手机中的震动马达

热门文章

  1. atitit.ajax 最佳实践跟框架选型 o99
  2. paip.提升性能----数据库连接池以及线程池以及对象池
  3. 阿里云落地全球最大云原生实践:双11核心系统全面云原生化
  4. 降低大数据分析门槛,HashData打造云端数据仓库
  5. 九存:重新定义存储矿机
  6. 【图像融合】基于matalb四叉树的加权聚焦多聚焦图像融合【含Matlab源码 1818期】
  7. 【语音处理】基于matlab GUI语音信号处理与滤波【含Matlab源码 1663期】
  8. 【细胞分割】基于matlab分水岭算法细胞分割计数【含Matlab源码 639期】
  9. 【图像隐写】基于matlab DWT数字水印嵌入+提取+攻击【含Matlab源码 622期】
  10. 【手写数字识别】基于matlab PCA手写数字识别【含Matlab源码 309期】