java - 如何防止MySQL InnoDB通过JDBC为delete语句设置锁

标签 java mysql multithreading jdbc innodb

我有一个多线程客户端/服务器系统,其中有数千个客户端不断向存储在特定表中的服务器发送数据。此数据仅在几天内很重要,因此之后会被删除。

服务器是用J2SE写的,数据库是MySQL,我的表用的是InnoDB引擎。它包含数百万个条目(并根据使用情况正确编入索引)。

一个预定的线程每天运行一次 以删除旧条目。该线程可能需要很长时间才能删除,因为要删除的行数可能非常大(几百万行)。 在我的特定系统上,删除 250 万行大约需要 3 分钟。

插入线程(和读取线程)收到超时错误告诉我

Lock wait timeout exceeded; try restarting transaction

  1. 我怎样才能简单地从我的 Java 代码中获取该状态?我宁愿自己处理情况,也不愿等待。但更重要的是,如何避免这种情况?
  2. 我可以用吗

    conn.setIsolationLevel( Connection.TRANSACTION_READ_UNCOMMITTED )
    

    对于阅读线程,他们将获得他们的信息,而不管它当前是否最准确(这对于这个用例来说绝对可以)?

  3. 如何处理我的插入线程以防止阻塞?他们纯粹将数据插入表中(主键是元组 useridservertimemillis)。
  4. 我应该更改我的删除线程吗?它纯粹是删除元组 userid 的数据,大于 specialtimestamp

编辑:

阅读 MySQL documentation 时,我想知道我是否不能简单地定义用于插入和删除行的连接

conn.setIsolationLevel( Connection.TRANSACTION_READ_COMMITTED )

并实现我所需要的。它说 UPDATE- 和 DELETE 语句,使用具有唯一搜索模式的唯一索引只锁定匹配的索引条目,但不是之前的间隙,并且仍然可以将行插入该间隙.如果你能获得这方面的经验会很棒,因为我不能简单地在生产环境中尝试它——而且在测试环境中模拟它需要付出很大的努力。

最佳答案

尝试在您的删除线程中首先加载要删除的记录的 ID,然后一次删除一个,在每次删除后提交。

如果您每天运行一次执行大量删除的线程并且需要 3 分钟,您可以将其拆分为删除少量记录的较小事务,并且仍然设法足够快地完成它。

更好的解决方案:

首先。您尝试的任何解决方案都必须在部署到生产环境之前进行测试。特别是某个随机网站上某个随机人建议的解决方案。

现在,这是我建议的解决方案(对您的表结构和索引做出一些假设,因为您没有指定它们):

  1. 改变你的 table 。不建议在 InnoDB 中使用多列的主键,尤其是在大表中(因为主键自动包含在任何其他索引中)。查看 this question 的答案出于更多原因。您应该添加一些唯一的 RecordID 列作为主键(我建议使用长标识符,或者在 MySQL 中使用 BIGINT)。

  2. 选择要删除的行 - 执行“SELECT RecordID FROM YourTable where ServerTimeMillis < ?”。

  3. 提交(以释放对 ServerTimeMillis 索引的锁定,我假设您已快速锁定)

  4. 对于每个 RecordID,执行“DELETE FROM YourTable WHERE RecordID = ?”

  5. 在每条记录之后或每 X 条记录之后提交(我不确定这是否会有很大不同)。也许在 DELETE 命令末尾进行一次提交就足够了,因为根据我建议的新逻辑,应该只锁定已删除的行。

至于改变隔离级别。我不认为你必须这样做。我不能建议你能不能做,因为我不知道你的服务器的逻辑,也不知道这样的改变会如何影响它。

关于java - 如何防止MySQL InnoDB通过JDBC为delete语句设置锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20218100/

相关文章:

java - 我可以使用 java.util.Set 在 Java 中为 DFA 实现状态转换吗

java - 从二进制文件读取并将某些信息转换为字符串

MySQL SELECT 查询具有多个表的联结表

c - 条件变量的实现

c# - yield return 的线程安全性(是吗?)

java - Log4j2 没有像指定的那样格式化输出/appender 没有添加我认为

java - reCaptcha 在用 Google 验证时总是返回 false

mysql - 如何在sql中添加两个选择列的总和?

php - CakePHP - 使用 JOIN 有效地搜索 3 个表

java - 困惑的java ThreadPool和ReentrantLock