对象的四种状态
临时状态
新创建出的对象。
持久化状态
数据库中查询出的对象
游离状态
数据库中查询出来,并修改后为保存的对象
删除状态
数据库delete后的对象。
hibernate的session对象自身是存在缓存的,当你重复get同一个对象只会执行一次。
Session 一级缓存:
在一次事务中重复相同查询,只会执行一次sql,该方式的范围在一次事务中。
@Test
public void testSave() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态,并且保存在Session缓存中
session.save(user); //Session会对该对象进行比对,如果是相同就不再只会执行保存。
//session.clear();//将Session清空,Session中没有User对象,所以无法在进行setName操作
//session.evict(user); //指定清除Session中的user对象,后续不再执行user的setName操作。
user.setName("李四"); //Session发现user那么修改了 数据 就会执行Update操作和数据库同步数据。
// --------------------------------------------
session.getTransaction().commit();
session.close();
user.setName("我无效");//Session 关闭后修改的不会更新到数据库
session = sessionFactory.openSession();
session.beginTransaction();
user = (User) session.get(User.class, user.getId()); // 持久化
System.out.println(user);
session.getTransaction().commit();
session.close();
}
Session 内存溢出问题:
public class User {
private Integer id;
private String name;
private byte[] data = new byte[1024 * 1024 * 5];//这里创建了一个大字节数据。
Session 的缓存数据如果超过了 java虚拟机就会导致内存溢出。
所以在单次事务操作大数据时,每隔一段时间对Session内存进行一次清理。
@Test
public void testBatchSave() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
for (int i = 0; i < 30; i++) {
User user = new User();
user.setName("测试");
session.save(user);
//缓存清理
if (i % 10 == 0) {
session.flush(); // 将缓存数据刷入数据库。
session.clear(); // 清空Session缓存
}
}
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
Load 懒加载
@Test
public void testLoad() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
//load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
User user = (User) session.load(User.class, 5);
System.out.println(user.getClass());
System.out.println("---");
System.out.println(user.getId());//对象有id,就不会执行Sql查询
System.out.println(user.getName());//发现对象没有name数据,这时才会去查询数据库
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
懒加载:
1、懒加载配置方式有两种:
①、在类级别上配置 :
<class ... lazy="true/false">
②、在属性级别上配置:
<set/list/map/bag/ ... lazy="true/false/extra">
2、懒加载 load()方法返回的是带有sql语句的代理对象而不是 带数据的实体对象,所以在调用里面方法时,才会去查询数据。
3、LazyInitalizationException 异常处理:
懒加载后对象获取数据的方法也必须在session关闭事务之前使用,如果想懒加载初始化所有数据,可以调用initializ()方法。否者就会包该异常。
4、true/false/extra
true:代表开启
false:代表关闭懒加载
extra:表示聪明的加载
比如下面的例子
public class User {
private Integer id;
private String name;
//用户购物列表
private Set<Goods> shopping;
User user = (User) session.get(User.class, 5);
//如果使用lazy=true 的话 就会查询所有的结果,然后回去结果的数量:
//如果使用lazy=extra: select count(id) from goods... 如果数据庞大的情况下,我只想获取总数,这样效率就会高很多
int num = user.getShopping().size();