如何在Java应用程序中设置锁定模式

伊萨斯:

我正在使用Weblogic连接到Informix数据库的Java Web应用程序上工作。在应用程序中,我们有多个线程在一个表中创建记录。

它经常发生失败,并引发以下错误:

java.sql.SQLException: Could not do a physical-order read to fetch next row....
Caused by: java.sql.SQLException: ISAM error: record is locked.

我假设当记录被锁定时,两个线程都试图插入或更新。

我进行了一些研究,发现有一个选项可以设置数据库,而不是抛出错误,而是应该等待锁被释放。

SET LOCK MODE TO WAIT;
SET LOCK MODE TO WAIT 17;

我认为JDBC中没有使用该设置的选项。如何在Java Web应用程序中使用此设置?

rzwitserloot:

您始终可以直接使用来直接发送该SQL createStatement(),然后发送该确切的SQL。

解决此问题的更“普通” /现代方法是MVCC,事务级别“ SERIALIZABLE”,重试和随机退避的组合。

不过,我不知道Informix是否接近该高级产品。诸如Postgres之类的现代数据库(出于MVCC /可序列化/重试/退避以及事务安全性的考虑,mysql不算是现代数据库)。

在原始JDBC中执行MVCC / Serializable / Retry / Backoff非常复杂;使用JDBI或JOOQ之类的库。

MVCC:一种机制,事务是基础数据的浅表克隆。2个独立的事务可以读取和写入同一表中的相同记录,而不会互相干扰。在提交事务之前,事情不会“保存”。

SERIALIZABLE:事务级别(也称为隔离级别),可通过以下方式设置jdbcDbObj.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);-最安全的水平。如果您知道版本控制系统是如何工作的:您正在要求数据库积极地对所有内容进行基础调整,以便将整个提交链按单个长事件进行排序:每个事务的行为就像在完成上一个事务之后一样。实现此级别的最简单方法是全局锁定所有内容。当然,这对多线程性能非常不利。实际上,好的DB引擎(例如postgres)比这更聪明:多个线程可以同时运行事务,而不仅仅是被冻结和等待锁;DB引擎改为检查事务所做的事情(不仅是写入,还要读取)是否与同步事务无冲突。如果是,则全部允许。如果不,除了一个并发事务之外的所有事务都抛出重试异常。这是使您可以安全地执行此事件序列的唯一级别:

  1. 提取isaace的银行帐户余额。
  2. 提取rzwitserloot的银行帐户余额。
  3. 从isaace的数字中减去€10,-如果余额不足则失败。
  4. 在rzwitserloot的号码上加上10欧元。
  5. 将isaace的新余额写入数据库。
  6. 将rzwitserloot的新余额写入数据库。
  7. 提交交易。

任何低于SERIALIZABLE的级别都将默默地使工作失败;如果多个线程同时执行上述操作,则不会发生SQLException,但是isaace和rzwitserloot的余额之和将随时间而变化(金钱丢失或创建-在步骤1和2与步骤5/6/7之间,另一个线程集新余额,但这些新余额由于5/6/7中的更新而丢失)。使用可序列化,这不可能发生。

重试:智能数据库解决问题的方法是通过失败(带有“重试”错误)除一个事务以外的所有事务,检查整个事务完成的所有SELECT是否不受此后提交给数据库的任何事务的影响此交易已打开。如果答案是肯定的(某些选择会有所不同),则事务失败。该错误的要点是告诉运行事务的代码从顶部开始,然后再执行一次。这次很可能不会发生冲突,它会起作用。假设可以发生冲突,但通常不会发生冲突,因此最好假设“天气晴朗”(没有锁,只做你的东西),事后检查,然后在发生冲突的特殊情况下重试,而不是尝试锁定行和表。请注意,例如,以太网的工作方式相同(假设天气晴朗,事后恢复错误)。

退避:重试的一个问题是计算机过于一致:如果2个线程相互干扰,它们都可能会失败,都将再次尝试,只是永远再次失败。解决方案是,线程在任意时间扭曲它们的拇指,以确保在某个时候两个冲突的重访者之一“获胜”。

换句话说,如果您想“正确”(请参阅​​银行帐户示例),但又要相对“快速”(不全局锁定),则可以使用DB,并使用JDBI或JOOQ;否则,您将必须编写代码以在lambda块中运行所有数据库内容,捕获SQLException,检查SqlState以查看是否指示您应重试(sqlstate代码是数据库引擎特定的),如果是,在等待成倍增加的时间(还包括一个随机因素)之后,重新运行该lambda。那是相当复杂的,这就是为什么我强烈建议您依靠JOOQ或JDBI为您解决这一问题的原因。

如果您尚未准备好使用该级别的数据库,则只需声明并发送“ SET LOCK MDOE TO WAIT 17;”即可。在打开任何连接开始时,SQL语句会一直向上。如果使用连接池,通常可以在一个地方配置SQL语句以在连接启动时运行。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在Eclipse中设置Gradle Java应用程序?

如何在Java中为应用程序锁定Redis集群

如何在android studio中以编程方式在最近的应用程序中锁定应用程序

如何在我设备的所有应用程序上应用模式锁定?

如何在OS X中为每个应用程序设置输入模式

如何在iPhone Web应用程序中将方向锁定为纵向模式?

如果使用应用程序工厂模式,如何在gunicorn中运行flask应用程序?

如何在Java Hibernate中的整个应用程序中设置FetchSize

如何在Android中设置应用程序范围的字体?

如何在我的应用程序中设置twilio

如何在Swing中全局设置应用程序的图标?

如何在golang中设置应用程序图标?

如何在通用应用程序中设置窗口的大小?

如何在WinJS应用程序的Backgrounduploader中设置ServerCredential

如何在Soap应用程序中设置TXSDateTime

如何在离子应用程序中设置setCancelable(false)?

如何在离子应用程序中设置默认图像

如何在Web应用程序中设置用户代理?

如何在应用程序设置中存储图像路径?

如何在Android应用程序中设置语言环境?

如何在android应用程序中实现语言设置?

如何在角度应用程序中设置基本 Href?

如何在Java EE 7应用程序中设置上下文根

如何在Java Web应用程序中动态设置会话超时?

如何在简单的Java应用程序中设置quartz.config文件?

如何在Java应用程序中设置JVM时间(不是操作系统时间)?

如何在iPhone应用程序中设置应用程序图标

如何在 PySpark 应用程序中设置纱线应用程序 ID

如何在Ubuntu Touch应用程序的.desktop文件中设置应用程序图标?