我正在使用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应用程序中使用此设置?
您始终可以直接使用来直接发送该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引擎改为检查事务所做的事情(不仅是写入,还要读取)是否与同步事务无冲突。如果是,则全部允许。如果不,除了一个并发事务之外的所有事务都抛出重试异常。这是使您可以安全地执行此事件序列的唯一级别:
任何低于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] 删除。
我来说两句