欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

互联网技术02——脏读

程序员文章站 2022-07-11 11:53:14
...

脏读:

当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没提交到数据库中,这时另一个事务也访问这个数据,然后使用了这个数据。

对于多线程的同步和异步方法,如果考虑不周,就有可能发生脏读的错误。

例子:

package com.company;

/**
 * Created by BaiTianShi on 2018/8/13.
 * 脏读
 */
public class DirtyRead {
    private String userName = "DaBaiTwo";
    private String password = "123456";

    private synchronized void setValue (String userName,String password){
        this.userName =  userName;
        try {
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.password = password;
        System.out.println("set的值:userName = "+this.userName+"!!password="+this.password);
    }
    private  void getValue (){
        System.out.println("查询的值:userName = "+this.userName+"!!password="+this.password);
    }

    public static void main(String[] args) {
        final DirtyRead dr = new DirtyRead();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                dr.setValue("zhangSan","123");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                dr.getValue();
            }
        });
        t1.start();
        t2.start();
    }

}

运行结果:

查询的值:userName = zhangSan!!password=123456
set的值:userName = zhangSan!!password=123

如果数据正常,一定是“DaBaiTwo”和“123456”成对出现,“zhangSan”和“123”成对出现。而结果可看出,出现了数据不一致的情况,这就是脏读。现实中的场景就是,当我们处理数据时,但是还没完全处理完毕,这时其他线程获取到这些数据(没完全处理完毕)就会出现数据不一致的情况,最终到时数据错误。

解决办法是将setValue加上synchronized关键字。因为这个对象被上了锁,getValue必须等待锁被释放。

 

oracle中是如何避免脏读的

假如有千万级别的数据,用户要查询某条记录(假设开始时的值是100),查询了10分钟,在这10分钟之内,别的用户将这条数据修改成了200,那么用户插的结果是多少?结果是100。因为Oracle采用undo机制,undo就是用来保存事务操作过的记录,如果发生错误,可将之前的数据重新填补

互联网技术02——脏读

当用户A查询一大表table数据时,假设9:50开始查询,10:00本次查询结束,且本table在9:50这一刻的SCN编号为1000(自增)。用户B此时对大表table进行了一次update并commit。此时undo会记录B的反向操作记录为undo1,并记录SCN编号为1001,此时C再次对大表进行了一次update并commit,此时记录为undo2,并记录SCN编号为1002。当用户A查询到被修改的数据块时,发现此时的SNC编号(1002)大于查询发起时的编号(1000),然后就找比自己小的数据块进行对比,直到找到SCN编号为999的undo,在进行数据对比处理

 

 

 

 

相关标签: 多线程