重试中止事务

在乐观并发控制(OCC)中,在COMMIT阶段前的事务期间(使用任何隔离级别)不会对记录进行锁定。这是一个能显著提高性能的强大优势。它的缺点是,如果另一个会话尝试更新相同的记录,则更新可能会失败。所以必须中止整个事务。这些所谓的更新冲突是由MOT在提交时通过版本检查机制检测到的。

重试中止事务 - 图1 说明: 使用悲观并发控制的引擎,如标准Postgres和openGauss基于磁盘的表,当使用SERIALIZABLE或REPEATABLE-READ隔离级别时,也会发生类似的异常中止。

这种更新冲突在常见的OLTP场景中非常少见,在使用MOT时尤其少见。但是,由于仍有可能发生这种情况,开发人员应该考虑使用事务重试代码来解决此问题。

下面以多个会话同时尝试更新同一个表为例,说明如何重试表命令。有关更多详细信息,请参阅“OCC与2PL的区别举例”部分。下面以TPC-C支付事务为例。

  1. int commitAborts = 0;
  2. while (commitAborts < RETRY_LIMIT) {
  3. try {
  4. stmt =db.stmtPaymentUpdateDistrict;
  5. stmt.setDouble(1, 100);
  6. stmt.setInt(2, 1);
  7. stmt.setInt(3, 1);
  8. stmt.executeUpdate();
  9. db.commit();
  10. break;
  11. }
  12. catch (SQLException se) {
  13. if(se != null && se.getMessage().contains("could not serialize access due to concurrent update")) {
  14. log.error("commmit abort = " + se.getMessage());
  15. commitAborts++;
  16. continue;
  17. }else {
  18. db.rollback();
  19. }
  20. break;
  21. }
  22. }