0

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

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 删除了批处理数据)。

4

0 回答 0