一 、生命周期
1.1 . 说明
持久化类就是我们所说的实体类,实体类(持久化类)对象是有状态的。
为什么实体类对象会有状态?
答:由于HIbernate框架是一个先映射,后操作的框架。所谓的状态就是实体类的对象和数据库是否有关联的情况。
是因为HIbernate是通过对象操作数据库的,对象必须要和数据库有连接,才可以操作数据库表。
我们将这个实体类对象和数据库连接的情况称为状态。
瞬时态:当new一个对象的时候,此时是瞬时态,内存中包含此对象,但是数据库表中无此记录
持久态:当session执行save或者saveOrUpdate方法的时候,进入持久态,此时数据库中的记录跟内存中的对象保持一致
游离态:当session中不再包含此对象的时候(clear,evict,close),此时是游离态,对象存在于内存之中,跟数据库表无关系
public class TestHBM { @Test public void test() { Configuration config = new Configuration().configure(); SessionFactory factory = config.buildSessionFactory(); Session session = factory.openSession(); Transaction tx = session.beginTransaction(); // 使用new关键字创建对象的时候,叫做瞬时态 User user = new User(); user.setName("张三丰"); user.setPwd("123"); // 经过save方法之后,对象交由session来管理,进入持久态 session.save(user); System.out.println(user.getId()); //清空session对象,进入游离态 session.clear(); System.out.println(user.getId()); user.setName("张无忌"); //再次保存之后进入持久态 session.save(user); System.out.println(user.getId()); //进入瞬时态 //session.delete(user); tx.comit(); factory.close(); } }
1.2 目的:只有知道如何获得持久态的对象就可以。
有一下情况可以获得持久态对象:
更新(update/ saveOrupdate)
查询(get/load)
Hibernate持久态的对象就是正在和数据表关联的状态对象。支持条对象支持一下功能:
-
支持缓存
-
支持快照
-
支持导航查询:所谓的导航查询就是,通过一个表直接获得关联的表的数据。
二 、 缓存
HIbernate是支持一级缓存。所谓的一级缓存就是Session级别的缓存。
意思就是说,同一个session查询同样的数据,只查询一次数据库。如果出现同多次同样的查询(get/load)直接返回缓存的数据。
三 、 清空缓存的方法
清空缓存的三个方法。
-
关闭 close()
-
清空 clear()
-
清空指定的实体态对象 evit()
public void get(){ //1.获得操作对象 Session session = HibernateUtils.getSession(); //通过OID获得对应的记录 //如果支持缓存,get四次数据库,只查一次。 Student student1 = session.get(Student.class,1L); //如果clear()清空同一个session的所有持久化对象,缓存被清空 session.clear(); Student student2 = session.get(Student.class,1L); //evict()清空指定的持久化对象,该对象的缓存被清空 session.evict(student2); Student student3 = session.get(Student.class,1L); Student student4 = session.get(Student.class,1L); //表示关闭了session。session的所有缓存被清空 session.close();
四、 缓存的作用:缓存的作用:就是减少查询的次数,从而提高查询的效率!!!!
close,clear,evit清空缓存只是将持久态转成游离态,清空的是缓存的数据,清空的是数据和数据库的关联,而不是对象原有清空数据。
五 、 快照的机制
5.1 定义
当实体对象变成持久态对象的时候,和数据库表关联后。在session中会保存两份数据的副本。
一份是缓存,一个是快照。
缓存的作用:用于提高查询的效率
快照的作用:用于更新数据,作对比使用。
快照的支持就是持久态对象直接可以通过直接修改属性值更数据库表的数据,不需要update方法。
|
5.2 示例代码
实现原理
-
在获得数据库记录的那一刻,Hibernate同时将数据产生两个副本,快照和缓存。
-
在修改持久态对象的数据时,同时也修改了缓存的数据
public class StudentDAOTest { @Test public void update(){ //1.获得数据库操作对象,session Session session = HibernateUtils.getSession(); //2. Hibernate框架,操作(增删改)必须先开启事务才能操作 Transaction transaction = session.beginTransaction(); //3.创建一个实体类,并且封装数据 Student c=session.get(Student.class, 1L); //持久态对象修改了属性,直接提交就可以更新到数据库里面 c.setStuName("李四"); //先查出来,就是变成持久态对象了,然后直接通过set 之类的就能更新数据 //5.提交事务,如果出错自动回滚 transaction.commit(); //6.关闭 session.close(); } }
5.3 实现流程图
![](https://img2018.cnblogs.com/blog/1665938/201908/1665938-20190814135956584-37265496.png)
联合主键
1、创建java类:ScoreId.java
package cn.gzsxt.po; import java.io.Serializable; public class ScoreId implements Serializable { private int sid; private int subjectid; public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public int getSubjectid() { return subjectid; } public void setSubjectid(int subjectid) { this.subjectid = subjectid; } } Score.java package cn.gzsxt.po; public class Score { private ScoreId scoreId; private double score; public ScoreId getScoreId() { return scoreId; } public void setScoreId(ScoreId scoreId) { this.scoreId = scoreId; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } }
2、编写类与表的关系映射文件 Score.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.gzsxt.po"> <class name="Score" table="t_score"> <!-- 设置联合主键 class:执行联合主键对应的类 --> <composite-id class="ScoreId" name="scoreId"> <!-- 设置联合主键的属性 --> <key-property name="sid"></key-property> <key-property name="subjectid"></key-property> </composite-id> <property name="score"></property> </class> </hibernate-mapping>
3、测试
package cn.gzsxt.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.junit.Test; import cn.gzsxt.po.Score; import cn.gzsxt.po.ScoreId; public class TestHBM { @Test public void createTable() { Configuration config = new Configuration().configure(); SchemaExport se = new SchemaExport(config); // script表示脚本是否显示 export是否将脚本执行到数据库 se.create(true, true); } @Test public void testSave(){ Configuration config = new Configuration().configure(); ServiceRegistry register = new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build(); SessionFactory factory = config.buildSessionFactory(register); Session session = factory.openSession(); Transaction tx = session.beginTransaction(); ScoreId scoreid = new ScoreId(); scoreid.setSid(1); scoreid.setSubjectid(1); Score score = new Score(); score.setScore(100); score.setScoreId(scoreid); session.save(score); tx.commit(); session.close(); factory.close(); } }
注意: 1、实现联合主键,必须在联合主键类上实现序列化接口
2、配置联合主键属性的时候,必须加name属性值,与类中的某一个属性相关联
3、在执行DML操作的时候,可以设置hbm2ddl.auto属性,选择合适的模式创建表对象