hibernate学习(5)——对象状态与一级缓存
1、对象状态
1.1 状态介绍
hibernate 规定三种状态:瞬时态、持久态、脱管态
瞬时态:transient,session没有缓存对象,数据库也没有对应记录。没有与hibernate关联,与数据库中的记录没有产生关联。
OID特点:没有值
持久态:persistent,session缓存对象,数据库最终会有记录。(事务没有提交)与hibernate关联,对象有id
OID特点:有值
脱管态:detached,session没有缓存对象,数据库有记录。没有与hibernate关联,对象有id
OID特点:有值
1.2 对象转换
1.2.1 瞬时态/临时态
1 获得:一般都只直接创建(new)
2 瞬时态 转换 持久态
一般操作:save方法、saveOrUpdate
3 瞬时态 转换 脱管态
一般操作:通过setId方法设置数据
例如:
User user = new User(); //瞬时态
user.setUid(1); //脱管态
1.2.2 持久态
1 获得:
查询操作:get、loat、createQuery、createCriteria 等 获得都是持久态【】
执行save之后持久态
执行update之后持久态
2 持久态 转换 瞬时态
官方规定执行delete() --民间:删除态
3 持久态 转换 脱管态
session没有记录
session.close () 关闭
session.clear() 清除所有
session.evict(obj) 清除指定的PO对象
1.2.3 脱管态/游离态
1 获得:
创建、并设置OID的
通过api获得
2 脱管态 转换 瞬时态
手动去除OID,设置成默认值
3 脱管态 转换 持久态
一般操作:update()、saveOrUpdate
总结:
持久状态,我们使用Hibernate主要是为了持久化我们的数据.
对于对象的状态,我们期望我们需要同步到数据库的数据,都被装换成持久状态
/持久化状态特点: Hibernate会自动将持久化状态对象的变化同步到数据库中
代码实现:
package com.alice.hibernate02.a_statue; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.alice.hibernate02.util.HibernateUtil; import com.alice.hibernate02.vo.User; public class Status01Test { @Test //演示三种状态 public void statue01Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = new User();// 瞬时状态 user.setName("lili");// 瞬时状态 user.setPassword("12233");// 瞬时状态 session.save(user);// 持久状态调用完save方法,数据库中有没有对应记录? // 没有对应记录, 但是最终会被同步到数据库中.仍然是持久状态. tran.commit();//持久状态 session.close();//游离状态 } @Test public void statue02Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = new User();// 瞬时状态 user.setName("lili");// 瞬时状态 user.setPassword("12233");// 瞬时状态 session.save(user);//save方法会使用主键生成策略,为User指定id. //主键自增 => 打印 insert语句 // increment=> select max(id) .... //assigned => 需要手动指定主键,不指定将会报错 tran.commit(); session.close(); } @Test // 瞬时=> 游离 // 瞬时: 没有关联,没有id // 游离: 没有关联,有id(与数据库中对应的id) public void statue03Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); //............ User user = new User();//瞬时态 user.setId(1);//游离态 //---------------------------------------------------- session.getTransaction().commit(); // 持久状态 //事务提交时,会把持久化状态对象同步到数据库中 session.close(); // 游离状态 } // @Test // 持久=> 瞬时 // 持久: 有关联,有id // 瞬时: 无关联,无id // public void statue04Test(){ // Session session = HibernateUtil.openSession(); // // Transaction tran = session.beginTransaction(); // // //............ // //通过get方法,得到持久状态对象 // User user = (User) session.get(User.class, 1); // // // //---------------------------------------------------- // session.getTransaction().commit(); // 持久状态 // //事务提交时,会把持久化状态对象同步到数据库中 // session.close(); // 游离状态 // // user.setId(null);//瞬时态 // } @Test // 持久=> 游离 // 只需要将session的关联取消 public void statue05Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); //............ User user = new User();//瞬时态 session.evict(user);//游离 //---------------------------------------------------- session.getTransaction().commit(); // 持久状态 //事务提交时,会把持久化状态对象同步到数据库中 session.close(); // 游离状态 } @Test // 游离=> 瞬时 // 移除ID public void statue06Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); //............ User user = new User();//瞬时态 session.evict(user);//游离 user.setId(null);//瞬时 //---------------------------------------------------- session.getTransaction().commit(); // 持久状态 //事务提交时,会把持久化状态对象同步到数据库中 session.close(); // 游离状态 } @Test // 游离=> 持久 // 是否与Session关联 public void fun8(){ Session session = HibernateUtil.openSession(); session.beginTransaction(); //------------------------------------------------ //通过get方法,得到持久状态对象 User u= (User) session.get(User.class, 1); // 持久状态 session.evict(u);//游离 session.update(u);//持久 //---------------------------------------------------- session.getTransaction().commit(); // 持久状态 -> 打印update语句 session.close(); // 瞬时状态 } }
2、 一级缓存
2.1 介绍session缓存
一级缓存:又称为session级别的缓存。当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。当session关闭时,一级缓存销毁。
//证明session缓存的存在 public void statue01Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user1 = (User) session.get(User.class, 1);// 发送select语句,从数据库取出记录.并封装成对象 // 持久化状态对象=> 存到缓存中 System.out.println("user1"+user1); User user2 = (User) session.get(User.class, 1);//再次查询时,会从缓存中查找,不会发送select System.out.println("user2"+user2); System.out.println(user1 == user2); tran.commit();//持久状态 session.close();//游离状态 }
2.2 一级缓存快照
l 快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。
@Test //session缓存中的快照 public void cache02Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user1 = (User) session.get(User.class, 1);// 发送select语句,从数据库取出记录.并封装成对象 session.update(user1); tran.commit();//持久状态 session.close();//游离状态 } @Test //session缓存中的快照 public void cache03Test(){ Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user1 = new User(); user1.setId(1); user1.setName("aaaa"); user1.setPassword("1435"); session.update(user1); tran.commit();//持久状态 session.close();//游离状态 }
// 持久化状态: 本质就是存在缓存中的对象,就是持久化状态.
2.3 缓冲区
package com.alice.hibernate02.a_statue; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.alice.hibernate02.util.HibernateUtil; import com.alice.hibernate02.vo.User; //session缓存 的细节问题 public class DetailsTest { @Test // 1.保存对象时使用 save方法 // 保存对象时使用 persist方法 // 区别? 没有区别 // persist(持久) 方法 来自于JPA 接口 // save(保存) 方法来自于Hibernate public void details01Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = new User();// 瞬时状态 user.setName("lili");// 瞬时状态 user.setPassword("12233");// 瞬时状态 // session.save(user);// insert 语句被打印,读取id session.persist(user); tran.commit();// 持久状态 session.close();// 游离状态 } // HQL查询一般不会使用缓存 @Test public void details02Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); List<User> list1 = session.createQuery("from User").list(); List<User> list2 = session.createQuery("from User").list(); List<User> list3 = session.createQuery("from User").list(); tran.commit();// 持久状态 session.close();// 游离状态 } @Test // HQL语句批量查询时,查询结果会存入缓冲区 public void details03Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); List<User> list1 = session.createQuery("from User").list(); User user = (User) session.get(User.class, 1); tran.commit();// 持久状态 session.close();// 游离状态 } @Test // SQL查询,如果把查询结果封装到对象中,对象会放入一级缓存 public void details04Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); List<User> list1 = session.createSQLQuery("select * from t_ser") .addEntity(User.class).list(); User u = (User) session.get(User.class, 1); System.out.println(u); tran.commit();// 持久状态 session.close();// 游离状态 } @Test // SQL查询,没有把查询结果封装到对象中,对象不会放入一级缓存 public void details05Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); List<User> list1 = session.createSQLQuery("select * from t_ser").list(); User u = (User) session.get(User.class, 1); System.out.println(u); tran.commit();// 持久状态 session.close();// 游离状态 } //criteria => 会将查询结果放入一级缓存. 但是查询不会使用一级缓存. 与Hql查询结论一致. }
//问题: 缓存中的数据如果与数据库中的不同步,会怎么样?
// 会优先使用缓存中的. 使用JDBC
// 在一级缓存中出现该问题的几率比较小.
//openSession==> 一级缓存生命周期开始
//session.close();=> 一级缓存销毁
2.4 其他api
package com.alice.hibernate02.api; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.alice.hibernate02.util.HibernateUtil; import com.alice.hibernate02.vo.User; //其他API (大部分都是了解) public class SessionTest { @Test // 1. evict 将缓存中的对象移除. // 2. clear 清空1级缓存 public void session01Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = (User) session.get(User.class, 21); session.clear(); session.getTransaction().commit(); session.close();// 游离状态 } @Test // 3 refresh 刷新 => 强制刷新缓存中的对象 => (可以用来解决缓存与数据库数据不同步的问题) public void session02Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = (User) session.get(User.class, 9); session.refresh(user);// 将缓存中的对象立刻与数据库同步,会再发送一个sql语句 session.getTransaction().commit(); session.close();// 游离状态 } @Test // 4 flush 对比快照,并提交缓存对象 public void session03Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = (User) session.get(User.class, 9); session.flush();// 将缓存中的对象立刻与数据库同步,会再发送一个sql语句 session.getTransaction().commit(); session.close();// 游离状态 } @Test // 代理主键=> native // 5.1 aveOrUpdate方法 // saveOrUpdate 可以同时完成保存或更新操作 // 主键为空=>save // 主键有值=> update // 自然主键=> assigned // 5 update 与 saveOrUpdate方法 // saveOrUpdate 可以同时完成保存或更新操作 // 主键为空=> 报错,因为无论是save还是update 都必须指定id // 主键有值=> 先会根据主键查询数据库. // 数据库中存在=> 执行update // 数据库中不存在=> 执行insert public void session04Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = new User(); user.setId(1); user.setName("lilaa"); user.setPassword("143325"); session.saveOrUpdate(user); session.getTransaction().commit(); session.close();// 游离状态 } //在我们使用Hibernate时候,注意要避免出现,两个相同的ID对象.放入一级缓存的情况. @Test public void session05Test() { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User user = (User) session.get(User.class, 1);// 持久化,缓存中存在 session.evict(user); // 游离态,缓存中不存在 User user1 = (User) session.get(User.class, 1);// 持久化,缓存中存在 session.update(user);// 将user重新变为持久化状态,缓存中存在 session.getTransaction().commit(); session.close();// 游离状态 } }