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 )
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~
title: swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~description: 阅读 sowft 框架源码, swoft 第一步, ...
- 如何在linux上安装使用virt-manager
环境是centos6.5-64位操作系统. 1.准备yum源: 将CentOS6-Base-163.repo 下载到目标主机的/etc/yum.repos.d/目录. cd /etc/yum.repo ...
- bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...
- [Swift实际操作]八、实用进阶-(4)通过protocol在两个对象中进行消息传递
本文将演示如何借助协议,实现视图控制器对象和其内部的自定义视图对象之间的数据传递. 首先创建一个自定义视图对象.在项目名称文件夹点击鼠标右键New File ->Cocoa Touch Clas ...
- Linux 下 SSH 远程超时解决方案
Linux 下 SSH 远程超时解决方案 今天突然看到一个问题说是如何解决SSH远程超时的问题. 找了一点资料.用于解决这个需求~ 第一种:OpenSSH 配置文件设置 位于112行的 "C ...
- ubuntu下搭建Discuz
环境:我用桥接方式创建了一个ubuntu16的虚拟机,ip为192.168.0.220 1.安装mysql sudo apt-get install mysql-server mysql-cl ...
- Ionic——下一代 APP 开发框架
http://www.tuicool.com/articles/iY3ENvY 最近 Facebook React 团队释出了 React Native, 用来构建 Mobile Native 应用. ...
- python 数据分析 文章集锦
文本分析: re&jieba模块 使用 正则表达式 和 中文处理模块jieba 原文地址:https://www.cnblogs.com/minutesheep/p/10357209.htm ...
- Hibernate入门教程
Hibernate 随心所欲的使用面向对象思想操纵数据库. Table of contents 介绍 搭建开发环境 半sql半面向对象写法 完全的sql写法 完全的面向对象写法 Hibernate H ...
- Flume启动运行时报错org.apache.flume.ChannelFullException: Space for commit to queue couldn't be acquired. Sinks are likely not keeping up with sources, or the buffer size is too tight解决办法(图文详解)
前期博客 Flume自定义拦截器(Interceptors)或自带拦截器时的一些经验技巧总结(图文详解) 问题详情 启动agent服务 [hadoop@master flume-1.7.0]$ ...