Hibernate(二)一级缓存、延迟加载
一级缓存概念:
一级缓存又称为session级别的缓存,所以当session关闭时一级缓存也会关闭。如果每次查询或修改数据都到数据库中进行查找或修改,当数据量比较大时就会对程序的性能产生比较大的影响。而一级缓存正好解决了这一问题。每次对数据进行查询时先到缓存中去查找所需要的数据,如果缓存中有则直接拿过来用,如果没有再到数据库中查询。然后将查询到的数据往缓存中也放一份,以便下一次使用。
而session对数据进行操作的时候并不是直接操作数据库,而是将数据先放置到一级缓存中,当事务提交或者调用session.flush()方法是才会正式执行sql语句对数据库进行操作。
一级缓存测试:
先上测试代码
package cn.otote.session;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.junit.jupiter.api.Test;
import cn.otote.entity.User;
import cn.otote.utils.HibernateUtil;
class SessionTest {
@Test
void test() {
//获取session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
//获取user对象
User user = (User) session.get(User.class,1);
//将user的信息打印出来
System.out.println(user);
System.out.println("-----------------------------------------");
//再次获取user对象
User user2 = (User) session.get(User.class,1);
//将user2的信息打印出来
System.out.println(user2);
//事务提交
transaction.commit();
}
}
控制台打印的信息:
通过控制台打印的信息可以看到在第一次查询用户小明的信息的时候一级缓存中没有小明的数据,所以发送了sql语句到数据库中查询。而第二次再查询小明信息时一级缓存中已经有了小明的信息,所以直接拿过来用,并没有再次到数据库中查询。
一级缓存测试2:
@Test
void test2() {
//获取session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
User user=new User();
user.setUserName("小花");
user.setAge(19);
user.setSex("女");
//保存对象
session.save(user);
//事务不提交
//transaction.commit();
}
控制台信息:
此时可以看到控制台已经打印出sql语句,但是因为事务没提交,也没调用session.flush()方法。所以到数据库中查看用户表可以发现小花这条数据并没有插入。
将代码修改一下,调用transaction.commit();提交事务。运行可以看到控制台打印的信息还是跟上面一样,但是这时候打开数据库用户表就可以看到小花这条数据已经插入到数据库了。
延迟加载get()与load()区别:
1、get():
a、get的加载很积极,调用立即发送sql语句。
b、返回的是个正式的对象。
c、如查询到一个不存在的数据返回的时null。
2、load():
a、懒加载
b、返回的是个代理对象,这个代理对象中只有id有值,其他属性都是空值
c、查询一个不存在的数据抛出异常
get()测试:
@Test
void test3() {
//获取session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
User user = (User) session.get(User.class, 1);
//事务提交
transaction.commit();
}
控制台信息:
测试代码中并没有使用到user对象,但是hibernate还是发送了sql。
接着测试通过get获取一个数据库中不存在的对象,代码与上面的代码一致,因为目前数据库中不存在id为4的用户,所以将
User user = (User) session.get(User.class, 1);该为User user = (User) session.get(User.class, 4);接着打印user。
通过控制台可以看到返回的是一个null;
load()测试:
@Test
void test4() {
//获取session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
User user = (User) session.load(User.class, 1);
//先不打印user
// System.out.println(user);
//事务提交
transaction.commit();
}
先不打印user对象,运行观察控制台可以发现并没有发送sql语句查询数据。接着将代码改一下打印user对象。再观察控制台。
可以发现当用到该对象时才会真正发送sql去查询,所以称为懒加载。
接着测试用load()查询一个不存在的数据。
@Test
void test5() {
//获取session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
//因为id为4的用户数据库中不存在所以用4测试
User user = (User) session.load(User.class, 4);
//打印user 因为只有使用到了user对象才会加载
System.out.println(user);
//事务提交
transaction.commit();
}
观察单元测试:
可以发现通过load方式查询不存在的数据会出对象找不到的异常。
补充:load()的懒加载是可以更改为立即加载的,只需要再映射文件中的class标签内将lazy属性设为false就可以变成立即加载。