在我们设计程序的时候要考虑问题的整体,不然很容易出现脏读,看示例
1 /** 2 * 业务整体需要使用完整的synchronized,保持业务的原子性。 3 * @author alienware 4 * 5 */ 6 public class DirtyRead { 7 8 private String username = "bjsxt"; 9 private String password = "123"; 10 11 public synchronized void setValue(String username, String password){ 12 this.username = username; 13 14 try { 15 Thread.sleep(2000); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 20 this.password = password; 21 22 System.out.println("setValue最终结果:username = " + username + " , password = " + password); 23 } 24 25 public void getValue(){ 26 System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password); 27 } 28 29 30 public static void main(String[] args) throws Exception{ 31 32 final DirtyRead dr = new DirtyRead(); 33 Thread t1 = new Thread(new Runnable() { 34 @Override 35 public void run() { 36 dr.setValue("z3", "456"); 37 } 38 }); 39 t1.start(); 40 Thread.sleep(1000); 41 42 dr.getValue(); 43 } 44 45 46 47 }
在getValue方法前加synchronized关键字可以避免脏读。否则打印出来的结果是下图那样的:
实际我们先要的结果应该是这样的:
二、数据库的ACID
这里先关注一下ORACLE的一致性读的特性:举个例子,有A和B两个人,A在上午9点的时候对一张很大的表进行查询操作,假设这个查询需要10分钟,B在9点05分的时候对A要查询的这条记录进行了DML操作,将原来的数据值为1改成了2,那么A在9点10分得到的结果一定是1,而不会是2.(做DML操作之前会把原来的值放到UNDO里,A拿到的是UNDO里的值,也有可能抛出snapshot too old异常,但绝不可能把2返回给A)