Hibernate 学习(三)
一、关系映射
实体类之间的关联映射以及表之间的关系是 ORM 的灵魂之处。对象间的关系的子集可以用下列四种方式解释。关联映射可以是单向的也可以是双向的。
| 映射类型 | 描述 |
|---|---|
| Many-to-One | 使用 Hibernate 映射多对一关系 |
| One-to-One | 使用 Hibernate 映射一对一关系 |
| One-to-Many | 使用 Hibernate 映射一对多关系 |
| Many-to-Many | 使用 Hibernate 映射多对多关系 |
1、多对一
1、映射文件 Product.hbm.xml 配置:
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--映射文件-->
<hibernate-mapping package="com.hibernate.pojo">
<!--class表示一个由hibernate管理的持久对象,对应数据库中一个表-->
<!--table数据库的表名-->
<!--一方-->
<class name="ProductDir" table="product_dir">
<id name="id" type="int" column="id">
<!--generator表示主键的生成方式,native自动选择数据库本地的策略-->
<generator class="native"/>
</id>
<!--非主键属性-->
<property name="dirNum" column="num" type="string"/>
<property name="dirName" column="name" type="string"/>
</class> <!--多方-->
<class name="Product" table="product">
<id name="id" type="int" column="id">
<!--generator表示主键的生成方式,native自动选择数据库本地的策略-->
<generator class="native"/>
</id>
<!--非主键属性-->
<property name="name" column="name" type="string"/>
<property name="price" column="price" type="float"/> <!--多Product对一ProductDir-->
<many-to-one name="dir" class="ProductDir" column="dir_id"/>
</class>
</hibernate-mapping>
2、pojo设计:
1、多方
package com.hibernate.pojo; /**
* @author zt1994 2018/3/6 14:16
*/
public class Product {
private Integer id;
private String name;
private float price;
private ProductDir dir; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public float getPrice() {
return price;
} public void setPrice(float price) {
this.price = price;
} public ProductDir getDir() {
return dir;
} public void setDir(ProductDir dir) {
this.dir = dir;
}
}
2、一方
package com.hibernate.pojo; /**
* @author zt1994 2018/3/7 15:23
*/
public class ProductDir {
private Integer id;
private String dirNum;
private String dirName; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getDirNum() {
return dirNum;
} public void setDirNum(String dirNum) {
this.dirNum = dirNum;
} public String getDirName() {
return dirName;
} public void setDirName(String dirName) {
this.dirName = dirName;
}
}
3、数据库设计:
1、product 表

2、product_dir 表

4、查询测试
/**
* 测试多对一 查询
*/
@Test
public void testManyToOneQuery(){
//1.获取session
Session session = HibernateUtil.getSession();
Transaction transaction = null;
try {
//2.开启事务
transaction = session.getTransaction();
transaction.begin();
//3.操作CRUD
String hql = "select o from com.hibernate.pojo.Product o";
Query query = session.createQuery(hql);
List<Product> list = query.list();
for (Product product : list) {
System.out.println(product.getDir().getDirName());
}
//4.提交事务
transaction.commit();
} catch (Exception e) {
if (transaction != null) transaction.rollback(); //回滚
e.printStackTrace();
} finally {
//5.关闭资源
session.close();
}
}
5、保存测试
/**
* 保存测试
*/
@Test
public void testManyToOneSave(){
//1.获取session
Session session = HibernateUtil.getSession();
Transaction transaction = null;
try {
//2.开启事务
transaction = session.getTransaction();
transaction.begin();
//3.操作CRUD
//一方(产品类型)
ProductDir productDir = new ProductDir();
productDir.setDirName("类型4"); //多方(产品1)
Product product1 = new Product();
//建立联系
product1.setDir(productDir);
product1.setName("产品1");
//多方(产品2)
Product product2 = new Product();
//建立联系
product2.setDir(productDir);
product2.setName("产品2"); //保存一方产品类型
session.save(productDir);
//保存多方产品1,2
session.save(product1);
session.save(product2); //4.提交事务
transaction.commit();
} catch (Exception e) {
if (transaction != null) transaction.rollback(); //回滚
e.printStackTrace();
} finally {
//5.关闭资源
session.close();
}
}
控制台输出:

注意:如果先保存产品后保存产品类型,控制台输出不一样,

控制台输出:

实际情况,我们先把类型分好,然后进货的时候就直接可以分类。但是如果相反的话,我们就要先进货,再分类型,再把货放到相应类型中去。
2、一对多
1、映射文件 Product.hbm.xml 配置:
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--映射文件-->
<hibernate-mapping package="com.hibernate.pojo">
<!--class表示一个由hibernate管理的持久对象,对应数据库中一个表-->
<!--table数据库的表名-->
<!--一方-->
<class name="ProductDir" table="product_dir">
<id name="id" type="int" column="id">
<!--generator表示主键的生成方式,native自动选择数据库本地的策略-->
<generator class="native"/>
</id>
<!--非主键属性-->
<property name="dirNum" column="num" type="string"/>
<property name="dirName" column="name" type="string"/> <set name="products">
<key column="dir_id"/>
<one-to-many class="Product"/>
</set>
</class> <!--多方-->
<class name="Product" table="product">
<id name="id" type="int" column="id">
<!--generator表示主键的生成方式,native自动选择数据库本地的策略-->
<generator class="native"/>
</id>
<!--非主键属性-->
<property name="name" column="name" type="string"/>
<property name="price" column="price" type="float"/>
</class>
</hibernate-mapping>
2、pojo 设计:
package com.hibernate.pojo; import java.util.HashSet;
import java.util.Set; /**
* @author zt1994 2018/3/7 15:23
*/
public class ProductDir {
private Integer id;
private String dirNum;
private String dirName;
private Set<Product> products = new HashSet<>(); //产品集合 public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getDirNum() {
return dirNum;
} public void setDirNum(String dirNum) {
this.dirNum = dirNum;
} public String getDirName() {
return dirName;
} public void setDirName(String dirName) {
this.dirName = dirName;
} public Set<Product> getProducts() {
return products;
} public void setProducts(Set<Product> products) {
this.products = products;
}
}
3、测试一对多查询
/**
* 测试一对多保存
*/
@Test
public void testOneToManySave(){
//1.获取session
Session session = HibernateUtil.getSession();
Transaction transaction = null;
try {
//2.开启事务
transaction = session.getTransaction();
transaction.begin();
//3.操作CRUD
//一方(产品类型)
ProductDir productDir = new ProductDir();
productDir.setDirName("类型4"); //多方(产品1)
Product product1 = new Product();
product1.setName("产品1");
//多方(产品2)
Product product2 = new Product();
product2.setName("产品2"); //建立关系(只能由一方建立多方关系)
productDir.getProducts().add(product1);
productDir.getProducts().add(product2); //保存一方产品类型
session.save(productDir);
//保存多方产品1,2
session.save(product1);
session.save(product2);
//4.提交事务
transaction.commit();
} catch (Exception e) {
if (transaction != null) transaction.rollback(); //回滚
e.printStackTrace();
} finally {
//5.关闭资源
session.close();
}
}
二、二级缓存
第二级缓存是一种可选择的缓存并且第一级缓存在任何想要在第二级缓存中找到一个对象前将总是被询问。第二级缓存可以在每一个类和每一个集合的基础上被安装,并且它主要负责跨会话缓存对象。
任何第三方缓存可以和 Hibernate 一起使用。org.hibernate.cache.CacheProvider 接口被提供,它必须实现来给 Hibernate 提供一个缓存实现的解决方法。
1、并发策略
一个并发策略是一个中介,它负责保存缓存中的数据项和从缓存中检索它们。如果你将使用一个二级缓存,你必须决定,对于每一个持久类和集合,使用哪一个并发策略。
- Transactional:为主读数据使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
- Read-write:为主读数据再一次使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
- Nonstrict-read-write:这个策略不保证缓存和数据库之间的一致性。如果数据几乎不改变并且过期数据不是很重要,使用这个策略。
- Read-only:一个适合永不改变数据的并发策略。只为参考数据使用它。
2、配置二级缓存
1、拷贝 jar 包

2、配置Hibernate.cfg.xml文件
1、开启二级缓存
hibernate.cache.use_second_level_cache=true
2、添加一个二级缓存的供应商(实现类)
hibernate4的配置:hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
hibernate3的配置:hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
3、开启查询缓存
hibernate.cache.use_query_cache=true
4、配置那个 domain 需要二级缓存(最好添加在映射文件后)
<class-cache class="com.hibernate.day01.model.Product" usage="read-write" />
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!--hibernate核心配置文件-->
<hibernate-configuration>
<session-factory>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!--链接池配置-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/how2java</property>
<property name="connection.username">root</property>
<property name="connection.password">admin</property>
<!--显示sql语句-->
<property name="show_sql">true</property> <!--开启二级缓存-->
<property name="cache.use_second_level_cache">true</property> <!--添加一个二级缓存的供应商(实现类)-->
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property> <!--开启查询缓存-->
<property name="hibernate.cache.use_query_cache">true</property> <!-- 映射文件-->
<mapping resource="mapper/Product.hbm.xml"/> <!--配置那个domain需要二级缓存(最好添加在映射文件后)-->
<class-cache class="com.hibernate.pojo.Product" usage="read-write" />
</session-factory>
</hibernate-configuration>
3、测试二级缓存
/**
* 测试二级缓存
*/
@Test
public void testSecondLevelCache(){
//1.获取session
Session session = HibernateUtil.getSession();
//2.开启事务
Transaction transaction = session.getTransaction();
transaction.begin();
//3.操作CRUD
Product product1 = (Product) session.get(Product.class, 1); //一、二级缓存都没有命中
System.out.println(product1.hashCode());
Product product2 = (Product) session.get(Product.class, 1); //一级缓存命中
System.out.println(product2.hashCode());
session.close(); Session session2 = HibernateUtil.getSession();
Product product3 = (Product) session2.get(Product.class, 1); //二级缓存命中
System.out.println(product3.hashCode());
Product product4 = (Product) session2.get(Product.class, 1); //一级缓存命中
System.out.println(product4.hashCode()); //4.提交事务
transaction.commit();
//5.关闭资源
session2.close();
}
}
控制台输出:

分析:
第一次 get 操作获取到 product1 时,一级,二级缓存都没有,所有发送 SQL 语句查询,并保存到一级缓存和二级缓存中;
第二次 get 操作直接从一级缓存获取数据,所有两个对象的 hashCode 相同;
第三次 get 操作时,由于前一个 session 被关闭了,所有没有一级缓存,只有从二级缓存中获取数据,并保存到新session中;
第四次 get 操作时,直接从 session 的一级缓存中获取数据,hashCode 和 product3 的 hashCode 相同。
Hibernate 学习(三)的更多相关文章
- hibernate学习三(使用Annotation,注解)
一.新建一个工程hibernate_02_HelloWorld_Annotation(复制01工程并重命名); 二.新建一个实体类teacher.java,数据库中新建teacher表; import ...
- hibernate学习(三) hibernate中的对象状态
hibernate对象的状态分为三种: 游离状态,持久化状态,瞬时状态 下面一行代码区分: Configuration cfg=new Configuration().configure(); ...
- Hibernate学习(三)自动建表
一般情况下有如下两种方法: 1.在配置文件中添加如下配置 <property name="hibernate.hbm2ddl.auto">create</prop ...
- Hibernate学习三----------session详解
© 版权声明:本文为博主原创文章,转载请注明出处 如何获取session对象 1. openSession 2. getCurrentSession - 如果使用getCurrentSession需要 ...
- hibernate学习三 精解Hibernate之核心文件
一 hibernate.cfg.xml详解 1 JDBC连接: 2 配置C3P0连接池: 3 配置JNDI数据源: 4 可选的配置属性: 5 hibernate二级缓存属性 6 hibernate事务 ...
- Hibernate学习2--对象的三种状态以及映射关系的简单配置
上篇hibernate的博客总体简单梳理了对象持久化的一些思想以及hibernate中对象持久化化的方法,下面说说对象持久化过程的三种状态. 一.hibernate缓存的概念 1.session与缓存 ...
- Hibernate学习之——搭建log4j日志环境
昨天讲了Hibernate开发环境的搭建以及实现一个Hibernate的基础示例,但是你会发现运行输出只有sql语句,很多输出信息都看不见.这是因为用到的是slf4j-nop-1.6.1.jar的实现 ...
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- [原创]java WEB学习笔记88:Hibernate学习之路-- -Hibernate检索策略(立即检索,延迟检索,迫切左外连接检索)
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记87:Hibernate学习之路-- -映射 继承关系(subclass , joined-subclass,union-subclass )
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- Windows便签快捷键
Win+R 是运行的快捷件打 StikyNot 回车 快捷键 功能Ctrl+N 新建一张便笺Ctrl+D 删除当前便笺Ctrl+E 居中对齐Ctrl+R 右对齐Ctrl+J 左对齐Ctrl+I 斜体C ...
- [Flex] 组件Tree系列 —— 利用firstVisibleItem属性,设置或取得第一个显示节点
mxml: <?xml version="1.0" encoding="utf-8"?> <!--功能描述: 利用firstVisibleIt ...
- [ActionScript 3.0] 如何获得实例对象的类名及类
package { import flash.display.DisplayObject; import flash.display.MovieClip; import flash.display.S ...
- shell__常用命令__grep
grep | zgrep (不用解压zip就能直接搜索) -i 不区分大小写 -I 忽略二进制文件 -R或r 递归文件目录 -c 计算找到的总数量 -n 显示行号 -v 显示不包含匹配文本的所有行 - ...
- ubuntu14.04部署kickstart
转自:http://www.mamicode.com/info-detail-1646465.html kickstart用于在内网自动安装系统. 使用pxe安装系统需要安装dhcp,tftp,htt ...
- php-elasticsearch bulk批量插入数据
1.单条插入 <?php include '../vendor/Elasticsearch/autoload.php'; $a['hosts'] = array( #需要用户名时 http:// ...
- vue中vueRouter使用
首先需要安装依赖:
- &与&& ,|与||的区别
&&和||是短路运算符,&和|是非短路运算符 &&与& 区别:两者都表示“与”运算,但是&&运算符第一个表达式不成立的话,后面的表达式不 ...
- 899. Orderly Queue
A string S of lowercase letters is given. Then, we may make any number of moves. In each move, we c ...
- 在 Linux 服务器上部署 nginx 之后不能访问
原文地址:https://blog.csdn.net/lipeigang1109/article/details/73295373 解决办法:https://jingyan.baidu.com/art ...