addBatch使用方法

本文详细介绍了在Java中使用PreparedStatement替代Statement的方法,通过预编译SQL语句,不仅提高了代码的可读性和可维护性,还显著提升了执行效率,并增强了数据库操作的安全性。
  1. 建立链接

Connection connection =getConnection();

  1. 去掉自动提交功能 Commit

connection.setAutoCommit(false);

  1. 预编译SQL语句,只编译一回哦,效率高啊。
PreparedStatement statement = connection.prepareStatement("INSERT INTO TABLEX VALUES(?, ?)");
  1. 注备语句
//记录1
statement.setInt(1, 1); 
statement.setString(2, "Cujo"); 
statement.addBatch(); 
//记录2
statement.setInt(1, 2); 
statement.setString(2, "Fred"); 
statement.addBatch(); 
//记录3
statement.setInt(1, 3); 
statement.setString(2, "Mark"); 
statement.addBatch(); 
复制代码
复制代码
5. 批量执行上面3条语句

int [] counts = statement.executeBatch(); 
//Commit it 咽下去,到肚子(DB)里面
connection.commit();

二、使用PreparedStatement的好处:

1、代码的可读性和可维护性:

虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说,都比直接用Statement的代码高很多档次:

第一种方法

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");//stmt是Statement对象实例

–第二种方法

perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate(); //prestmt是 PreparedStatement 对象实例

一看便知,对于第一种方法,别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心。

2、PreparedStatement尽最大可能提高性能:

语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(这相当于一个涵数)就会得到执行。这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配,那么在任何时候就可以不需要再次编译而可以直接执行。

而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配。比如:

insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');

即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义。事实是没有数据库会对普通语句编译后的执行代码缓存。

(当然并不是所有的预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果,以保存有更多的空间存储新的预编译语句。)

3、最重要的一点是提高了安全性:

可能到目前为止,仍有一些人连基本的恶义SQL语法都不知道:

String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";

如果我们把[’ or ‘1’ = '1]作为varpasswd传入进来.用户名随意,看看会成为什么?

select * from tb_name = ‘随意’ and passwd = ‘’ or ‘1’ = ‘1’;
因为’1’=‘1’肯定成立,所以可以任何通过验证。这算比较委婉的,更有甚者把[’;drop table tb_name;]作为varpasswd传入进来… 关于数据安全方面的内容这里就不做展开讨论了,总之使用PreparedStatement让执行的SQL更安全。

### JDBC 批量插入时未调用 `clearBatch` 的影响及正确用法 在 JDBC 批量操作中,`addBatch()` 方法用于将 SQL 语句添加到批处理队列中,而 `executeBatch()` 方法则用于执行这些批量的 SQL 语句。`clearBatch()` 方法的作用是清空当前批处理队列中的所有 SQL 语句[^1]。如果在使用 `addBatch()` 后未调用 `clearBatch()`,可能会产生以下影响: #### 1. 内存占用问题 如果未调用 `clearBatch()`,批处理队列中的 SQL 语句将一直保留,直到下一次调用 `executeBatch()` 或连接关闭。这可能导致内存占用逐渐增加,尤其是在循环中反复调用 `addBatch()` 但未清理的情况下[^3]。例如,在一个大规模的数据插入场景中,如果不清理批处理队列,程序可能因内存不足而崩溃。 #### 2. 数据一致性问题 在事务管理中,如果未调用 `clearBatch()`,可能会导致批处理队列中的 SQL 语句在事务提交后仍然存在,从而引发不必要的重复执行或数据不一致问题[^4]。例如,当事务回滚后,批处理队列中的 SQL 语句并未被清除,下次执行时可能会重新插入相同的数据。 #### 3. 性能下降 未调用 `clearBatch()` 可能导致批处理队列中积累过多的 SQL 语句,从而降低性能。每次调用 `executeBatch()` 时,数据库需要处理整个批处理队列中的所有语句,如果队列过大,执行时间会显著增加[^3]。 --- ### 正确用法 为了确保批处理操作的高效性和安全性,应遵循以下正确用法: #### 1. 在适当的时间点调用 `executeBatch()` 在批量插入时,应在适当的间隔调用 `executeBatch()` 来执行批处理队列中的 SQL 语句。例如,可以每 1000 条记录执行一次批量操作,以平衡内存占用和性能[^3]。 ```java for (int i = 1; i <= 10000; i++) { stat.addBatch("insert into stu values(" + i + ",'张三',25,'男');"); if (i % 1000 == 0) { int[] result = stat.executeBatch(); System.out.println("Executed batch: " + result.length); stat.clearBatch(); // 清理批处理队列 } } ``` #### 2. 调用 `clearBatch()` 清理批处理队列 在每次调用 `executeBatch()` 后,建议立即调用 `clearBatch()` 来清空批处理队列。这样可以避免内存泄漏和不必要的重复执行[^1]。 #### 3. 管理事务提交 在批量插入时,通常需要手动管理事务。可以通过设置 `conn.setAutoCommit(false)` 来禁用自动提交,并在所有 SQL 语句加载完毕后调用 `conn.commit()` 提交事务[^4]。 ```java Connection conn = DbUtils.getConnection(); try { conn.setAutoCommit(false); // 禁用自动提交 PreparedStatement pstmt = conn.prepareStatement("INSERT INTO stu (id, name, age, gender) VALUES (?, ?, ?, ?)"); for (int i = 1; i <= 10000; i++) { pstmt.setInt(1, i); pstmt.setString(2, "张三"); pstmt.setInt(3, 25); pstmt.setString(4, "男"); pstmt.addBatch(); if (i % 1000 == 0) { pstmt.executeBatch(); pstmt.clearBatch(); } } pstmt.executeBatch(); // 执行剩余的批处理 conn.commit(); // 提交事务 } catch (SQLException e) { conn.rollback(); // 回滚事务 e.printStackTrace(); } finally { conn.close(); } ``` --- ### 注意事项 - **SQL 注入问题**:在使用 `addBatch()` 时,如果直接拼接 SQL 字符串,可能会导致 SQL 注入风险。建议使用 `PreparedStatement` 来绑定参数,从而避免此类问题[^1]。 - **异常处理**:在执行批处理时,应捕获可能的异常并进行适当的处理,例如回滚事务或记录错误日志[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值