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 )
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- log4j日志+面向切面监控异常
log4j.xml src/main/resources ----------------------------------------------------------------------- ...
- CF666E Forensic Examination(后缀自动机+动态线段树)
题意 给你一个串 $S$ 以及一个字符串数组 $T[1..m]$ , $q$ 次询问,每次问 $S$ 的子串 $S[p_l..p_r]$ 在 $T[l..r]$ 中的哪个串里的出现次数最多,并输出出现 ...
- php与java的差异
http://zhidao.baidu.com/link?url=kd-eulWPoygRlMKeBxdCn3QA4bLJXYVSc_mUGPgWg05az8RIqu3r1GmRnmXZ4UMaR6y ...
- 7,CountDownLatch 与 CyclicBarrier 的 区别
CountDownLatch : 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 用给定的计数 初始化 CountDownLatch.由于调用了 countDo ...
- jquery事件三 -- load(), ready(), resize()以及bind()事件
例子1 ready() DOM加载完毕 load() 元素加载完毕 resize() 浏览器窗口的大小发生变化 <!DOCTYPE html> <html lang="en ...
- Python 标准库之 xml.etree.ElementTree
Python 标准库之 xml.etree.ElementTree Python中有多种xml处理API,常用的有xml.dom.*模块.xml.sax.*模块.xml.parser.expat模块和 ...
- 如何调用另一个包中的Application
在项目中要集成Xabber,将它作为一个Lib, ..... Xabber 原有代码 /** * Base entry point. * * @author alexander.ivanov */ p ...
- linux开机、重启和用户登陆注销
关机&重启命令 基本介绍: shutdown –h now 立该进行关机 shudown -h 1 "hello, 1 分钟后会关机了" shutdown –r no ...
- bootstrap table 超链接的添加 <a>标签
后台管理页面采用 bootstrap table 页面样式: 现在需要在操作中添加一个<a>标签,跳转到不同的页面 { title: '操作', align: 'center', form ...
- Go语言介绍
Go语言简介 Go语言是谷歌2009发布的第二款开源编程语言. Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程. Go ...