1、分为两部分:
①类级别检索策略,大概了解检索策略(代码所在包com.demo.sshtest)
②检索策略的lazy、fetch、batch-size属性使用(代码所在包com.demo.sshtest2)
2、检索策略:
①立即检索,立即加载检索方法指定的对象
②延迟检索,延迟加载检索方法指定的对象,在使用具体属性值时,才进行加载(这个时候会执行查询语句)
3、检索策略使用场景:
①如果加载对象是为了访问他的属性,则使用立即加载
②如果加载对象目的是为了获得他的应用,则可以使用延迟加载
4、检索策略属性:
①lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
②fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若取值为”join”, 则决定 orders 集合被初始化的时机,若把 fetch 设置为 “join”, lazy 属性将被忽略
③batch-size:批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
5、一对多和多对多的检索策略,lazy和fetch取值对应策略
①lazy=true ——– fatch=默认 ——– 采用延迟检索
②lazy=false ——– fatch=默认 ——– 采用立即检索
③lazy=extra ——– fatch=默认 ——– 采用加强延迟检索(延迟对象集合初始化时机)
④lazy=true/false/extra ——– fatch=默认 ——– 根据lazy决定执行检索策略
⑤lazy=true/false/extra ——– fatch=subselect ——– 根据lazy决定执行检索策略
⑥lazy=默认 ——– fatch=join ——– 采用迫切左外连接策略
6、多对一和一对一的检索策略,lazy和fetch取值对应策略
①lazy=proxy ——– fetch=默认 ——– 采用延迟检索
②lazy=non-proxy ——– fetch=默认 ——– 采用无代理延迟检索(需要增强持久化类的字节码才能实现)
③lazy=false ——– fetch=默认 ——– 采用立即检索
④lazy=默认 ——– fetch=join ——– 采用迫切左外连接策略(比立即检索用更少select语句)
7、类级别检索策略
(1)Customer.java “一”端(因为关系配置有用set)
package com.demo.sshtest;
import java.util.HashSet;
import java.util.Set;
public class Customer {
public Integer Id;
public String cName;
public Set<Merchant>merchant = new HashSet<>();
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
public String getcName() {
return cName;
}
public void setcName(String cName) {
this.cName = cName;
}
public Set<Merchant> getMerchant() {
return merchant;
}
public void setMerchant(Set<Merchant> merchant) {
this.merchant = merchant;
}
}
(2)Merchant.java “多”端
package com.demo.sshtest;
public class Merchant {
public Integer merId;
public String merName;
public Integer getMerId() {
return merId;
}
public void setMerId(Integer merId) {
this.merId = merId;
}
public String getMerName() {
return merName;
}
public void setMerName(String merName) {
this.merName = merName;
}
}
(3)Customer.hbm.xml 多端映射关系配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:01:32 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.demo.sshtest.Customer" table="CUSTOMER" lazy="true">
<id name="Id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="cName" type="java.lang.String" access="field">
<column name="CNAME" />
</property>
<set name="merchant" table="MERCHANT" cascade="save-update" order-by="ID DESC">
<key>
<column name="ID" />
</key>
<one-to-many class="com.demo.sshtest.Merchant" />
</set>
</class>
</hibernate-mapping>
(4)Merchant.hbm.xml “一”端映射关系配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:02:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.demo.sshtest.Merchant" table="MERCHANT">
<id name="merId" type="java.lang.Integer">
<column name="MERID" />
<generator class="native" />
</id>
<property name="merName" type="java.lang.String">
<column name="MERNAME" />
</property>
</class>
</hibernate-mapping>
(5)TestOne2Many.java 测试类
package com.demo.sshtest;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestOne2Many {
//类级别检索策略:
//①立即检索,立即加载检索方法指定的对象
//②延迟检索,延迟加载检索方法指定的对象,在使用具体属性值时,才进行加载(这个时候会执行查询语句)
//使用场景:
//①如果加载对象是为了访问他的属性,则使用立即加载
//②如果加载对象目的是为了获得他的应用,则可以使用延迟加载
//注意事项:
//①注意使用懒加载的时候要保证session没有关闭,否则会出现懒加载异常
//②class的lazy属性仅对session的load()方法有效
//③但lazy是默认或者true时,load()不会运行sql,只会代理对象实例(仅初始化其 OID 属性)
//④在上一点的情况下,应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例(这个时候会执行查询语句)
//步骤:
//在映射关系配置文件中,class标签后修改lazy值
//延迟检索/延迟加载:lazy="true"或默认情况下 :class com.demo.sshtest.Customer_$$_javassist_1 拿到的是代理对象
//立即检索/立即加载:lazy="false"的情况下 :class com.demo.sshtest.Customer 拿到了对象
public SessionFactory sessionFactory;
public Session session;
public Transaction transaction;
@Before
public void init(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
transaction = session.beginTransaction();
System.out.println("init");
}
@After
public void destory(){
transaction.commit();
session.close();
sessionFactory.close();
System.out.println("destory");
}
@Test
public void test() throws Exception{
System.out.println("test");
Customer customer = new Customer();
customer.setcName("cccName");
Merchant merchant1 = new Merchant();
Merchant merchant2 = new Merchant();
merchant1.setMerName("merchant1");
merchant2.setMerName("merchant2");
customer.getMerchant().add(merchant1);
customer.getMerchant().add(merchant2);
session.save(customer);
session.save(merchant1);
session.save(merchant2);
}
@Test
public void testquery(){
System.out.println("testquery");
Customer customer = (Customer)session.load(Customer.class,1);
System.out.println(customer.getClass());
System.out.println(customer.getId());
System.out.println(customer.getcName());
}
}
8、检索策略的lazy、fetch、batch-size属性使用
(1)Customer.java “一”端(因为关系配置有用set)
package com.demo.sshtest;
import java.util.HashSet;
import java.util.Set;
public class Customer {
public Integer Id;
public String cName;
public Set<Merchant>merchant = new HashSet<>();
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
public String getcName() {
return cName;
}
public void setcName(String cName) {
this.cName = cName;
}
public Set<Merchant> getMerchant() {
return merchant;
}
public void setMerchant(Set<Merchant> merchant) {
this.merchant = merchant;
}
}
(2)Merchant.java “多”端
package com.demo.sshtest;
public class Merchant {
public Integer merId;
public String merName;
public Integer getMerId() {
return merId;
}
public void setMerId(Integer merId) {
this.merId = merId;
}
public String getMerName() {
return merName;
}
public void setMerName(String merName) {
this.merName = merName;
}
}
(3)Customer2.hbm.xml “多”端关系映射配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:01:32 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.demo.sshtest2.Customer2" table="CUSTOMER2">
<id name="Id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="cName" type="java.lang.String" access="field">
<column name="CNAME" />
</property>
<set name="merchant" table="MERCHANT2" inverse="true" lazy="true" batch-size="5" fetch="join">
<key>
<column name="ID" />
</key>
<one-to-many class="com.demo.sshtest2.Merchant2" />
</set>
</class>
</hibernate-mapping>
这里面fetch的值 按照测试需要 可以改成select、subselect或者join
(4)Merchant2.hbm.xml “一”端映射关系配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:02:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.demo.sshtest2.Merchant2" table="MERCHANT2">
<id name="merId" type="java.lang.Integer">
<column name="MERID" />
<generator class="native" />
</id>
<property name="merName" type="java.lang.String">
<column name="MERNAME" />
</property>
</class>
</hibernate-mapping>
(5)TestOne2Many.java 测试类
package com.demo.sshtest2;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestOne2Many {
//一对多和多对多的检索策略
//set标签中对应属性用法:
//①lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
//②fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若取值为”join”, 则决定 orders 集合被初始化的时机
// 若把 fetch 设置为 “join”, lazy 属性将被忽略
//③batch-size:批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
//(1)lazy:
//1、一对多或者多对多的集合属性默认使用懒加载检索策略
//2、可以通过设置set的lazy属性修改检索策略,默认true
//3、set的lazy属性不建议设为false,sql语句翻倍,减慢效率
//4、lazy还可以设为extra(增强延迟检索),该取值会尽可能延迟集合初始化时机,就是能不初始化就不初始化,直接执行sql
//5、如果lazy是true、extra、默认的时候,要对集合的某个代理对象进行初始化,显式调用Hibernate.initialize即可
//(2)batch-size:
//1、是在使用懒加载(lazy="true"或者默认或者extra)情况下使用
//2、作用:用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
//3、使用:去set那里设置batch-size的值,数值未多少,一次性初始化set集合的对象的数量就是多少
//(3)fetch:
//1、fetch属性值的取值是select和subselect时,决定初始化对象的时候的查询语句形式
//2、fetch属性值的取值是join时,决定对象集合被初始化时机
//3、set集合的fetch属性:
//①默认为select,通过正常方式初始化set元素
//②取值为subselect时,通过子查询方式初始化所有set集合,子查询在where子句的in出现,查询所有该端的主键(ID),lazy有效,batch-size无效
//③取值为join时,检索对象时,才有迫切左外连接策略检查关联的对象,lazy无效(注意:Query.list()会忽略映射配置中的迫切左外连接检索策略,会用延迟加载策略)
//一对多和多对多的检索策略
//lazy属性和fetch属性取值对应检索策略
//1、lazy取值可以为true、false、extra(默认true),fetch取值为select、subselect、join(默认select)
//①lazy=true fatch=默认 采用延迟检索
//②lazy=false fatch=默认 采用立即检索
//③lazy=extra fatch=默认 采用加强延迟检索(延迟对象集合初始化时机)
//④lazy=true/false/extra fatch=默认 根据lazy决定执行检索策略
//⑤lazy=true/false/extra fatch=subselect 根据lazy决定执行检索策略
//⑥lazy=默认 fatch=join 采用迫切左外连接策略
//多对一和一对一的检索策略
//1、lazy取值可以为proxy、no-proxy、false(默认proxy),fetch取值可以为:select和join(默认select)
//2、lazy取值为proxy和false分别代表采用延迟检索和立即检索
//3、batch-size,设置在“一”端的class元素中,而不是像一对多、多对多的检索策略那样设置在set里面
//4、如果fetch取值join时,lazy无效
//5、lazy属性和fetch属性取值对应检索策略
//①lazy=proxy fetch=默认 采用延迟检索
//②lazy=non-proxy fetch=默认 采用无代理延迟检索(需要增强持久化类的字节码才能实现)
//③lazy=false fetch=默认 采用立即检索
//④lazy=默认 fetch=join 采用迫切左外连接策略(比立即检索用更少select语句)
public SessionFactory sessionFactory;
public Session session;
public Transaction transaction;
@Before
public void init(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
transaction = session.beginTransaction();
System.out.println("init");
}
@After
public void destory(){
transaction.commit();
session.close();
sessionFactory.close();
System.out.println("destory");
}
@Test
public void test() throws Exception{
System.out.println("test");
Customer2 customer = new Customer2();
customer.setcName("cccName");
Merchant2 merchant1 = new Merchant2();
Merchant2 merchant2 = new Merchant2();
merchant1.setMerName("merchant1");
merchant2.setMerName("merchant2");
customer.getMerchant().add(merchant1);
customer.getMerchant().add(merchant2);
session.save(customer);
session.save(merchant1);
session.save(merchant2);
}
@Test
public void testquery(){
System.out.println("testquery");
Customer2 customer = (Customer2)session.get(Customer2.class,1);
System.out.println(customer.getcName());
System.out.println(customer.getMerchant().getClass());
Merchant2 merchant2 = new Merchant2();
merchant2.setMerId(1);
System.out.println(customer.getMerchant().contains(merchant2));
//如果懒加载的时候,要对集合的某个代理对象进行初始化,显式调用Hibernate.initialize即可
Hibernate.initialize(customer.getMerchant());
}
@Test
public void testBatchSize(){
List<Customer2> customer2 = session.createQuery("FROM Customer2").list();
System.out.println(customer2.size());
for(Customer2 customer22 :customer2){
//使用懒加载(lazy="true"或者默认或者extra)时,如果不设置batch-size 这里每次检查customer22.getMerchant()是不是为空的时候 ,需要查询4次
//所以需要批量对customer22.getMerchant()对象初始化
//去set那里设置batch-size,就可以了
//作用:用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
if(customer22.getMerchant()!=null){
System.out.println(customer22.getMerchant().size());
}
}
}
@Test
public void testFetch(){
List<Customer2> customer2 = session.createQuery("FROM Customer2").list();
System.out.println(customer2.size());
for(Customer2 customer22 :customer2){
//fetch属性值的取值是select和subselect时,决定初始化对象的时候的查询语句形式
//set集合的fetch属性:
//1、默认为select,通过正常方式初始化set元素
//2、取值为subselect时,通过子查询方式初始化所有set集合,子查询在where子句的in出现,查询所有该端的主键(ID),lazy有效,batch-size无效
if(customer22.getMerchant()!=null){
System.out.println(customer22.getMerchant().size());
}
}
}
@Test
public void testFetch2(){
//fetch属性值的取值是join时,决定对象集合被初始化时机
//set集合的fetch属性:
//1、取值为join时,检索对象时,才有迫切左外连接策略检查关联的对象(查询端的另一端)
//2、迫切左外链接就是指:使用左外链接查询,且把集合属性进行初始化
//3、当fetch值为join时,lazy属性会无效(注意:Query.list()会忽略映射配置中的迫切左外连接检索策略,会用延迟加载策略)
//4、HQL查询时,忽略fetch=join的取值
Customer2 customer2 = (Customer2)session.get(Customer2.class, 1);
System.out.println(customer2.getMerchant().size());
}
}
9、hibernate.cfg.xml hibernate配置文件
<?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-configuration>
<session-factory>
<!-- 配置连接数据库基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- localhost是地址,如果用默认可以不写localhost,hebernateTEST是数据库名 -->
<property name="connection.url">jdbc:mysql://localhost/hebernateTEST</property>
<!-- 配置hibernate基本信息-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 执行操作室是否在控制台打印sql -->
<property name="show_sql">true</property>
<!-- 是否对sql格式化 -->
<property name="format_sql">true</property>
<!-- 指定自动生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 设置 Hibernate 的事务隔离级别 -->
<property name="connection.isolation">2</property>
<!-- 设置调用delete()时,OID变成null -->
<property name="hibernate.use_identifier_rollback">true</property>
<!--C3P0 数据库连接池-->
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">2000</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.idle_test_period">2000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<!--设定JDBC的statement读取数据-->
<property name="hibernate.jdbc.fetch_size">100</property>
<property name="hibernate.jdbc.batch_size">50</property>
<!-- 指定关联的 *.hbm.xml文件(目录结构) 每个.hbm.xml对应一个数据表-->
<mapping resource="com/demo/sshtest/Customer.hbm.xml"/>
<mapping resource="com/demo/sshtest/Merchant.hbm.xml"/>
<mapping resource="com/demo/sshtest2/Customer2.hbm.xml"/>
<mapping resource="com/demo/sshtest2/Merchant2.hbm.xml"/>
</session-factory>
</hibernate-configuration>
9、注意事项:
(1)注意多对一和一对一的时候lazy可选的值比一对多和多对多的时候多了proxy和non-proxy
(2)其实没什么需要在这里写的,用法和注意事项都写到注释里面去了,注意测试类的注释就好了
10、项目目录
11、demo
https://download.csdn.net/download/qq_22778717/10359603