Oracle 数据库 SELECT... FOR UPDATE 与自动提交
Posted
技术标签:
【中文标题】Oracle 数据库 SELECT... FOR UPDATE 与自动提交【英文标题】:Oracle database SELECT... FOR UPDATE with autocommit on 【发布时间】:2015-03-26 23:20:44 【问题描述】:我正在针对 Oracle 数据库 (11g) 运行此查询。该连接具有自动提交的默认值,即“true”。
Connection con = driver.connect(url, properties);
String query = "SELECT EMPID, NAME FROM EMPLOYEE FOR UPDATE";
Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = statement.executeQuery(query);
SELECT... FOR UPDATE 声明它“锁定选定的行,以便其他用户在您结束事务之前无法锁定或更新这些行。”使用自动提交应该在查询执行后立即执行。但是锁一直存在,直到连接关闭。
(我通过在 sqlplus 上运行查询 select * FROM DBA_DML_LOCKS WHERE NAME = 'EMPLOYEE';
进行了检查。)
这是一个错误还是有人可以解释原因吗? 提前谢谢你。
【问题讨论】:
附言。在关闭自动提交的情况下手动管理事务时,查询按预期工作 当你不更新任何东西时,为什么要使用“FOR UPDATE”? 我更新了!并使用resultSet.updateRow()
,但锁会一直保留到连接关闭为止。这是有问题的
【参考方案1】:
如documentation中所说:
默认是在 SQL 语句完成时提交,而不是在执行时提交。当检索到所有结果集和更新计数时,语句完成。然而,在几乎所有情况下,语句都会在执行后立即完成并提交
另一个documentation:
启用自动提交可能更方便,但控制权更少。例如,您没有回滚更改的选项。此外,某些 SQLJ 或 JDBC 功能与自动提交模式不兼容。例如,您必须禁用自动提交标志以进行更新批处理或 SELECT FOR UPDATE 语法才能正常工作。
所以对于这种查询类型,您应该使用手动提交
【讨论】:
即使在执行resultSet.updateRow()
之后,锁仍然存在。抱歉,我的测试用例出错,我更新了问题
执行resultSet.cancelRowUpdates()
或关闭resultSet时,锁不会被释放
谢谢。我实际上正在实现一个连接池,因此我不知道会运行什么查询。所以我想管理事务或自动提交应该是用户的责任。【参考方案2】:
我找到了这个文档。
FOR UPDATE clause 它说:使用 FOR UPDATE 子句对于获得可更新的 JDBC ResultSet 不是强制性的。只要用于生成 JDBC ResultSet 的语句满足可更新游标的要求,生成 JDBC ResultSet 的 JDBC Statement 具有并发模式 ResultSet.CONCUR_UPDATABLE 即可使 ResultSet 可更新。 p>
还有这个:Requirements for updatable cursors and updatable ResultSets
我假设您可以跳过 FOR UPDATE
子句。
【讨论】:
我的实际要求是找出它为什么不起作用而不是运行特定的查询(正如我在接受的答案中评论的那样)。不过谢谢,这是我以前不知道的事【参考方案3】:请参阅此常见问题解答。使用 FOR UPDATE 时应关闭 AutoCommit。 http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#30_06
【讨论】:
【参考方案4】:正如setAutoComit documentation 所说:
语句完成时发生提交。的时间 语句完成取决于 SQL 语句的类型: - 对于 DML 语句,例如 Insert、Update 或 Delete,以及 DDL 语句,语句一完成即完成 执行。 - 对于 Select 语句,当关联的结果集关闭时,该语句就完成了。 - 对于 CallableStatement 对象或返回多个结果的语句,当所有关联的语句完成时 结果集已关闭,所有更新计数和输出 参数已检索。
因此,在您的情况下,锁定将一直存在,直到您明确使用 ResultSet.close() 关闭 ResultSet 或 ResultSet 自动关闭(有关详细信息,请参阅 ResultSet.close())。
是的,当您说“管理事务或自动提交应该是用户的责任”时,您是对的。
【讨论】:
以上是关于Oracle 数据库 SELECT... FOR UPDATE 与自动提交的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们在 Oracle SQL 中需要 SELECT FOR UPDATE?
Oracle编辑数据时提示:这些查询结果不可更新,请使用ROWI或者SELECT……FOR UPDATE获得可更新结果
在 SQL Server 中,如何以类似于 Oracle 的“SELECT FOR UPDATE WAIT”的方式锁定单行?