目录
前言
在多线程或分布式系统中,当多个线程或进程同时访问和修改共享资源时,可能会出现数据不一致的情况。其中一个经典的问题就是脏读。本文将详细介绍脏读的概念、原因和解决方案,帮助读者更好地理解和应对这个常见的数据一致性问题。
一、脏读的定义
脏读是指一个事务中读取到了另一个并发事务未提交的数据,导致读取到的数据可能是不准确或无效的。脏读可能会导致程序的逻辑错误,甚至数据的损坏。
二、脏读的原因
脏读的原因主要是由于并发访问共享资源时,读操作与写操作之间的时间差异引起的。当一个事务正在执行写操作时,另一个事务可能会读取到未提交的数据。
主要原因包括:
- 事务隔离级别不当:数据库提供了不同的事务隔离级别,如读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。如果选择了较低的隔离级别,就容易出现脏读问题。
- 锁机制不合理:锁机制是保证数据一致性的重要手段。如果没有正确使用锁,就可能导致脏读问题。
- 代码逻辑错误:在编写程序时,如果没有考虑到并发访问的情况,就可能导致脏读问题。
三、解决脏读的方案
- 使用合适的事务隔离级别:根据具体业务需求,选择合适的事务隔离级别。一般情况下,推荐使用可重复读或串行化,以确保数据的一致性。
- 使用锁机制:在并发访问共享资源时,使用锁机制(如读写锁、互斥锁)来控制对资源的访问。通过加锁和解锁操作,确保同一时间只有一个事务能够读取或修改数据。
- 使用乐观并发控制:乐观并发控制是一种轻量级的并发控制方式,它通过版本号或时间戳等机制来标识数据的版本,并在进行更新操作时比较版本号,以判断是否有其他事务修改了该数据。
四、Demo讲解
对于对象的同步和异步的方法,我们在设计自己的程序的时候,一定要考虑问题的整体,不然就会出现数据不一致的错误,很经典的错误就是脏读(dirtyread)
package com.ctb.demo;
/**
* 业务整体需要使用完整的synchronized,保持业务的原子性
*
* @author biao
*
* 2024年
*/
public class DirtyRead {
private String username = "ctb";
private String password = "123";
public synchronized void setValue(String username,String password) {
this.username = username;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.password = password;
System.out.println("setValue最终结果:username = "+this.username + ", password = " + this.password);
}
public void getValue() {
System.out.println("getValue方法得到:username = "+this.username + ", password = " + this.password);
}
public static void main(String[] args) throws Exception {
final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("zs", "456");
}
});
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
结果:
public synchronized void getValue() {
System.out.println("getValue方法得到:
username = "+this.username + ", password = " + this.password);
}
结果:
注:在代码执行时,main方法下调用线程执行需2s时间,它会继续往下执行,1s后执行getValue()方法,所以需给getValue()方法加锁synchronized,保证整体的一致性。
总结:
在我们对一个对象的方法加锁的时候,需要考虑业务的整体性,即为setValue/getValue方法同时加锁synchronized同步关键字,保证业务(service)的原子性,不然会出现业务错误(也从侧面保证业务的一致性)
标签:username,事务,解决方案,getValue,脏读,一致性,password,public From: https://blog.csdn.net/weixin_74268571/article/details/139638668