熟悉Hibernate的童鞋 一定知晓Hibernate有一级缓存跟二级缓存 一级缓存是Hibernate默认开启的缓存 而二级缓存需要自己配置 此处只简单的讨论一个
Hibernate中load的内部实现原理
如果你要根据用户id获取用户的信息
User user = session.load(id,User.class);
此处返回的user类型是一个代理对象User$Proxy 而User$Proxy
User$Proxy extends User{
//代理对象持有用户id
private Integer id ;
private User realUuser;
public String getName(){
//首先会查询缓存 如果缓存中有数据则直接返回
//如果缓存为空 则需要向数据查询 数据
//如果从数据中也没有获取到数据 则抛出异常
}
}
故使用session.load方法时 如果没有查询到数据 会抛出异常 此处肯定有一些童鞋很好奇缓存机制是怎么实现的呢?
缓存系统会用读写锁 下面简单的介绍一个简单的缓存系统 实现原理
缓存肯定是多个线程并发访问的 故对效率要求极高 否则你的系统无法承受高并发访问..
大家了解一下读锁与写锁的一些关系
1.读锁与读锁不互斥
2.读锁与写锁互斥
3.写锁与写锁互斥
读写锁的妙用 一个简单的缓存系统
/**
*
* 一个简单的缓存系统
*/
class Cache{
//数据
private Object data;
//读写锁
ReadWriteLock rwl = new ReentrantReadWriteLock();
//获取数据
public Object get(){
//用户读取数据 开启读锁
System.out.println(Thread.currentThread().getName()+"开始获取数据等待中.");
rwl.readLock().lock();
System.out.println(Thread.currentThread().getName()+"获取读锁 开始读取数据...");
/**
* 当查询数据的过程中 出现异常 则不会执行下面的代码 而此时已经获取到读锁了
* 一旦发生异常 锁资源不能释放 故此处用try catch finally 保证资源得到释放
*/
try {
if ( data == null ) {
//由于无数据 需要向数据库查询 故要释放读锁
//开启写锁?因为要给data复制 故要开启写锁
System.out.println("数据为空:"+Thread.currentThread().getName()+":..");
rwl.readLock().unlock();
System.out.println(Thread.currentThread().getName()+" 释放读锁");
rwl.writeLock().lock();
//从数据中获取...
System.out.println(Thread.currentThread().getName()+" 获取写锁");
/**
* 此处如果不判断数据是否为空 会出现什么情况呢?
* 试想一下如果当三个线程同时访问该方法的时候.只有第一个线程可以获取写锁
* 其它线程处于等待... 当该线程写完数据之后 释放写锁
* 第二个线程获得写锁 但是此时数据不再为空[第一个获取写锁的线程已经写入数据]
* 如果此处不判断数据是否为空 第二个线程会再次查询数据并写入。
* 如果是N个线程 同时访问该方法 则会查询N次数据并写入 效率可想而知!
* 故为了提高效率 此处再次判断数据是否为空
* 有兴趣的童鞋可以把此处的判断去掉 你看看会发现什么?
*/
if ( data == null ) {
System.out.println(Thread.currentThread().getName()+"开始写入数据");
//此处的数据应该是从DB中获取
data = "data from db";
System.out.println(Thread.currentThread().getName()+"数据写入完毕...");
}
//释放写锁 获取读锁
/**
* 如果是第二个线程获取到写锁之后 经过判断之后 数据不为空
* 则立即释放写锁 再次获取读锁
* 至于先释放那个锁 再获取那个锁的顺序
*【如果此处是我自己 我可能会先释放写锁
* rwl.writeLock().unlock();
* 在获取读锁
* rwl.readLock().lock();】
* 此处是模仿JDK文档中关于缓存释放和获取锁的顺序...
*/
rwl.readLock().lock();
rwl.writeLock().unlock();
}
} catch (Exception e) {
//异常处理
} finally {
rwl.readLock().unlock();
}
return data;
}
}
测试代码:
public static void main(String[] args) {
final Cache cache = new Cache();
for(int i = 0;i<3;i++){
new Thread(){
public void run() {
Object data = cache.get();
System.out.println(Thread.currentThread().getName()+"得到数据"+data.toString());
};
}.start();
}
}