Java用JDBC批处理插入

本文介绍了如何使用Java JDBC API进行高效批量数据插入的方法。通过对比简单的逐条插入和使用批处理的方式,展示了如何利用Statement和PreparedStatement进行批量插入,同时讨论了SQL注入的风险及解决方案,并提出了一种分批提交的大数据量插入策略。
 让我们看看如何使用JDBC API在Java中执行批量插入。虽然你可能已经知道,但我会尽力解释基础到复杂的场景。
 
在此笔记里,我们将看到我们如何可以使用像Statement和PreparedStatement JDBC API来批量在任何数据库中插入数据。此外,我们将努力探索一些场景,如在内存不足时正常运行,以及如何优化批量操作。
 
首先,使用Java JDBC基本的API批量插入数据到数据库中。
 

Simple Batch - 简单批处理

 我把它叫做简单批处理。要求很简单,执行批量插入列表,而不是为每个INSERT语句每次提交数据库,我们将使用JDBC批处理操作和优化性能。

 
想想一下下面的代码:

Bad Code

 

String [] queries = {

    "insert into employee (name, city, phone) values ('A', 'X', '123')",

    "insert into employee (name, city, phone) values ('B', 'Y', '234')",

    "insert into employee (name, city, phone) values ('C', 'Z', '345')",

};

 

Connection connection = new getConnection();

Statement statemenet = connection.createStatement();

 

for (String query : queries) {

    statemenet.execute(query);

}

statemenet.close();

connection.close();

 

 这是糟糕的代码。它单独执行每个查询,每个INSERT语句的都提交一次数据库。考虑一下,如果你要插入1000条记录呢?这是不是一个好主意。

 

下面是执行批量插入的基本代码。来看看:

 

Good Code

 

Connection connection = new getConnection();

Statement statemenet = connection.createStatement();

 

for (String query : queries) {

    statemenet.addBatch(query);

}

statemenet.executeBatch();

statemenet.close();

connection.close();

 

请注意我们如何使用addBatch()方法,而不是直接执行查询。然后,加入所有的查询,我们使用statement.executeBatch()方法一次执行他们。没有什么花哨,只是一个简单的批量插入。

 

请注意,我们已经从一个String数组构建了查询。现在,你可能会想,使其动态化。例如:

  

import java.sql.Connection;

import java.sql.Statement;

 

//...

 

Connection connection = new getConnection();

Statement statemenet = connection.createStatement();

 

for (Employee employee: employees) {

    String query = "insert into employee (name, city) values('"

            + employee.getName() + "','" + employee.getCity + "')";

    statemenet.addBatch(query);

}

statemenet.executeBatch();

statemenet.close();

connection.close();

  

 请注意我们是如何从Employee对象中的数据动态创建查询并在批处理中添加,插入一气呵成。完美!是不是?

 等等......你必须思考什么关于SQL注入?这样动态创建的查询SQL注入是很容易的。并且每个插入查询每次都被编译。

 为什么不使用PreparedStatement而不是简单的声明。是的,这是个解决方案。下面是SQL注入安全批处理。

 

SQL Injection Safe Batch - SQL注入安全批处理

 

思考一下下面代码:

 

import java.sql.Connection;

 

import java.sql.PreparedStatement;

 

 

 

//...

 

 

 

String sql = "insert into employee (name, city, phone) values (?, ?, ?)";

 

Connection connection = new getConnection();

 

PreparedStatement ps = connection.prepareStatement(sql);

 

 

 

for (Employee employee: employees) {

 

    ps.setString(1, employee.getName());

    ps.setString(2, employee.getCity());

    ps.setString(3, employee.getPhone());

    ps.addBatch();

}

ps.executeBatch();

ps.close();

connection.close();

 

 

 

 

 

 

看看上面的代码。漂亮。我们使用的java.sql.PreparedStatement和在批处理中添加INSERT查询。这是你必须实现批量插入逻辑的解决方案,而不是上述Statement那个


这一解决方案仍然存在一个问题。考虑这样一个场景,在您想要插入到数据库使用批处理半万条记录。嗯,可能产生的OutOfMemoryError:

 

java.lang.OutOfMemoryError: Java heap space

    com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)

    com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)

    org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)

 

这是因为你试图在一个批次添加所有语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案

  

Smart Insert: Batch within Batch - 智能插入:将整批分批

 

这是一个简单的解决方案。考虑批量大小为1000,每1000个查询语句为一批插入提交。

 

String sql = "insert into employee (name, city, phone) values (?, ?, ?)";

 

Connection connection = new getConnection();

 

PreparedStatement ps = connection.prepareStatement(sql);

 

 

 

final int batchSize = 1000;

 

int count = 0;

 

 

 

for (Employee employee: employees) {

 

 

 

    ps.setString(1, employee.getName());

    ps.setString(2, employee.getCity());

    ps.setString(3, employee.getPhone());

    ps.addBatch();

 

    if(++count % batchSize == 0) {

        ps.executeBatch();

    }

}

ps.executeBatch(); // insert remaining records

ps.close();

connection.close();

 

 

 

 

 

这才是理想的解决方案,它避免了SQL注入和内存不足的问题。看看我们如何递增计数器计数,一旦BATCHSIZE 达到 1000,我们调用executeBatch()提交。

03-08
### MathPix工具介绍 Mathpix Snipping Tool 是一款强大的数学公式识别工具,从最初的原型发展至今已经历了多次迭代和功能增强[^1]。该工具不仅能处理简单的数学表达式,还可以应对复杂的数学模型以及多行公式,并且支持手写公式的识别。 这款应用程序通过不断的科技创新与用户反馈改进,在学术研究和技术领域赢得了良好声誉,成为许多科研人员不可或缺的工作伙伴之一。除了基本的功能外,Mathpix 还提供了多种高级特性来满足不同用户的特定需求。 ### 使用方法 #### 安装与启动 为了使用 Mathpix Snipping Tool ,首先需要下载安装程序并按照提示完成设置过程。一旦成功安装后即可随时调用此应用来进行截图操作。 #### 截取屏幕上的公式图像 当遇到想要转换成 LaTeX 或 AsciiMath 的图片时,只需打开软件界面按下快捷键(默认为 `Ctrl+Alt+M`),此时鼠标指针会变为十字形状以便于选取目标区域;框选所需部分之后松开按键即刻上传至云端服务器等待进一步分析处理。 #### 获取LaTeX代码片段 经过短暂几秒钟的时间延迟过后,所截获的内容将以纯文本形式显示出来供复制粘贴到其他编辑器当中继续编写文档或是分享给他人查看交流之用。 ```python import pyperclip # 假设已获取到LaTeX字符串 stored_in_variable named latex_code pyperclip.copy(latex_code) print("LaTeX code has been copied to clipboard.") ``` 对于希望深入探索更多可能性的用户来说,可以考虑查阅官方提供的扩展插件——如用于解析Markdown文件内的公式标记语法的库 **mathpix-markdown-it** [^2] ——这将进一步提升工作效率和个人体验感。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值