SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));
表已创建。
SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);
表已更改。
SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));
表已创建。
SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C
2 FOREIGN KEY (FID)
3 REFERENCES T_P (ID);
表已更改。
SQL> INSERT INTO T_P SELECT ROWNUM, TABLE_NAME FROM ALL_TABLES;
已创建884行。
SQL> INSERT INTO T_C SELECT ROWNUM, MOD(ROWNUM, 884) + 1, OBJECT_NAME
2 FROM ALL_OBJECTS;
已创建30339行。
SQL> COMMIT;
提交完成。
SQL> CREATE INDEX IND_T_C_FID ON T_C (FID);
索引已创建。
SQL> SELECT * FROM T_P WHERE IDSELECT * FROM T_C WHERE IDSET SQLP 'SQL2> '
SQL2> DELETE T_C WHERE ID = 2;
已删除 1 行。
删除了一条为2的子表级联,其对应的主表记录ID为3,下面尝试在第一个会话新增一条ID为1000的记录,然后删除这条记录:
SQL> INSERT INTO T_P VALUES (1000, 'A');
已创建 1 行。
SQL> DELETE T_P WHERE ID = 1000;
已删除 1 行。
SQL> ROLLBACK;
回退已完成。
可以看到,并没有发生锁表的情况,这是因为子表外键列上有索引,删除主表的记录时,只会锁定子表参考主表的对应记录。
会话二回滚:
SQL2> ROLLBACK;
回退已完成。
下面删除外键索引:
SQL> DROP INDEX IND_T_C_FID;
索引已删除。
重复刚才的操作,在另一个会话执行删除操作:
SQL2> DELETE T_C WHERE ID = 2;
已删除 1 行。
在会话一重复插入和删除操作:
SQL> INSERT INTO T_P VALUES (1000, 'A');
已创建 1 行。
SQL> DELETE T_P WHERE ID = 1000;
这时会话被锁住,因为缺少了外键索引后,主表删除或更新记录会导致子表整个表被锁,而这会导致严重的系统并发问题。
SQL2> ROLLBACK;
回退已完成。
会话2回滚后,会话1的删除操作才可以继续执行:
已删除 1 行。
|