oracle forupdate锁表,限制访问表的FOR UPDATE操作

几年以前有朋友问过类似的问题,当时考虑了一下,没有想到好的解决方法,前些天有客户询问同样的问题,没有办法周末仔细琢磨了一下,总算是找到一个解决的方法。

其实现在Oracle有专门的工具可以解决这个问题,就是Oracle的FireWall,通过直连的配置方式可以阻塞预配置好的FOR UPDATE操作,不过那需要单独的软件。这里主要方案是要通过数据库现有的功能实现这个目标。

限制FOR UPDATE是有实际意义的,有时候只希望给用户分配查询权限,但是一旦分配了SELECT权限后,用户就自动拥有了FOR UPDATE能力,虽然用户并没有真正UPDATE的权限,但是仍然可以将表的记录锁定,而这有时候并不是所期望的。

SQL> conn test/test

Connected.

SQL> create table t_update (id number, name varchar2(30));

Table created.

SQL> insert into t_update values

(1, 'a');

1 row created.

SQL> commit;

Commit complete.

SQL> create user u1 identified

by u1;

User created.

SQL> grant create session to u1;

Grant succeeded.

SQL> grant select on t_update to

u1;

Grant succeeded.

切换到U1用户,现在可以对T_UPDATE进行SELECT FOR UPDATE操作:

SQL> conn u1/u1

Connected.

SQL> set sqlp 'SQL2> '

SQL2> select * from

test.t_update where id = 1 for update;

ID NAME

---------- ------------------------------

1 a

为了避免FOR

UPDATE操作,可以封装一层视图。

SQL> create view v_update as

select * from t_update;

View created.

SQL> grant select on v_update to

u1;

Grant succeeded.

但是如果仅是视图,那么没有任何作用,FOR UPDATE操作同样可以对单表查询的视图执行:

SQL2> select * from test.v_update where id = 1 for update;

ID NAME

---------- ------------------------------

1 a

如果添加ROWNUM等伪列,可以避免直接FOR UPDATE:

SQL> create or replace view

v_update as select rownum rn, a.* from t_update a;

View created.

但是如果FOR

UPDATE指定ROWNUM伪列外的真实列,还是可以绕开:

SQL2> select * from

test.v_update where id = 1 for update;

select * from test.v_update where id = 1 for update

*

ERROR at line 1:

ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.

SQL2> select id, name from

test.v_update where id = 1 for update;

ID NAME

---------- ------------------------------

1 a

通过报错信息可以看出,如果包含了GROUP BY或DISTINCT就可以阻止FOR UPDATE操作:

SQL> create or replace view

v_update as select distinct * from t_update;

View created.

但是这种方式无疑会带来性能问题,更重要的是,如果表中存在重复记录,那么DISTINCT操作会使得重复记录丢失。

而最好的解决方法是采用UNION

ALL方式创建视图:

SQL> create or replace view

v_update as

2 select * from t_update

3 union all

4 select * from t_update where 1 = 2;

View created.

现在就达到了阻止FOR

UPDATE的操作,且对于查询基表的性能影响最小:

SQL2> select * from

test.v_update where id = 1 for update;

select * from test.v_update where id = 1 for update

*

ERROR at line 1:

ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.

对于不希望用户执行FOR

UPDATE操作的表,可以创建成UNION ALL视图,并将视图的查询权限授权给用户。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值