带有 BLOB 列的 MySQL 5.7 批量插入
Posted
技术标签:
【中文标题】带有 BLOB 列的 MySQL 5.7 批量插入【英文标题】:MySQL 5.7 bulk insert with BLOB column 【发布时间】:2019-03-18 00:22:15 【问题描述】:我正在尝试使用
对 mysql 进行批量插入INSERT INTO TABLE (a, b, c) VALUES (?, ?, ?), (?, ?, ?)
我有常规登录,并且看到这在大多数情况下都非常有效。但是,当表有 BLOB 列时,它就不能正常工作了。
我正在尝试插入 20 条记录。
没有 BLOB,我在通用日志中看到同一查询中的所有 20 条记录,同一查询中插入了 20 条记录。
使用 BLOB,我在常规日志中只看到每个查询 2 条记录,总共需要 10 个查询。
这是 MySQL、JDBC 驱动程序的问题,还是我遗漏了其他东西。我更喜欢使用 BLOB,因为我在 protobufs 中有数据。
这是一个示例表...
CREATE TABLE my_table (
id CHAR(36) NOT NULL,
name VARCHAR(256) NOT NULL,
data BLOB NOT NULL,
PRIMARY KEY (id)
);
然后,在代码中创建批量插入...
val ps = conn.prepareStatement(
"INSERT INTO my_table(id, name, data) VALUES (?, ?, ?)")
records.grouped(1000).foreach group =>
group.foreach r =>
ps.setString(1, UUID.randomUUID.toString)
ps.setString(2, r.name)
ps.setBlob(3, new MariaDbBlob(r.data))
ps.addBatch()
ps.executeBatch()
如果您运行它并检查常规日志,您将看到...
"2018-10-12T18:37:55.714825Z 4 查询 INSERT INTO my_table(id, name, fqdn, data) VALUES ('b4955537-2450-48c4-9953-e27f3a0fc583', '17-apply-test', _二进制' 17-apply-test\"AAAA(?2Pending8???,J$b4955537-2450-48c4-9953-e27f3a0fc583
1:2:3:4:5:6:7:8Rsystem'), ('480e470c-6d85-4bbc-b718-21d9e80ac7f7', '18-apply-test', _binary' 18-apply-test\"AAAA(?2Pending8?????,J$480e470c-6d85-4bbc-b718-21d9e80ac7f7
1:2:3:4:5:6:7:8Rsystem') 2018-10-12T18:37:55.715489Z 4 查询 INSERT INTO my_table(id、name、data)值('7571a651-0e0b-4e78-bff0-1394070735ce'、'19-apply-test'、_binary' 19-apply-test\"AAAA(?2Pending8???,J$7571a651-0e0b-4e78-bff0-1394070735ce
1:2:3:4:5:6:7:8Rsystem'), ('f77ebe28-73d2-4f6b-8fd5-284f0ec2c3f0', '20-apply-test', _binary' 20-apply-test\"AAAA(?2Pending8???,J$f77ebe28-73d2-4f6b-8fd5-284f0ec2c3f0
如您所见,每个 INSERT INTO 中只有 2 条记录。
现在,如果您从架构中删除 data
字段并插入并重新运行,您将看到以下输出(10 条记录)...
"2018-10-12T19:04:24.406567Z 4 查询 INSERT INTO my_table(id, name) VALUES ('d323d21e-25ac-40d4-8cff-7ad12f83b8c0', '1-apply-test'), ('f20e37f2 -35a4-41e9-8458-de405a44f4d9', '2-apply-test'), ('498f4e96-4bf1-4d69-a6cb-f0e61575ebb4', '3-apply-test'), ('8bf7925d-8f01-494f-8f9f -c5b8c742beae', '4-apply-test'), ('5ea663e7-d9bc-4c9f-a9a2-edbedf3e5415', '5-apply-test'), ('48f535c8-44e6-4f10-9af9-1562081538e5', '6 -apply-test'), ('fbf2661f-3a23-4317-ab1f-96978b39fffe', '7-apply-test'), ('3d781e25-3f30-48fd-b22b-91f0db8ba401', '8-apply-test') , ('55ffa950-c941-44dc-a233-ebecfd4413cf', '9-apply-test'), ('6edc6e25-6e70-42b9-8473-6ab68d065d44', '10-apply-test')"
所有 10 条记录都在同一个查询中
【问题讨论】:
请发minimal reproducible example。 您应该尝试 JDBC 的批处理语法,它允许您使用静态插入语句,您可以以迭代方式重用该语句。 This thread 有更多信息,还有关于优化参数的信息。 @MarkRotteveel 添加了详细信息 @MickMnemonic 我发布了批处理语法,我认为它是正确的。也重写了BatchedStatements。后一个示例演示了在不使用 BLOB 时批量插入按预期工作 您使用的是 MySQL 还是使用 MariaDB?您使用的是哪个 JDBC 驱动程序(+ 版本)? 【参考方案1】:我一直在修补,直到找到解决方法...
val ps = conn.prepareStatement(
"INSERT INTO my_table(id, name, data) VALUES (?, ?, ?)")
records.grouped(1000).foreach group =>
group.foreach r =>
ps.setString(1, UUID.randomUUID.toString)
ps.setString(2, r.name)
//ps.setBlob(3, new MariaDbBlob(r.data))
ps.setBytes(r.data)
ps.addBatch()
ps.executeBatch()
使用PreparedStatement.setBytes
而不是使用MariaDbBlob
似乎可以解决问题
【讨论】:
以上是关于带有 BLOB 列的 MySQL 5.7 批量插入的主要内容,如果未能解决你的问题,请参考以下文章
MyBatis 批量插入包含 BLOB 类型的数据到 Oracle 异常问题分析
Java:如何使用用于 Sql Server 的 java jdbc 执行带有标识列的批量插入