JDBC PreparedStatement Batch continue insert on error
Posted
技术标签:
【中文标题】JDBC PreparedStatement Batch continue insert on error【英文标题】: 【发布时间】:2015-07-03 08:50:23 【问题描述】:你好,我在 java 中创建了一个带有 PreparedStatement
的批处理
for(Item item: list)
ps.setString(1, item.getSome());
ps.setString(2, item.getFoo());
ps.setString(3, item.getBatman());
statement.addBatch();
if (++count % batchSize == 0)
results = ps.executeBatch(); //execute parcial batch
if (results != null)
System.out.println(results.length);
results= ps.executeBatch(); //execute rest of batch
数据库服务器是 mysql,在表中插入我有几个限制
通过这些限制,当我插入时会产生错误
我想运行批处理并忽略错误,此时抛出一个异常结束批处理
在我创建批次之前,我有一个 Big 用于一一保存
//seudocode level
For item
Try
insert item
catch(E)nothing happens
但它很慢,在某些情况下,批量处理 4000 个项目,插入 1500 个并省略其余部分
如何处理批次?
编辑
我使用 weblogic 与这个驱动程序mysql-connector-java-commercial-5.0.3-bin
进行连接
我测试了这个属性
1.
continueBatchOnError=true
2.
rewriteBatchedStatements=true
3.
continueBatchOnError=true
rewriteBatchedStatements=true
并添加connection.setAutoCommit(false);
,但继续重复抛出异常
编辑
忘了说,我是用来连接Hibernate + Spring的
唯一的 For-Save 示例是在 Hibernate 中制作的,但为了提高性能,我尝试使用 JDBC Batch,在 webapp 的其他过程中也使用 JDBC 与 Hibernate 的连接并且效果很好
这是完整的代码
@Transactional
public void saveMany(final List<Item> items)
getMySqlSession().doWork(new Work()
@Override
public void execute(Connection connection) throws SQLException
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO `FRT_DB`.`ITEM` ");
sb.append("( ");
sb.append("`masterID`, ");
sb.append("`agent`, ");
sb.append("`rangeID`) ");
sb.append("VALUES ");
sb.append("( ");
sb.append("?, ");
sb.append("?, ");
sb.append("?) ");
int[] results = null;
PreparedStatement ps = null;
try
connection.setAutoCommit(false);
ps = connection.prepareStatement(sb.toString());
final int batchSize = 250;
int count = 0;
for (Item item : items)
if (item.getMasterId() != null)
ps.setInt(1, item.getMasterId());
else
ps.setNull(1, java.sql.Types.INTEGER);
if (item.getAgent() != null)
ps.setString(2, item.getAgent());
else
ps.setNull(2, Types.VARCHAR);
if (item.getRangeId() != null)
ps.setInt(3, item.getRangeId());
else
ps.setNull(3, Types.INTEGER);
ps.addBatch();
if (++count % batchSize == 0)
results = ps.executeBatch();
if (results != null)
System.out.println(results.length);
results= ps.executeBatch();
catch (Exception e)
e.printStackTrace();
);
这会产生下一个异常
java.sql.BatchUpdateException: 重复条目 '1-000002725' 的键 '主ID'
但我需要继续
spring + hibernate 设置会干扰jdbc的属性吗?我不知道
【问题讨论】:
您使用的是“MySQL Connector/J”JDBC 驱动程序吗?如果是这样,默认行为应该是continueBatchOnError=true
,这似乎是你想要的。
@GordThompson 我使用 weblogic 进行连接,我添加属性 continueBatchOnError=true
并重新启动,但问题仍然存在,在第一次插入时抛出异常 ps.executeBatch();
稍后阅读此 SO post 并添加此 rewriteBatchedStatements=true
但是仍然是例外
【参考方案1】:
我觉得可以用一个词来概括IGNORE
当你用这个运行批处理时
sb.append("INSERT IGNORE INTO `FRT_DB`.`ITEM` ");
这个不会抛出异常,有约束,这个传递,你的行中仍然是旧数据
如果您需要保存为INSERT ... ON DUPLICATE KEY
语句更改的“新数据”,但是,现在认为不需要它。
在您的代码中不需要提交或回滚@Transactional
为您工作。
你的大 try
只在 SqlException 中崩溃,而不是在 BatchUpdateException 中
您只需要添加allowMultiQueries
,因为其他默认true
http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
【讨论】:
我正在使用 mssql,其中它们没有被忽略(说无效对象)。他们在 jdbcTemplate 中有任何选择吗?以上是关于JDBC PreparedStatement Batch continue insert on error的主要内容,如果未能解决你的问题,请参考以下文章
JDBC - 语句、PreparedStatement、CallableStatement 和缓存
JDBC封装学习笔记---面向对象的JDBC,使用preparedStatement
JDBC深入理解Statement和PreparedStatement