Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用 EJB 的J2EE 架构中取代CMP(Container Managed Persistence,容器管理的持久性,服务器负责处理数据库访问)完成数据持久化的重任。ORM框架,对象关系映射(Object Relation Mapping)。
Hibernate工具类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.glorze.hibernate; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; /** * hibernate工具类-建立session工厂 * @ClassName HibernateUtil * @author: glorze.com * @since: 2018年10月18日 下午10:54:26 */ public class HibernateUtil { private static final SessionFactory SESSION_FACTORY = buildSessionFactory(); public static SessionFactory buildSessionFactory() { // 实例化配置文件 Configuration configuration = new Configuration().configure(); // 实例化服务登记 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); // 建立session工厂 return configuration.buildSessionFactory(serviceRegistry); } public static SessionFactory getSessionFactory() { return SESSION_FACTORY; } } |
xml与注解:
1 2 3 4 5 6 7 8 9 10 11 |
<?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="com.glorze.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="native"></generator> </id> <property name="name"></property> </class> </hibernate-mapping> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.glorze.hibernate; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; /** * 使用注解标记hibernate持久化 * @ClassName Teacher * @author: glorze.com * @since: 2018年10月18日 下午11:00:16 */ @Entity @Table(name = "t_teacher") public class Teacher { private long id; private String name; @Id @GeneratedValue(generator = "_native") @GenericGenerator(name = "_native", strategy = "native") public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Teacher [id=" + id + ", name=" + name + "]"; } } |
映射对象标识符(OID):
Hibernate使用对象标识符(OID)标识对象
Hibernate级联保存与更新:
在<many-to-one>这端,cascade 默认是”none”,假如我们希望在持久化多的一端的时候,自动级联保存和更新一的一端,我们可以把cascade设置成”save-update”;
Hibernate中inverse属性:
其实就是在级联关系当中可以实现权力控制的反转,转移。简单的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?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="com.glorze.model"> <class name="Class" table="t_class"> <id name="id" column="classId"> <generator class="native"></generator> </id> <property name="name" column="className"></property> <!-- 班级与学生一对多,配置inverse属性可以实现学生拥有控制权 --> <set name="students" cascade="delete" inverse="true"> <key column="classId"></key> <one-to-many class="com.glorze.model.Student"/> </set> </class> </hibernate-mapping> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package com.glorze.hibernate; import org.junit.Test; /** * 测试Hibernate中inverse属性 * @ClassName TestInverse * @author: 高老四 * @since: 2018年10月19日 下午12:42:13 */ public class InverseTest { @Test public void testInverse() { Class c = (Class) session.get(Class.class, Long.valueOf(1)); Student s = (Student) session.get(Student.class, Long.valueOf(1)); // 拥有控制权 c.getStudents().add(s); s.setC(c); } } |
一对多双向自身关联关系映射:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package com.glorze.hibernate; import java.util.HashSet; import java.util.Set; /** * 节点Bean * @ClassName Node * @author: 高老四 * @since: 2018年10月19日 下午12:45:53 */ public class Node { private long id; private String name; /** * 多对一,父节点 */ private Node parentNode; /** * 一对多,相当于父节点 */ private Set<Node> childrenNode = new HashSet<Node>(); public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Node getParentNode() { return parentNode; } public void setParentNode(Node parentNode) { this.parentNode = parentNode; } public Set<Node> getChildrenNode() { return childrenNode; } public void setChildrenNode(Set<Node> childrenNode) { this.childrenNode = childrenNode; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?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="com.glorze.model"> <class name="Node" table="t_node"> <id name="id" column="nodeId"> <generator class="native"></generator> </id> <property name="name" column="nodeName"></property> <many-to-one name="parentNode" column="parentId" class="com.glorze.model.Node" cascade="save-update"></many-to-one> <set name="childrenNode" inverse="true"> <key column="parentId"></key> <one-to-many class="com.glorze.model.Node"/> </set> </class> </hibernate-mapping> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
package com.glorze.hibernate; import static org.junit.Assert.*; import java.util.Iterator; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.glorze.model.Class; import com.glorze.model.Node; import com.glorze.model.Student; import com.glorze.util.HibernateUtil; /** * 测试一对多节点双向自身关联关系映射 * @ClassName NodeTest * @author: 高老四 * @since: 2018年10月19日 下午12:49:28 */ public class NodeTest { private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); private Session session; @Before public void setUp() throws Exception { // 生成一个新的session session = sessionFactory.openSession(); // 开启事务 session.beginTransaction(); } @After public void tearDown() throws Exception { // 提交事务 session.getTransaction().commit(); // 关闭session session.close(); } @Test public void testSave() { Node node = new Node(); node.setName("根节点"); Node subNode1 = new Node(); subNode1.setName("子节点1"); Node subNode2 = new Node(); subNode2.setName("子节点2"); subNode1.setParentNode(node); subNode2.setParentNode(node); /** * invers属性 在多的一段进行数据操作 */ session.save(subNode1); session.save(subNode2); } } |
Hibernate中四种对象状态:
- 临时状态(transient): 刚用new语句创建,还没有被持久化,并且不处 Sesssion的缓存中。处于临时状态的Java对象被称为临时对象。
- 持久化状态(persistent): 已经被持久化,并且加入到Session的缓存中。处于持久化状态的Java对象被称为持久化对象。
- 删除状态(removed): 不再处于Session的缓存中,并且Session已经计划将其从数据库中删除。处于删除状态的Java对象被称为删除对象。
- 游离状态(detached):已经被持久化,但不再处于Session的缓存中。处于游离状态的Java对象被称为游离对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package com.glorze.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.glorze.model.Class; import com.glorze.model.Student; import com.glorze.util.HibernateUtil; /** * Hibernate四种对象状态测试 * * @ClassName StudentTest * @author: 高老四 * @since: 2018年10月19日 下午1:02:55 */ public class StudentTest { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 生成一个新的session Session session = sessionFactory.openSession(); // 开启事务 session.beginTransaction(); // c1 c2为临时对象 Class c1 = new Class(); c1.setName("高老四博客"); Class c2 = new Class(); c2.setName("http://www.glorze.com"); // c1 c2为持久化对象,存在session中 session.save(c1); session.save(c2); // 删除对象 session.delete(c2); // 提交事务,提交之后就插入到了数据库 session.getTransaction().commit(); // 关闭session session.close(); // 此时的c1为游离对象,但是可以获取属性值 System.out.println(c1.getName()); // 删除状态 System.out.println(c2.getName()); } } |
session常用方法:
- save()方法: 将一个临时对象转变成持久化对象。
- update()方法: 将一个游离对象转变为持久化对象。
- saveOrUpdate()方法: 包含了save()和update()方法。
- merge()方法: 合并对象。
- delete()方法: 删除对象。
load()方法VSget()方法区别:
- 都是根据 OID 从数据库中加载一个持久化对象。
- 假如数据库中不存在与OID对应的记录,Load()方法会抛出异常,而get()方法返回null;
- load()方法默认采用延迟加载策略(懒加载),get()方法采用立即检索策略(eager)。
集合类型映射:
- Set无序,元素不可重复
- List有序,元素可重复
- Bag无序,元素可重复
- Map键值对
检索策略:
一、检索策略属性: Lazy
- Lazy: true(默认) 延迟检索;set端一对多;
- Lazy: false 立即检索;set 端 一对多;
- Lazy: extra 增强延迟检索;set端一对多;
- Lazy: proxy(默认) 延迟检索;many-to-one多对一;
- Lazy:no-proxy 无代理延迟检索;many-to-one多对一(需要编译时字节码增强);
二、检索策略属性: batch-size
- 批量延迟检索;
- 批量立即检索;
三、检索策略属性: Fetch
- Fetch: select(默认)查询方式
- Fetch: subselect子查询方式
- Fetch: join迫切左外连接查询方式
Hibernate查询方式:
- 导航对象图查询方式(级联)
- OID查询方式(get()方法和load()方法)
- 本地SQL查询方式 (数据库的语法)
- HQL查询方式(面向对象)
HQL(Hibernate Query Language)是面向对象的查询语言,是使用最广的一种查询方式。
普通查询
带条件查询
使用别名
对结果排序
分页查询
查询单个对象
链式写法 - QBC查询方式(Query By Criteria)
QBC查询方式(Query By Criteria)是用一套接口来实现的查询方式。
普通查询
带条件查询
对结果排序
分页查询
查询单个对象
链式写法
配置Hibernate缓存:
一、缓存的概念:
缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存或者硬盘中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。Hibernate在进行读取数据的时候根据缓存机制在相应的缓存中查询如果在缓存中找到了需要的数据(我们把这称做”缓存命中”),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。
二、Hibernate缓存的分类:
- Session缓存(又称作事务缓存): Hibernate内置的,不能卸除。 缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。一级缓存只适用于同一事物中。
- SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。缓存被应用范围内的所有session共享,不同的Session可以共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。
三、二级缓存策略提供商:
提供了HashTable缓存,EHCache、OSCache、SwarmCache、jBoss Cathe2,这些缓存机制,其中EHCache、OSCache 是不能用于集群环境(Cluster Safe)的,而 SwarmCache,jBoss Cathe2 是可以的。
HashTable缓存主要是用来测试的,只能把对象放在内存中,EHCache、OSCache可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)(为什么放到硬盘上?上面解释了)。
四、什么数据适合放二级缓存中?
- 经常被访问
- 改动不大
- 数量有限
- 不是很重要的数据,允许出现偶尔并发的数据。比如组织机构代码,列表信息等。
五、配置EHCache二级缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<ehcache> <!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个目录下 --> <diskStore path="c:\\glorze"/> <!-- 设置缓存的默认数据过期策略 name 设置缓存的名字,他的取值为类的完整名字或者类的集合的名字; maxElementsInMemory 设置基于内存的缓存可存放的对象的最大数目 eternal 如果为true,表示对象永远不会过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds,默认为false; timeToIdleSeconds 设定允许对象处于空闲状态的最长时间,以秒为单位; timeToLiveSeconds 设定对象允许存在于缓存中的最长时间,以秒为单位; overflowToDisk 如果为true,表示当基于内存的缓存中的对象数目达到maxElementsInMemory界限,会把溢出的对象写到基于硬盘的缓存中; --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!-- 设定具体的第二级缓存的数据过期策略 --> <cache name="com.glorze.model.Class" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> </ehcache> |
更博不易,如果觉得文章对你有帮助并且有能力的老铁烦请赞助盒烟钱,点我去赞助。或者扫描文章下面的微信/支付宝二维码打赏任意金额,老四这里抱拳了。赞助时请备注姓名或者昵称,因为您的署名会出现在赞赏列表页面,您的赞赏钱财也会被用于小站的服务器运维上面,再次抱拳。