一、框架的概述
1.什么是框架
框架:指的是软件的半成品,已经完成了部分功能。
2.JavaEE的三层架构
二、Hibernate概述
1.什么是Hibernate
Hibernate是持久层的一个ORM(Object Relational Mapping)框架。
2.ORM
ORM:对象关系映射。指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。
3.Hibernate的优势
4.Hibernate入门
(1)下载Hibernate
https://sourceforge.net/projects/hibernate/files/hibernate-orm
(2)Hibernate文件结构
(3)创建Hibernate
①.创建Java Project导入下列jar包
②.创建数据库表以及对应的实体类
package pers.zx.hibernate.demo;
public class Customer {
private long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
public long getCust_id() {
return cust_id;
}
public void setCust_id(long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
}
③.编写映射文件:命名方式(实体类名.hbm.xml)
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立类与表的映射 -->
<class name="pers.zx.hibernate.demo.Customer" table="cst_customer">
<!-- 建立类中属性与表的主键对应 -->
<id name="cust_id" column="cust_id">
<generator class="native" />
</id>
<!-- 建立类中的普通的属性和表的字段的应对 -->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
④.编写hibernate核心配置文件,配置数据库连接以及与映射文件的关联
hibernate.cfg.xml
<?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="hibernate.connection.driver.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">19960213zx.</property>
<!-- 配置hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 可选配置 -->
<!-- 打印SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<mapping resource="pers/zx/hibernate/demo/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
⑤.编写测试代码
public class Hibernate01 {
public static void main(String[] args) {
//1.加载Hibernate的核心配置文件
Configuration configuration=new Configuration();
configuration.configure();//多读一次hibernate.cfg.xml配置
//2.创建一个SessionFactory获取到Session对象:类似于JDBC中的连接池
SessionFactory sessionFactory=configuration.buildSessionFactory();
//3.通过SessionFactory获取到Session对象:类似于JDBC中的Connection
Session session=sessionFactory.openSession();
//4.手动开启事务
Transaction transaction=session.beginTransaction();
//5.编写代码
Customer customer=new Customer();
customer.setCust_name("zx");
session.save(customer);
//6.提交事务
transaction.commit();
//7.资源释放
session.close();
}
}
5.Hibernate的常见配置
1.配置XML提示
目的:是在编写XML文件的时候会有自动提示
步骤:在eclipse中,选择windows–>prefernces–>搜索XML–>选择XML Catalog
然后点击User Specified Entries–>Add
在1中选择需要添加的.dtd文件的位置,2中选择URI,3中填写链接
6.Hibernate常见的映射配置
(1)class标签配置
(2)id标签配置
(3)property标签配置
7.Hibernate常见的核心配置
(1)核心配置的方式
①.属性文件:hibernate.properties
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql:///hibernate
hibernate.connection.username=root
hibernate.connection.password=123456
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
注意:属性文件的方式不能引入映射文件,需要手动编写代码加载映射。
②.XML文件的方式:hibernate.cfg.xml
(2)必须的配置
(3)可选的配置
(4)映射文件引入
8.Hibernate核心的API
(1)Configuration
作用:对Hibernate进行配置
①.加载核心配置文件
//对于hibernate.properties
Configuration cfg=new Configuration();
//对于hibernate.cfg.xml
Configuration cfg=new Configuration().configure();
②.加载映射文件
//手动加载
cfg.addResource(“pers/zx/hibernate/demo/Customer.hbm.xml”);
//在核心配置文件中加载
< mapping resource=”pers/zx/hibernate/demo/Customer.hbm.xml”/>
(2)SessionFactory:Session工厂
SessionFactory接口负责初始化Hibernate,其内部维护了Hibernate的连接池和Hibernate的二级缓存。是线程安全对象,一个项目创建一个对象即可。
①.配置连接池:在hibernate.cfg.xml
<!-- 配置C3P0连接池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
②.抽取工具类
public class HibernateUtils {
public static final Configuration configuration;
public static final SessionFactory sessionFactory;
static {
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}
public static Session getSession() {
return sessionFactory.openSession();
}
}
(3)Session:类似于Connection对象是一个链接对象
Session接口负责执行被持久化对象的CRUD(增删改查)操作,其代表的是Hibernate与数据库的连接对象,不是线程安全的。
①.Session接口中的API
1.保存方法:
Serializable save(Object obj); //返回一个序列化的数值,即id
2.查询方法:
T get(Class c,Serializable id);
T load(Class c,Serializable id);
具体使用:
Customer c=session.get(Customer.class,1L);
Customer c=session.load(Customer.class,2L);
区别:
3.修改方法:
void update(Object obj);
具体使用:
Ⅰ、直接创建对象,进行修改
Customer c=new Customer();
c.setCust_id(1L);
c.setCust_name(“xxx”);
session.update(c);//更新id为1的对象的name
Ⅱ、先查寻、后修改(推荐)
Customer c=session.get(Customer.class,1L);
c.setCust_name(“xxx”);
session.update(customer);
注意:推荐使用Ⅱ,这时由于第一种方法可能会错误修改其他数据。第二种是查询出来后设置查询后的对象,将修改后的对象在更新到数据表中,不会出错。
4.删除方法
void delete(Object obj);
具体使用
Ⅰ、直接创建对象,进行删除
Customer c=new Customer();
c.setCust_id(1L);
session.delete(c);//更新id为1的对象的name
Ⅱ、先查寻、后修改(推荐)
Customer c=session.get(Customer.class,1L);
session.delete(customer);
5.查询所有
Ⅰ、HQL查询:Hibernate Query Language,面向对象的查询语言,该方式查询出来的是一个对象
Query query=session.createQuery(“from Customer”);
List< Customer> list=query.list();
for(Customer customer : list){
Systeem.out.println(customer);
}
Ⅱ.SQL方式:结构化查询语言,返回的是个对象数组
SQLQuery query=session.createSQLQuery(“SELECT * from cst_customer”);
List<Object[]> list=query.list();
for(Object[] objects : list){
System.out.println(Arrays.toString(objects));
}
(4)Transaction:事务处理对象
①.commit():提交
②.rollback():回滚
三、Hibernate进阶
1.持久化类的编写规则
(1)什么是持久化类?
持久化:将内存中的一个对象持久化到数据库(磁盘)的过程。Hibernate框架就是用来进行持久化的框架。
持久化类:一个Java对象与数据库建立了映射关系,那么这个类在Hibernate中称为持久化类。
持久化类= java类+映射文件
(2)持久化类的编写规则
①.对持久化类提供一个无参的构造方法
目的:Hibernate底层需要使用反射生成实例
②.属性需要私有,对私有属性提供public的get和set方法
目的:在Hibernate中获取,设置对象的值
③.对持久化类提供一个唯一标识OID的属性区分是否是同一个对象
目的:Java中通过对象的地址区分是否是同一个对象,数据库中通过主键确定是否是同一条记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
④.持久化类中的属性尽量使用包装类类型
目的:基本数据类型默认是0,那么就会有很多的歧义,包装类类型默认为null。
⑤.持久化类不要使用final修饰
目的:延迟加载本身是hibernate一个优化的手段。其返回的是一个代理对象(javassist可以对没有实现接口的类产生代理—–使用了底层的字节码增强技术,继承这个类进行代理)。由于要是使用了final的话,该类就不能被继承了,如果不能被继承,就不能产生代理对象,延迟加载就失效了。load方法就和get方法一致了。
2.主键生成策略
(1)主键的分类
①.自然主键:主键本身就是表中的一个字段(实体中的一个具体属性)。表中的主键即是代码中的主键。
②.代理主键:主键本身不是表中必须的一个字段(不是实体中的某个具体属性)
注意:在实际开发中,尽量使用代理主键,一旦自然主键参与到业务逻辑中,后期有可能需要修改源代码。好的程序设计满足OCP原则:对程序的扩展是open,对程序的修改是关闭的。
(2)主键生成策略
在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多种的主键的生成策略。
①.increment:hibernate中提供的自动增长机制,适用于short、int、long类型的主键。在单线程程序中使用。
执行原理:首先发送一条语句:selete max(id) from table,然后id+1作为下一条记录的主键。
②.identity:适用于short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长的数据库(MySQL、MSSQL),不适合Oracle。
③.sequence:适用short、int、long类型的主键,采用的是序列的方式。(Oracle支持序列)。MySql不能适用sequence
④.uuid:适用于字符串类型的主键,适用hibernate中的随机方式生成字符串主键。
⑤.native:本地策略,可以在identity和sequence之间进行自动切换
⑥.assigned:hibernate放弃外键的管理,需要手动编写程序或用户自己设置。
⑦.foreign:外部的,一对一的关系映射的情况下适用,其他表的属性字段是一个表的主键。
3.持久化类的三种状态
Hibernate是持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分成三种状态。
(1)瞬时态
这种对象没有唯一的标识OID,没有被session管理。
(2)持久态
这种对象有唯一标识OID,被session管理。
(3)脱管态
这种对象有唯一标识OID,没有被session管理。
(4)如何区分这三种状态:
(5)三种状态转换
①.瞬时态对象
②.持久太对象
③.脱管态
(6)持久态对象的特性
它可以自动跟新数据库,利用的原理就是Hibernate的一级缓存。
下面的代码可以不用update方法更新数据库(当数据和数据库中的数据不一致时更新,一样不更新)
public void test1() {
Session session=HibernateUtils.getSession();
Transaction t=session.beginTransaction();
Customer c=session.get(Customer.class, 1L);
c.setCust_name("xxx");
//session.update(c);
t.commit();
session.close();
}
4.Hibernate一级缓存
(1)什么是缓存?
是一种优化方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。
(2)一级缓存
一级缓存是hibernate框架中提供的一种优化手段,包括:缓存,抓取策略。关于缓存其提供了两种缓存机制:一级缓存和二级缓存。
所谓一级缓存:称为是Session级别的缓存,一级缓存生命周期与session一致,它是由session中的一系列的java集合构成。一级缓存是自带的不可卸载的。
二级缓存是SessionFactory级别的缓存,是需要配置的缓存。
(3)测试一级缓存
public void test() {
Session session=HibernateUtils.getSession();
Transaction t=session.beginTransaction();
Customer c=session.get(Customer.class, 1L);//发送sql语句
System.out.println(c);
Customer c1=session.get(Customer.class, 1L);//不发送,从缓存中读
System.out.println(c1);
t.commit();
session.close();
}
(4)一级缓存的特点
(5)一级缓存的特殊区域:快照区
快照区会复制缓存区的内容,当在一次执行操作时,会修改缓存区,此时进行提交时,会用快照区的数据与更新后的缓存区的数据进行对比,如果不一样就更新数据库,一样就不更新数据库。
原理:
4.Hibernate事务管理
(1)回顾事务管理
①.事务:事务是指逻辑上的一组操作,组成事务操作的各个单元必须全部成功。
②.事务的特性(ACID)
③.不考虑隔离性可能引发的问题
④.设置隔离级别
(2)Hibernate设置事务的隔离级别
在核心配置文件中
< property name=”hibernate.connection.isolation”>4< /property>
1—–Read uncommitted isolation
2—–Read committed isolation
4—–Repeatable read isolation
8—–Serializable isolation
(3)线程绑定
①.在项目中使用同一个连接的方法(同一个Session)
1.向下传递:在所要使用该连接的方法的上一层做一个公共的连接,把这个连接传到这些被调用的方法中。
2.ThreadLocal:同一个线程产生的连接是一样的。
②.Hibernate线程绑定
修改工具类,得到当前线程的session
public class HibernateUtils {
public static final Configuration configuration;
public static final SessionFactory sessionFactory;
static {
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}
public static Session getSession() {
return sessionFactory.openSession();
}
//getCurrentSession
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
修改核心配置文件
<!-- 配置session绑定本地线程 -->
<property name="hibernate.current_session_context_class">Thread</property>
编写代码测试:此时不用关闭session
public void test2() {
Session session=HibernateUtils.getCurrentSession();
Transaction t=session.beginTransaction();
Customer c=session.get(Customer.class, 1L);
c.setCust_name("xxx");
t.commit();
}
5.Hibernate其他的一些API
(1)Query
Query接口用于接收HQL,查询多个对象。
HQL:Hibernate Query Language Hibernate查询语言,是面向对象的查询语言。
①.代码
//Query测试
public void test3() {
Session session=HibernateUtils.getCurrentSession();
Transaction t=session.beginTransaction();
//简单查询
String hql="from Customer";
Query query=session.createQuery(hql);
List<Customer> list=query.list();
for(Customer lists:list) {
System.out.println(lists);
}
//条件查询
String hql1="from Customer where cust_name = ?";
Query query1=session.createQuery(hql1);
query1.setParameter(0, "zx");//为占位符赋值
//设置分页
String hql2="from Customer";
Query query2=session.createQuery(hql2);
query2.setFirstResult(0);//从哪开始
query2.setMaxResults(2);//每页的个数
List<Customer> list2=query.list();
for(Customer lists:list2) {
System.out.println(lists);
}
t.commit();
}
(2)Criteria
QBC(Query by Criteria),query条件查询。是一种更加面向对象的方式。
①.代码
@Test
//criteria测试
public void test4() {
Session session=HibernateUtils.getCurrentSession();
Transaction t=session.beginTransaction();
//简单查询
Criteria c=session.createCriteria(Customer.class);
List<Customer> list=c.list();
for(Customer a:list) {
System.out.println(a);
}
//条件查询
c.add(Restrictions.like("cust_name", "z%"));//以z开头的
List<Customer> list1=c.list();
for(Customer a:list1) {
System.out.println(a);
}
//分页
Criteria b=session.createCriteria(Customer.class);
b.setFirstResult(0);
b.setMaxResults(2);
List<Customer> list2=b.list();
for(Customer a:list2) {
System.out.println(a);
}
t.commit();
}
(3)SQLQuery
用来接收SQL语句,一般用于复杂的SQL语句。
四、Hibernate表的操作与配置
1.表与表之间的关系
(1)一对多
①.1 :N :一个部门有多个员工,一个员工只能属于一个部门
②.建表原则
(2)多对多
①.M : N:一个学生可以选多门课,每门课也可以有多个学生选。
②.建表原则
(3)一对一
①.1 :1:一个公司只有一个地址,一个地址对应一个公司。
②.建表原则
2.创建一对多的实例
(1)创建一对多的数据库表
(2)编写实体
①.Customer
private long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
//通过ORM方式表示:一个客户对应多个联系人。
// 放置的多的一方的集合。Hibernate默认使用的是Set集合。
private Set<LinkMan> linkMans=new HashSet<LinkMan>();
②.LinkMan
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
// 通过ORM方式表示:一个联系人只能属于某一个客户。
// 放置的是一的一方的对象。
private Customer customer;
注意:在多的一方要写一个一的一方的对象,而一的一方要写多的一方的集合,同时生成get和set方法。
(3)编写配置文件
①.Customer.hbm.xml
<hibernate-mapping>
<!-- 建立类与表的映射 -->
<class name="pers.zx.hibernate.demo.Customer" table="cst_customer">
<!-- 建立类中属性与表的主键对应 -->
<id name="cust_id" column="cust_id">
<generator class="native" />
</id>
<!-- 建立类中的普通的属性和表的字段的应对 -->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!-- 配置一对多的映射:放置的多的一方的集合 -->
<!--
set标签 :
name :多的一方的对象集合的属性名称。
cascade :级联
inverse :放弃外键维护权。
-->
<set name="linkMans" cascade="save-update" inverse="true">
<!--
key标签
column:多的一方的外键的名称。
-->
<key column="lkm_cust_id"/>
<!--
one-to-many标签
class :多的一方的类的全路径
-->
<one-to-many class="pers.zx.hibernate.test.LinkMan"/>
</set>
</class>
</hibernate-mapping>
②.LinkMan.hbm.xml
<hibernate-mapping>
<class name="pers.zx.hibernate.test.LinkMan.class" table="cst_linkman">
<!-- 建立OID与主键映射 -->
<id name="lkm_id" column="lkm_id">
<generator class="native" />
</id>
<!-- 建立属性与表字段的映射 -->
<property name="lkm_name"/>
<property name="lkm_gender"/>
<property name="lkm_phone"/>
<property name="lkm_mobile"/>
<property name="lkm_email"/>
<property name="lkm_qq"/>
<property name="lkm_position"/>
<property name="lkm_memo"/>
<!--配置多对一的关系:放置的是一的一方的对象 -->
<!--
many-to-one标签
name :一的一方的对象的属性名称。
class :一的一方的类的全路径。
column :在多的一方的表的外键的名称。
-->
<many-to-one name="customer" class="pers.zx.hibernate.test.Customer" column="lkm_cust_id" />
</class>
</hibernate-mapping>
(4)编写核心配置文件
<hibernate-configuration>
<session-factory>
<!-- 建立数据库连接的基本参数 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">19960213zx</property>
<!-- 配置hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 配置C3P0连接池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
<!-- 可选配置 -->
<!-- 打印SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 设置事务隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
<!-- 配置session绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 有几个就配置几个映射 -->
<mapping resource="pers/zx/hibernate/test/Customer.hbm.xml"/>
<mapping resource="pers/zx/hibernate/test/LinkMan.hbm.xml"/>
</session-factory>
</hibernate-configuration>
(5)引入工具类
public class HibernateUtils {
public static final Configuration configuration;
public static final SessionFactory sessionFactory;
static {
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}
public static Session getSession() {
return sessionFactory.openSession();
}
//getCurrentSession
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
(6)编写测试类
// 保存2个客户 和 3个联系人 并且建立好关系
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 创建两个客户
Customer customer1 = new Customer();
customer1.setCust_name("zx");
Customer customer2 = new Customer();
customer2.setCust_name("xx");
// 创建三个联系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("rt");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("qw");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("gf");
// 设置关系:
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
// 保存数据:
session.save(linkMan1);
session.save(linkMan2);
session.save(linkMan3);
session.save(customer1);
session.save(customer2);
tx.commit();
}
3.一对多的级联保存或跟新
我们在对数据库操作的时候,如果不设置级联,则就不能进行单方面的保存,必须要像上面一样同时都要保存。
(1)什么叫级联?
级联指的是,操作一个对象的时候,是否会同时操作其关联的对象。
(2)级联的方向性
操作一的一方时,会影响到多的一方
操作多的一方时,会影响到一的一方
(3)级联保存或更新的配置
①.要想在一的一方更新影响多的一方
配置一的一方的配置文件,在< set>中添加属性:cascade=”save-update”
②.要想在多的一方更新影响一的一方
配置多的一方的配置文件,在< many-to-one>中添加属性:cascade=”save-update”
③.代码:
@Test
// 级联保存或更新操作:
// 保存客户级联联系人,操作的主体是客户对象,需要在Customer.hbm.xml中进行配置
// <set name="linkMans" cascade="save-update">
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("赵洪");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("如花");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
session.save(customer);
tx.commit();
}
//级联保存或更新操作:
//保存联系人级联客户,操作的主体是联系人对象,需要在LinkMan.hbm.xml中进行配置
//<many-to-one name="customer" cascade="save-update" class="com.itheima.hibernate.domain.Customer" column="lkm_cust_id"/>
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("李兵");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("凤姐");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
session.save(linkMan);
tx.commit();
}
注意:谁级联谁就去改谁的配置文件
(4)对象的导航
@Test
//测试对象的导航
//前提:一对多的双方都设置cascade="save-update"
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("zx");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("vv");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("xx");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("oo");
linkMan1.setCustomer(customer);
customer.getLinkMans().add(linkMan2);
customer.getLinkMans().add(linkMan3);
// 双方都设置了cascade
// session.save(linkMan1); // 发送几条insert语句 4条
// session.save(customer); // 发送几条insert语句 3条
session.save(linkMan2); // 发送几条insert语句 1条
tx.commit();
}
第一个session发送四条是因为联系人关联了客户,保存联系人之后由于级联操作,客户会保存,又是由于级联操作,所以另外两个联系人也会被保存。
第二个session是因为,保存客户会发一条,有因为另外两个联系人和客户有关联,所以也会发送。
第三个session发一条是因为没有客户与他关联,所以只发一条
关系:Link1–>customer–>link2
–>link3
(5)级联删除
一般是删除一的一方级联删除多的一方。方法是在一的一方的配置文件中的set中添加cascade=”delete”(反过来也可以,但不常用)
// 级联删除:
//删除客户级联删除联系人,删除的主体是客户,需要在Customer.hbm.xml中配置
//<set name="linkMans" cascade="delete">
public void demo6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 没有设置级联删除,默认情况:修改了联系人的外键,删除客户
/*Customer customer = session.get(Customer.class, 1l);
session.delete(customer);*/
// 删除客户,同时删除联系人
Customer customer = session.get(Customer.class, 1l);
session.delete(customer);
tx.commit();
}
(6)如何防止多余的SQL语句
使用在一的一方的set中使用属性inverse=”true”,这是由于在未设置inverse之前,双方都会维护外键,所以会有多余的更新语句。在设置后,一的一方会放弃对外键的维护权。
原理:
@Test
//将2号联系人原来归1号客户,现在改为2号客户
public void demo8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询2号联系人
LinkMan linkMan = session.get(LinkMan.class, 2l);
// 查询2号客户
Customer customer = session.get(Customer.class, 2l);
// 双向的关联
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
tx.commit();
}
(7)区分cascade和inverse
在一方级联的时候设置inverse为true时,若是更新这一方,则不会维护外键值,只会插入相应的客户和联系人,外键值为空。
@Test
//区分cascade和inverse的区别
public void demo9(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("李兵");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("凤姐");
customer.getLinkMans().add(linkMan);
// 条件在Customer.hbm.xml上的set中配置了cascade="save-update" inverse="true"
session.save(customer); // 客户会插入到数据库,联系人也会插入到数据库,但是外键为null
tx.commit();
}
4.多对多操作
(1)创建表
(2)创建实体
①.User
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
// 设置多对多关系:表示一个用户选择多个角色?
// 放置的是角色的集合
private Set<Role> roles = new HashSet<Role>();
②.Role
private Long role_id;
private String role_name;
private String role_memo;
// 一个角色被多个用户选择:
// 放置的是用户的集合
private Set<User> users = new HashSet<User>();
(3)配置实体与表的映射文件
①.User.hbm.xml
<hibernate-mapping>
<class name="pers.zx.hibernate.test.User" table="sys_user">
<id name="user_id" column="use_id">
<generator class="native"/>
</id>
<property name="user_code" column="user_code" />
<property name="user_name" column="user_name" />
<property name="user_password" column="user_password" />
<property name="user_state" column="user_state" />
<!-- 建立多对多的映射关系 -->
<!--
set标签
name :对方的集合的属性名称。
table :多对多的关系需要使用中间表,放的是中间表的名称。
-->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!--
key标签:
column :当前的对象对应中间表的外键的名称。
-->
<key column="user_id" />
<!--
many-to-many标签:
class :对方的类的全路径
column :对方的对象在中间表中的外键的名称。
-->
<many-to-many class="pers.zx.hibernate.test.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
②.Role.hbm.xml
<hibernate-mapping>
<class name="pers.zx.hibernate.test.Role" table="sys_role">
<!-- 建立OID与主键的映射 -->
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<!-- 建立普通属性与字段的映射 -->
<property name="role_name" column="role_name"/>
<property name="role_memo" column="role_memo"/>
<!-- 与用户的多对多的映射关系 -->
<!--
set标签
name :对方的集合的属性名称。
table :多对多的关系需要使用中间表,放的是中间表的名称。
-->
<set name="users" table="sys_user_role" cascade="save-update,delete" inverse="true">
<!--
key标签:
column :当前的对象对应中间表的外键的名称。
-->
<key column="role_id"/>
<!--
many-to-many标签:
class :对方的类的全路径
column :对方的对象在中间表中的外键的名称。
-->
<many-to-many class="pers.zx.hibernate.test.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
(4)配置核心配置文件
<hibernate-configuration>
<session-factory>
<!-- 建立数据库连接的基本参数 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">19960213zx</property>
<!-- 配置hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 配置C3P0连接池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
<!-- 可选配置 -->
<!-- 打印SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 设置事务隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
<!-- 配置session绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 有几个就配置几个映射 -->
<mapping resource="pers/zx/hibernate/test/Customer.hbm.xml"/>
<mapping resource="pers/zx/hibernate/test/LinkMan.hbm.xml"/>
<mapping resource="pers/zx/hibernate/test/User.hbm.xml"/>
<mapping resource="pers/zx/hibernate/test/Role.hbm.xml"/>
</session-factory>
</hibernate-configuration>
(5)编写测试代码
@Test
// 保存多条记录:保存多个用户和角色
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 创建2个用户
User user1 = new User();
user1.setUser_name("赵洪");
User user2 = new User();
user2.setUser_name("李兵");
// 创建3个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系:
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
// 保存操作:多对多建立了双向的关系必须有一方放弃外键维护。
// 一般是被动方放弃外键维护权。
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
tx.commit();
}
5.多对多的级联操作
也需要在相应的配置文件的set中设置属性cascade=”save-update”。谁去级联谁就去改谁的配置文件。
@Test
//多对多的级联保存:
//保存用户级联保存角色。在用户的映射文件中配置。
//在User.hbm.xml中的set上配置 cascade="save-update"
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 创建2个用户
User user1 = new User();
user1.setUser_name("赵洪");
// 创建3个角色
Role role1 = new Role();
role1.setRole_name("研发部");
// 设置双向的关联关系:
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 只保存用户:
session.save(user1);
tx.commit();
}
6.多对多的其他操作
(1)给用户选择角色
public void demo7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 给1号用户多选2号角色
// 查询1号用户
User user = session.get(User.class, 1l);
// 查询2号角色
Role role = session.get(Role.class, 2l);
user.getRoles().add(role);
tx.commit();
}
(2)给用户改选角色
public void demo8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 给2号用户将原有的2号角色改为3号角色
// 查询2号用户
User user = session.get(User.class, 2l);
// 查询2号角色
Role role2 = session.get(Role.class, 2l);
Role role3 = session.get(Role.class, 3l);
user.getRoles().remove(role2);
user.getRoles().add(role3);
tx.commit();
}
(3)删除用户的角色
public void demo9(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 给2号用户删除1号角色
// 查询2号用户
User user = session.get(User.class, 2l);
// 查询2号角色
Role role = session.get(Role.class, 1l);
user.getRoles().remove(role);
tx.commit();
}
五、Hibernate查询方式
Hibernate中提供了五种查询方式。
1.OID查询
OID检索:Hibernate根据对象的OID(主键)进行检索。
(1)使用get方法
Customer c=session.get(Customer.class,1L);
(2)使用load方法
Customer c=session.load(Customer.class,1L);
2.对象导航检索
对象导航检索:Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式。
通过联系人获取顾客信息
LinkMan l=session.get(LinkMan.class,1L);
Customer c=l.getCustomer();
Customer c=session.get(Customer.class,1L);
Set< LinkMan> l=c.getLinkMans();
3.HQL检索
Hibernate Query Language,Hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL。通过session.createQuery()接收HQL的方式查询。
(1)初始化数据库数据
用于查询操作
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 创建一个客户
Customer customer = new Customer();
customer.setCust_name("zx1mm");
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("er" + i);
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer);
tx.commit();
}
(2)HQL简单查询
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 简单的查询
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
// sql中支持*号的写法:select * from cst_customer; 但是在HQL中不支持*号的写法。
/*
* Query query = session.createQuery("select * from Customer");// 报错
* List<Customer> list = query.list();
*/
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(3)HQL别名查询
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 别名的查询
/*
* Query query = session.createQuery("from Customer c"); List<Customer>
* list = query.list();
*/
Query query = session.createQuery("select c from Customer c");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(4)排序查询
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序的查询
// 默认情况
// List<Customer> list = session.createQuery("from Customer order by
// cust_id").list();
// 设置降序排序 升序使用asc 降序使用desc
List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(5)条件查询
public void demo5() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 条件的查询
// 一、按位置绑定:根据参数的位置进行绑定。
// 一个条件
/*
* Query query = session.createQuery("from Customer where cust_name = ?"
* ); query.setParameter(0, "李兵"); List<Customer> list = query.list();
*/
// 多个条件
/*
* Query query = session.createQuery(
* "from Customer where cust_source = ? and cust_name like ?");
* query.setParameter(0, "小广告"); query.setParameter(1, "李%");
* List<Customer> list = query.list();
*/
// 二、按名称绑定
Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
// 设置参数:
query.setParameter("aaa", "朋友推荐");
query.setParameter("bbb", "李%");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(6)投影查询
投影查询:查询对象的某个或某些属性。
public void demo6() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 投影查询
// 单个属性
/*
* List<Object> list = session.createQuery(
* "select c.cust_name from Customer c").list(); for (Object object :
* list) { System.out.println(object); }
*/
// 多个属性:
/*
* List<Object[]> list = session.createQuery(
* "select c.cust_name,c.cust_source from Customer c").list(); for
* (Object[] objects : list) {
* System.out.println(Arrays.toString(objects)); }
*/
// 查询多个属性,但是我想封装到对象中。
List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(7)分页查询
public void demo7() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分页查询
Query query = session.createQuery("from LinkMan");
query.setFirstResult(20);//从哪开始
query.setMaxResults(10);//多少个
List<LinkMan> list = query.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
tx.commit();
}
(8)分组统计查询
public void demo8() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 聚合函数的使用:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
// 分组统计:
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source")
.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tx.commit();
}
(9) HQL的多表查询
public void demo9() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// SQL:SELECT * FROM cst_customer c INNER JOIN cst_linkman l ON
// c.cust_id = l.lkm_cust_id;
// HQL:内连接 from Customer c inner join c.linkMans
/*
* List<Object[]> list = session.createQuery(
* "from Customer c inner join c.linkMans").list(); for (Object[]
* objects : list) { System.out.println(Arrays.toString(objects)); }
*/
// HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner
// join fetch c.linkMans
List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans")
.list();// 通知hibernate,将另一个对象的数据封装到该对象中
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
4.QBC查询
QBC查询:Query By Criteria,条件查询。是一种更加面向对象化的查询的方式。
(1)简单查询
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 获得Criteria的对象
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(2)排序查询
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序查询
Criteria criteria = session.createCriteria(Customer.class);
// criteria.addOrder(Order.asc("cust_id")); // 升序
criteria.addOrder(Order.desc("cust_id")); // 降序
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(3)分页查询
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分页查询
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(10);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
tx.commit();
}
(4)条件查询
条件是默认并列的
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 条件查询
Criteria criteria = session.createCriteria(Customer.class);
// 设置条件:
/**
* = eq
* > gt
* >= ge
* < lt
* <= le
* <> ne
* like
* in
* and
* or
*/
criteria.add(Restrictions.eq("cust_source", "小广告"));
// criteria.add(Restrictions.or(Restrictions.like("cust_name", "李%")));
criteria.add(Restrictions.like("cust_name", "李%"));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
(5)统计查询
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
/**
* add :普通的条件。where后面条件
* addOrder :排序
* setProjection :聚合函数 和 group by having
*/
criteria.setProjection(Projections.rowCount());
Long num = (Long) criteria.uniqueResult();
System.out.println(num);
tx.commit();
}
(6)离线条件查询
public void demo6(){
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.like("cust_name", "李%"));//上面两行在web层,下面在dao层
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
5.多表查询
SQL多表查询
(1)连接查询
1.交叉连接:表与表之间的笛卡儿积
select * from A,B;
内连接:inner join (inner 可以省略),内连接就是表的交集。
①.隐式内连接:没有join关键字
select * from A,B where A.id=B.aid;
②.显示内连接:
select * from A inner join B on A.id=B.aid;
外连接:
左外连接:left outer join(outer可以省略),即左边的表与右边表的交集加上左边表与右边表没有交集的部分。
select * from A left outer join B on A.id=B.id;
右外连接:right outer join(outer可以省略)
右边表与左边表的交集加上右边表中与左边表没有交集的部分
select * from A right outer join B on A.id=B.aid;
2.子查询
HQL多表查询
(1)连接查询
交叉连接
(2)内连接
from Customer c inner join c.linkMans
显示内连接
隐式内连接
迫切内连接:fetch通知hibernate,将另一个对象的数据封装到该对象中
from Customer c inner join fetch c.linkMans
(3)外连接
左外连接
右外连接
迫切左外连接
public void demo9() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// SQL:SELECT * FROM cst_customer c INNER JOIN cst_linkman l ON
// c.cust_id = l.lkm_cust_id;
// HQL:内连接 from Customer c inner join c.linkMans
// List<Object[]> list = session.createQuery(
// "from Customer c inner join c.linkMans").list(); for (Object[]
// objects : list) { System.out.println(Arrays.toString(objects)); }
// HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner
// join fetch c.linkMans
List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans")
.list();// fetch通知hibernate,将另一个对象的数据封装到该对象中
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6.SQL查询
通过使用sql语句进行查询
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//返回数组
/*SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}*/
//返回对象实体
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
sqlQuery.addEntity(Customer.class);
List<Customer> list = sqlQuery.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
六、Hibernate抓取策略
对查询关联对象SQL语句的一种优化
1.延迟加载
(1)延迟加载:lazy(懒加载)。执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。
(2)延迟加载的分类
2.抓取策略
通过一个对象抓取到关联对象需要发送的SQL语句,对于SQL语句如何发送,和发送成什么样格式通过策略进行配置。
通过< set>或者< many-to-one>上通过fetch属性进行设置
fetch和这些标签上的lazy如何设置优化发送的SQL语句
(1)< set>上的fetch和lazy
//在<set>上的fetch和lazy
public class HibernateDemo2 {
@Test
// 默认情况:
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询客户的SQL
System.out.println(customer.getCust_name());
// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
System.out.println(linkMan.getLkm_name());
}
tx.commit();
}
@Test
//设置fetch="select" lazy="true"
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询客户的SQL
System.out.println(customer.getCust_name());
// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
System.out.println(linkMan.getLkm_name());
}
tx.commit();
}
@Test
// 设置 fetch="select" lazy="false"
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送两条SQL语句:查询客户的名称,查询客户关联联系人
System.out.println(customer.getCust_name());
/*// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) {//
System.out.println(linkMan.getLkm_name());
}*/
System.out.println(customer.getLinkMans().size());
tx.commit();
}
@Test
//设置fetch="select" lazy="extra"
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询1号客户的SQL语句
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 发送一条select count() from ...;
tx.commit();
}
@Test
//设置fetch="join" lazy=失效
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条迫切左外连接查询记录
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 不发送
tx.commit();
}
@SuppressWarnings("unchecked")
@Test
//设置fetch="subselect" lazy="true"
public void demo6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL
for (Customer customer : list) {
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 发送一条子查询
}
tx.commit();
}
@SuppressWarnings("unchecked")
@Test
//设置fetch="subselect" lazy="false"
public void demo7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL,发送一条子查询
for (Customer customer : list) {
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());//
}
tx.commit();
}
}
(2)< many-to-one>上的fetch和lazy
// many-to-one上的fetch和lazy测试
public class HibernateDemo3 {
@Test
// 默认值
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条查询联系人语句
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());// 发送一条select语句查询联系人所关联的客户
tx.commit();
}
@Test
//fetch="select" lazy="proxy"
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条查询联系人语句
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());// 发送一条select语句查询联系人所关联的客户
tx.commit();
}
@Test
//fetch="select" lazy="false"
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条查询联系人语句,发送一条select语句查询联系人所关联的客户
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());//
tx.commit();
}
@Test
//fetch="join" lazy=失效
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条迫切左外连接查询联系人所关联的客户。
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());//
tx.commit();
}
}
3.批量抓取
一批关联对象一起抓取,batch-size,在set上设置属性batch-size=””,来指定每次抓几条。即发送多少条sql语句。内部其实使用的in来一次性查询多少条。
下面有两种配置方式:
// 批量抓取
public class HibernateDemo4 {
@SuppressWarnings("unchecked")
@Test
// 获取客户的时候,批量抓取联系人
//在Customer.hbm.xml中set上配置batch-size
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println(customer.getCust_name());
for (LinkMan linkMan : customer.getLinkMans()) {
System.out.println(linkMan.getLkm_name());
}
}
tx.commit();
}
@SuppressWarnings("unchecked")
@Test
// 获取联系人的时候,批量抓取客户
//在Customer.hbm.xml中<class>上配置
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
List<LinkMan> list = session.createQuery("from LinkMan").list();
for (LinkMan linkMan : list) {
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());
}
tx.commit();
}
}