La respuesta es que si no hacemos bien las cosas es SI. Vamos a verlo mejor con un ejemplo con las típicas tablas de formación que utiliza Oracle, DEPT y EMP:
CREATE TABLE dept (
deptno NUMBER(2) NOT NULL CONSTRAINT dept_pk PRIMARY KEY,
dname VARCHAR2(14),
loc VARCHAR2(13));
CREATE TABLE emp (
empno NUMBER(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2) CONSTRAINT emp_ref_dept_fk
REFERENCES dept(deptno));
Insertamos un departamento:
INSERT INTO dept (deptno, dname, loc)
VALUES (23, 'CONTABILIDAD', 'VIGO');
COMMIT;
Ahora insertamos un empleado:
INSERT INTO emp (empno,ename,job,mgr,
hiredate,
sal,comm,deptno)
VALUES (1234, 'MARIOBROS', 'FONTA', 10,
TO_DATE('16/05/1975', 'DD/MM/YYYY'),
50000, 2000, 23);
Antes de hacer el commit, al ver los bloqueos veremos que están la tabla EMP y la DEPT bloqueadas.
SELECT lk.sid, lk.TYPE lock_type, lk.lmode,
(SELECT o.object_name
FROM dba_objects o
WHERE o.object_id = lk.id1) object_name
FROM gv$lock lk
WHERE lk.TYPE IN ('TM', 'UL');
Lo que nos devolverá será esto:
SID LO LMODE OBJECT_NAME
------ -- --------- ----------------
311 TM 3 EMP
311 TM 3 DEPT
El bloqueo de la tabla EMP es por el registro que acabamos de insertar pero que todavía no está commitado, pero la tabla DEPT se bloquea por la clave foránea, ya que en el momento de insertar el registro en EMP existía el departamento 23 en DEPT, pero como no hemos comitado el insert en EMP tiene que bloquear el registro del departamento 23 para evitar que otra sesión borre ese registro o modifique el código del departamento.
Hasta aquí todo normal, el problema viene cuando otra sesión quiere modificar el nombre del departamento:
UPDATE dept
SET dname = 'FINANCIERO'
WHERE deptno = 23;
Con esta update nos dejará modificarlo sin problema, pero si en vez de hacer un update que únicamente modifica el nombre del departamento hacemos este otro (el resultado final de los datos en la tabla serán los mismos):
UPDATE dept
SET deptno = 23,
dname = 'FINANCIERO',
loc = 'VIGO'
WHERE deptno = 23;
El registro quedaría con los mismos datos, pero ya tenemos el bloqueo montado ya que le estamos diciendo que actualice el campo DEPTNO, pero la modificación de ese campo afectaría a registros introducidos por otra sesión y que todavía no están comitados, por lo que se quedará bloqueado.
Esta es la explicación del motivo, pero ¿porqué ocurre en Forms?. La respuesta la encontramos en la propiedad "Actualizar Sólo Columnas Cambiadas" a nivel de bloque, por defecto esa propiedad está a "No" con lo que para hacer un update actualizará todos los campos, incluso los que no ha modificado el usuario.
Lo recomendable para evitar bloqueos es poner esa propiedad al valor "Si".
5 comentarios:
Hola, acabo de encontrar tu blog, y precisamente la causa del problema del bloqueo inesperado/inexplicable en Forms que tengo es posible que sea por lo que comentas. Voy a probarlo, y si no se vuelve a producir, te debo un jamón.
Gracias por el post. un saludo
Gracias por el post. un saludo
Hola a mi no me funciono, como si no hubiera hecho nada :/
pero eso va de la mano, con la propiedad Locking Mode = Delayed a nivel de bloque
Publicar un comentario