小弟最近刚学hibernate,看的是深入浅出hibernate一书。里面碰到一些关于缓存的问题。
建了个简单的表测试 User 里面的字段只有 id 和 name
其中操作User类中(OperatorUser类)有个删除User的方法和获取User的方法如下
//删除User
//获取user
写了个测试类Test
运行,没错,会打印出相同的姓名。因为当调用deleteUser()方法时,Hibernate的内部缓存和数据库不同步。但是当我注释掉
//System.out.println(user.getName()) ;
//op.deleteUser("001") ;
//User user01= op.getUser("001") ;
//System.out.println(user01.getName()) ;
再重新运行一次下面注释掉一些的代码-----意味着重新打开了一个session,而前面运行那次的session已经关闭,相对应前面的session的缓存也不存在了。
OperatorUser op = new OperatorUser() ;
User user=op.getUser("001") [color=red];--运行到此时,不会抛出异常,从二级缓存中取出的吗?[/color] //System.out.println(user.getName()) [color=red];---取消注释,运行到此时候,抛出异常,说没有相应的列[/color]
//op.deleteUser("001") ;
//User user01= op.getUser("001") ;
//System.out.println(user01.getName()) ;
可以,没错,不会抛出异常,但,加上System.out.println(user.getName());时,
却抛出异常,说数据库中没有相应的列!
问题就在这:[color=blue]为什么调用op.getUser("001")不会抛出异常,为什么调用user.getName()却说没有相应的列![/color]
两次运行,不同的session,内部缓存不同。但是二级缓存相同。也就是说二级缓存里应该有Id 为 001的User实体对象才是。但是为什么调用user.getName()时会抛出异常呢?
通过指点,再在网上查了下关于session.load方法的信息,的确是关于load方法延迟加载的问题,而和缓存没有多大关系,因为两次运行,无论是sessionfactory还是session,两次都不同。
关于session.load():
1. load方法会先从内部缓存和二级缓存中查找实体对象,看看缓存中是否存在该对象。session.get()方法也一样。
2. hibernate中的load方法的加载方式是延迟加载, 返回的是一个实体对象的代理实例,,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,当调用getXXX()方法时,才会真正地到数据库里获得属性值。所以第二次再执行时,会抛出异常!
建了个简单的表测试 User 里面的字段只有 id 和 name
其中操作User类中(OperatorUser类)有个删除User的方法和获取User的方法如下
//删除User
public void deleteUser(String id){
Transaction tran = session.beginTransaction() ;
String hql = "delete User where id=?" ;
Query q = session.createQuery(hql) ;
q.setString(0, id) ;
q.executeUpdate() ;
tran.commit() ;
}
//获取user
public User getUser(String id){
Transaction tran = this.session.beginTransaction() ;
User user = (User) this.session.load(User.class, id) ;
tran.commit() ;
return user ;
}
写了个测试类Test
OperatorUser op = new OperatorUser() ;
User user=op.getUser("001") ;
System.out.println(user.getName()) ;
op.deleteUser("001") ;
User user01= op.getUser("001") ;
System.out.println(user01.getName()) ;
运行,没错,会打印出相同的姓名。因为当调用deleteUser()方法时,Hibernate的内部缓存和数据库不同步。但是当我注释掉
//System.out.println(user.getName()) ;
//op.deleteUser("001") ;
//User user01= op.getUser("001") ;
//System.out.println(user01.getName()) ;
再重新运行一次下面注释掉一些的代码-----意味着重新打开了一个session,而前面运行那次的session已经关闭,相对应前面的session的缓存也不存在了。
OperatorUser op = new OperatorUser() ;
User user=op.getUser("001") [color=red];--运行到此时,不会抛出异常,从二级缓存中取出的吗?[/color] //System.out.println(user.getName()) [color=red];---取消注释,运行到此时候,抛出异常,说没有相应的列[/color]
//op.deleteUser("001") ;
//User user01= op.getUser("001") ;
//System.out.println(user01.getName()) ;
可以,没错,不会抛出异常,但,加上System.out.println(user.getName());时,
却抛出异常,说数据库中没有相应的列!
问题就在这:[color=blue]为什么调用op.getUser("001")不会抛出异常,为什么调用user.getName()却说没有相应的列![/color]
两次运行,不同的session,内部缓存不同。但是二级缓存相同。也就是说二级缓存里应该有Id 为 001的User实体对象才是。但是为什么调用user.getName()时会抛出异常呢?
通过指点,再在网上查了下关于session.load方法的信息,的确是关于load方法延迟加载的问题,而和缓存没有多大关系,因为两次运行,无论是sessionfactory还是session,两次都不同。
关于session.load():
1. load方法会先从内部缓存和二级缓存中查找实体对象,看看缓存中是否存在该对象。session.get()方法也一样。
2. hibernate中的load方法的加载方式是延迟加载, 返回的是一个实体对象的代理实例,,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,当调用getXXX()方法时,才会真正地到数据库里获得属性值。所以第二次再执行时,会抛出异常!