如何在Java中提交PreparedStatement的batchExecute时处理死锁

时间:2013-09-23 01:20:24

标签: java mysql transactions prepared-statement deadlock

代码从队列中获取数据,将其作为批处理添加到预准备语句中,执行批处理然后提交:

int counter = 0;
while (!this.dataQueue.isEmpty()
        && counter <= config.MAX_FLUSH_COUNT) {
    DataRecord record = this.dataQueue.poll();
    if (record.ip.length() > 40) {
        record.ip = record.ip.substring(0, 40);
    }
    try {
        this.dataFlush.setInt(1, record.uid);
        this.dataFlush.setInt(2, record.fid);
        this.dataFlush
                .setTimestamp(3, new Timestamp(record.time));
        this.dataFlush.setString(4, record.ip);
        this.dataFlush.addBatch();
    } catch (Exception ex) {
        Log.logError("Error building record: " + ex.getMessage());
    }
    counter++;
}
if (counter > 0) {
    try {
        this.dataFlush.executeBatch();
        this.dataFlush.getConnection().commit();
    } catch (SQLException ex) {
        Log.logError("Error executing flush: " + ex.getMessage());
    }
}

此刷新可能包含数千个条目(MAX_FLUSH_COUNT限制为每批2000个),因此有时会发生死锁(每8秒执行一次刷新,每5到6个小时就会发生一次死锁)。

编辑:这是我准备好的声明:

Connection conn = DBBase.getConnection();
conn.setAutoCommit(false);
this.snatchFlush = conn.prepareStatement("INSERT INTO slog (uid, fid, time, ip) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE fid=VALUES(fid), time=VALUES(time), ip=VALUES(ip)");

uid是此表的主键。 数据库引擎是InnoDB,没有外键,没有触发器。 该表可以由Web服务器以及此应用程序同时读取或写入,这是非常不可能但可能的。

我的第一个更改是将批次分成多个批次,并将其大小限制为200-500个数据集。

我现在的问题:当发生死锁时,通常的解决方案是重启事务。

这是否意味着我必须将数据重新添加到dataFlush Prepared Statement,executeBatch并再次提交?如果是,那就意味着我需要保存从队列中轮询的数据,否则会丢失。

有没有更好的解决方案不需要我保存轮询数据? (我假设一个简单的executeBatch并且catch-Block中的提交不起作用,因为executeBatch删除了批处理数据)。

0 个答案:

没有答案