并发问题可能导致的脏数据

在整理应用中旧系统数据移植的问题,发现表中出现了几条异常记录,记录除主键不同外,记录的时间和其它内容完全一致。
业务本身的逻辑是,如果碰到数据库中有相关的记录需要把这些记录置为无效,然后插入一条记录。现在是出现了二条有效的记录,是违背业务逻辑本意的。

猜测问题可能出在
1、重复提交表单引起的
2、两个人同时进行相同的操作引起的
3、由于生产环境使用了集群,当不同的人访问不同的集群上的节点时,也会导致这个问题

避免1,2,系统改动不会太大,如果避免3引起的问题,就不是那么好搞了。
市检办案系统虽然使用的人不是太多,但是有些模块会有集中使用的情况,由3导致问题的机率也会增大。


--trancation start
update tab set flag=2 where flag=1 and id=10;
insert into tab values(1,10);
--trancation complete
两个事务并行时,两个事务同时运行到update 语句,由于表中并没有满足条件的记录,update语句并没有使其中的一个事务挂起。这时就出现两条相同数据的语句。

如果说update时,数据表中有满足条件的语句,由于获取不到相同行的排他锁,其中一个事务是会被挂起的,就相当两个事务是串行的了。

初次解决方案(失败):
1、可以把事务的隔离级别设为Serializable(Oracle缺省是Read committed);

如果update没有更新记录,是不存在幻想读的。

(一个事务中,查询时看到了另一个已完成事务的插入记录),update时,由于更新为0,所以不会导致事务失败。还是会有两条相同记录插入到了表中。
serializable并不是对事务串行执行。可以考虑用锁,比如在另一张表t_mylock中放一条记录,永久不删,事务开始时使select * from t_mylock for update。让事务真正串行
--trancation start
--set transaction isolation level serializable;
select * from t_mylock for update;
update tab set flag=2 where flag=1 and id=10;
insert into tab values(1,10);
--trancation complete


ps: serializable 可能会报不能序列化访问的错误,在实际应用中可能不太合适。
ora-08177 :cann't serialize access for this transaction
如果update时,更新了其它事务提交的记录(当前事务开始时还看不到这条记录)就会报这个错。




解决方案:

2、使用select t from table_lock  for update 及在数据库端使用锁,这条语句有一个前提是必须要有记录,才能起到阻塞的效果。
--trancation start
select id from table_mylock where id=1 for update;(表table_mylock中有满足条件的记录)
update tab set flag=2 where flag=1 and id=10;
insert into tab values(1,10);
--trancation complete

你可能感兴趣的:(oracle,Access)