我有一个数据库,有些人和服务同时用它来更新个人数据。
因此有可能一个人更新一行并忘记提交。稍后更新服务总是想要更新此行并且服务挂起,直到提交或会话将被关闭。这可能需要一些时间,而更新服务无法完成其工作。
我可以确定这种情况吗? 更新服务可能会发送如下语句:
UPDATE person
SET email_address = 'new.email@company.com' WHERE person_id='1234567'
ON LOCKED ERROR;
如果此行有锁定,则此语句应该出错。
或者我可以配置oracle服务器在定义的时间后发送错误代码,如果一行上的锁没有完成?
感谢您的帮助。
答案 0 :(得分:3)
一个人更新一行并忘记提交。稍后更新服务总是想要更新此行并且服务挂起,直到提交或会话将被关闭
理想情况下,读者不会阻止作者,作者也不会阻止读者。
您所描述的是不 DEADLOCK 方案。当会话执行更新时,它会获取行级别独占锁,而其他会话尝试更新这些行,需要等到COMMIT / ROLLBACK释放锁。
当两个或多个会话相互等待锁定时发生死锁。
或者我可以配置oracle服务器在定义的时间后发送错误代码,如果一行上的锁没有完成?
要检查阻止会话和等待课程,您可以查询 v $ session 视图:
select sid,
status,
program,
sql_id,
state,
wait_class,
blocking_session_status,
event
from v$session;
当遇到死锁时, Oracle自动检测到死锁,抛出ORA-00060:在等待资源时检测到死锁,并回滚Oracle确定为死锁的死锁中涉及的一个事务受害者。以前成功的事务不会回滚。即使在死锁错误之后,如果发出提交,也会提交先前成功的事务。此时,其他会话的事务也将成功,您可以发出提交。您无需在此明确执行任何操作。死锁会自动清除 - 您永远不需要清除它们。
查看我在此处回答的类似问题https://stackoverflow.com/a/28455397/3989608
有关死锁的详细演示和示例,请参阅Understanding Oracle Deadlock
如果您使用 FOR UPDATE NOWAIT ,则Oracle不会让您更新这些行并抛出以下错误:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
例如,
第1节:
SQL> SELECT empno, deptno
2 FROM emp WHERE
3 deptno = 10
4 FOR UPDATE NOWAIT;
EMPNO DEPTNO
---------- ----------
7782 10
7839 10
7934 10
SQL>
第2节:
SQL> SELECT empno, deptno
2 FROM emp WHERE
3 deptno in (10, 20)
4 FOR UPDATE NOWAIT;
FROM emp WHERE
*
ERROR at line 2:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
更进一步,如果您想避免更新已锁定的行,可以使用 FOR UPDATE SKIP LOCKED 子句来避免其他会话被提取要更新的行已经锁定。
例如,
第1节:
SQL> SELECT empno, deptno
2 FROM emp WHERE
3 deptno = 10
4 FOR UPDATE NOWAIT;
EMPNO DEPTNO
---------- ----------
7782 10
7839 10
7934 10
SQL>
第2节:
SQL> SELECT empno, deptno
2 FROM emp WHERE
3 deptno in (10, 20)
4 FOR UPDATE NOWAIT;
FROM emp WHERE
*
ERROR at line 2:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
现在让我们跳过会话1锁定的行。
SQL> SELECT empno, deptno
2 FROM emp WHERE
3 deptno IN (10, 20)
4 FOR UPDATE SKIP LOCKED;
EMPNO DEPTNO
---------- ----------
7369 20
7566 20
7788 20
7876 20
7902 20
SQL>
因此,部门= 10被会话1锁定,然后部门= 20被会话2锁定。
请参阅有关避免已锁定行Oracle deadlock keeps repeating on the same record
上的更新的类似问题答案 1 :(得分:2)
你可以分两个阶段完成;使用circle.setPosition(ol.proj.transform([GPS_lon, GPS_lat], 'EPSG:4326', 'EPSG:3857'));
查询表,如果该行已被锁定则会抛出异常,如果没有错误则执行更新(和提交):
FOR UPDATE NOWAIT
如果你是从两个会话那样做,没有提交,那么运行select的第二个会看到:
ORA-00054:资源繁忙,并在指定NOWAIT或超时过期时获取
您还可以使用SELECT * FROM person WHERE person_id = 1234567 FOR UPDATE NOWAIT;
UPDATE person SET email_address = 'new.email@company.com' WHERE person_id='1234567';
超时:
WAIT <time>
在这种情况下,如果第一个没有在3秒内提交/回滚,第二个调用者将收到错误:
ORA-30006:资源繁忙;获取WAIT超时已到期
如果您通过JDBC或OCI等方式调用此方法,则可能需要在同一会话中进行单独的背对背呼叫,并且如果第一次呼叫处理异常,则需要抛出。