蒋振飞的博客 - Java进阶01:Hibernate教程   
正在加载蒋振飞的博客...
V3.0
蒋振飞的博客

Java进阶01:Hibernate教程

发布时间: 2018年12月11日 发布人: 蒋振飞 热度: 505 ℃ 评论数: 0

一、Hibernate概述

    1.什么是Hibernate?

        Hibernate是一个开放源码的ORM(Object Relational Mapping,对象关系映射)框架,它对JDBC进行了轻量级的封装,使得Java开发人员可以使用面向对象的编程思想来操作数据库。

    2.什么是ORM?

        ORM:Object Relational Mapping(对象关系映射)。指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。

    3.为什么要使用Hibernate?

        在使用传统的Servlet+JSP+JavaBean+JDBC开发应用系统,针对大型应用系统开发时,需要写多条sql查询语句,过程枯燥繁琐。使用Hibernate可以提高数据访问层的编程效率,也是最流行的ORM框架。

    4.Hibernate5下载使用

        下载地址:https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/

    5.Hibernate压缩包结构

documentation       :Hibernate开发的文档
lib                 :Hibernate开发包
    required        :Hibernate开发的必须的依赖包
    optional        :Hibernate开发的可选的jar包
project             :Hibernate提供的项目

二、Hibernate简单配置

    1.创建数据库和表

CREATE TABLE `cst_customer` (
    `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
    `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
    `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
    `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
    `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
    `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
    `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
    PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

    2.创建实体类

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;
}

    3. 创建映射

        在实体类Customer所在包中,创建一个名为Customer.hbm.xml的映射文件,在该文件中定义了实体类Customer的属性是如何映射到cst_customer表的列上的。

<?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="com.jzfblog.hibernate.Customer" table="cst_customer">
        <!-- 建立类中的属性与表中的主键对应 -->
        <id name="cust_id" column="cust_id" >
            <generator class="native"/>
        </id>
 
        <!-- 建立类中的普通的属性和表的字段的对应 -->
        <property name="cust_name" column="cust_name" length="32" />
        <property name="cust_source" column="cust_source" length="32"/>
        <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>

    4.创建一个Hibernate的核心配置文件

        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>
 
        <!-- 
        #hibernate.dialect org.hibernate.dialect.MySQLDialect
        #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
        #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
        #hibernate.connection.driver_class com.mysql.jdbc.Driver
        #hibernate.connection.url jdbc:mysql:///test
        #hibernate.connection.username gavin
        #hibernate.connection.password
         -->
         <!-- 数据库驱动 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <!-- 数据库url -->
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
         <!-- 数据库连接用户名 -->
        <property name="hibernate.connection.username">root</property>
         <!-- 数据库连接密码 -->
        <property name="hibernate.connection.password">1234</property>
        <!-- 数据库方言
            不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
            sql99标准: DDL 定义语言  库表的增删改查
                      DCL 控制语言  事务 权限
                      DML 操纵语言  增删改查
            注意: MYSQL在选择方言时,请选择最短的方言.
         -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 
 
        <!-- #hibernate.show_sql true 
             #hibernate.format_sql true
        -->
        <!-- 将hibernate生成的sql语句打印到控制台 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 将hibernate生成的sql语句格式化(语法缩进) -->
        <property name="hibernate.format_sql">true</property>
        <!-- 
        ## auto schema export  自动导出表结构. 自动建表
        #hibernate.hbm2ddl.auto create      自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
        #hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
        #hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
        #hibernate.hbm2ddl.auto validate    校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
         -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 引入orm元数据
            路径书写: 填写src下的路径
         -->
         <!-- 指定hibernate操作数据库时的隔离级别 
            #hibernate.connection.isolation 1|2|4|8     
            0001    1   读未提交
            0010    2   读已提交
            0100    4   可重复读
            1000    8   串行化
         -->
         <property name="hibernate.connection.isolation">4</property>
         <!-- 指定session与当前线程绑定 -->
         <property name="hibernate.current_session_context_class">thread</property>
 
        <mapping resource="cn/jzfblog/domain/Customer.hbm.xml" />
 
    </session-factory>
</hibernate-configuration>

    5.编写测试代码

        首先创建Configuration类的实例,并通过它来读取并解析配置文件hibernate,cfg.xml。然后创建SessionFactory读取解析映射文件信息,并将Configration对象中所有配置信息拷贝到SessionFactory内存中。接下来,打开Session,让SessionFactory提供链接,并开启事务,之后创建对象,向对象中添加数据,通过session.save()方法完成向数据库中保存数据的操作。最后提交事务,并关闭资源。

// 1.加载Hibernate的核心配置文件
Configuration configuration = new Configuration().configure();
// 手动加载映射
// configuration.addResource("com/jzfblog/hibernate/Customer.hbm.xml");
// 2.创建一个SessionFactory对象:类似于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("王西");
session.save(customer);
// 6.事务提交
transaction.commit();
// 7.资源释放
session.close();
sessionFactory.close();

三、Hibernate常见配置

    1.映射的配置

        1) class标签的配置

            标签用来建立类与表的映射关系。

属性:
name        :类的全路径
table       :表名(类名与表名一致,table可以省略)
catalog     :数据库名

        2) id标签的配置

            标签用来建立类中的属性与表中的主键的对应关系。

属性:
name        :类中的属性名
column      :表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length      :长度
type        :类型

        3) property标签的配置

            标签用来建立类中的普通属性与表的字段的对应关系。

属性:
name        :类中的属性名
column      :表中的字段名
length      :长度
type        :类型
not-null    :设置非空
unique      :设置唯一

    2.Hibernate的核心的配置

        2.1 必须的配置

            1) 连接数据库的基本的参数

                ①驱动类
                ②url路径
                ③用户名
                ④密码

            2) 方言

        2.2 可选的配置

            1) 显示SQL:hibernate.show_sql

            2) 格式化SQL:hibernate.format_sql

            3) 自动建表:hibernate.hbm2ddl.auto

                ①none :不使用hibernate的自动建表。
                ②create :如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)
                ③create-drop:如果数据库中已经有表,删除原有表,执行操作,删除这个表。如果没有表,新建一个,使用完了删除该表。(测试)
                ④update :如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)。
                ⑤validate :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。

        2.3 映射文件的引入

            引入映射文件的位置

<mapping resource="com/jzfblog/hibernate/demo1/Customer.hbm.xml"/>

    3.Hibernate的核心API

        3.1 Hibernate配置对象—Configration

            Configration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。

            1) 加载核心配置文件

                 hibernate.properties
                Configuration cfg = new Configuration();

            2) hibernate.cfg.xml

                Configuration cfg = new Configuration().configure();

            3) 加载映射文件

// 手动加载映射
configuration.addResource("com/jzfblog/hibernate/Customer.hbm.xml");

        3.2 Session工厂—SessionFactory

            充当数据存储源的代理,负责创建Session对象。通常情况下,一个项目只需要一个SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

            配置连接池:(了解)

<!-- 配置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 cfg;
    public static final SessionFactory sf;
 
    static{
        cfg = new Configuration().configure();
        sf = cfg.buildSessionFactory();
    }
 
    public static Session openSession(){
        return sf.openSession();
    }
 
    public static Session getCurrentSession(){
        return sf.getCurrentSession();
    }
}

        3.3 类似Connection连接对象—Session

            Session代表的是Hibernate与数据库的链接对象。不是线程安全的。与数据库交互桥梁。

            1) 保存方法:

                Serializable save(Object obj);

// 保存客户
public void demo1(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    Customer customer  = new Customer();
    customer.setCust_name("王小西");
    Serializable id = session.save(customer);
    System.out.println(id);
    tx.commit();
    session.close();
}

            2) 查询方法:

                T get(Class c,Serializable id);

                T load(Class c,Serializable id);

                get方法和load方法的区别?

                    get方法:

                        采用的是立即加载,执行到这行代码的时候,就会马上发送SQL语句去查询。
                        查询后返回是真实对象本身。
                        查询一个找不到的对象的时候,返回null

                    load方法:

                        采用的是延迟加载(lazy懒加载),执行到这行代码的时候,不会发送SQL语句,当真正使用这个对象的时候才会发送SQL语句。
                        查询后返回的是代理对象。javassist-3.18.1-GA.jar 利用javassist技术产生的代理。
                        查询一个找不到的对象的时候,返回ObjectNotFoundException

// 查询:
public void demo2(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 使用get方法查询
    /*Customer customer = session.get(Customer.class, 100l); // 发送SQL语句
    System.out.println(customer);*/
 
    // 使用load方法查询
    Customer customer = session.load(Customer.class, 200l);
    System.out.println(customer);
 
    tx.commit();
    session.close();
}

            3) 修改方法:

                void update(Object obj);

// 修改操作
public void demo3(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 直接创建对象,进行修改
    /*Customer customer = new Customer();
    customer.setCust_id(1l);
    customer.setCust_name("王聪");
    session.update(customer);*/
 
    // 先查询,再修改(推荐)
    Customer customer = session.get(Customer.class, 1l);
    customer.setCust_name("王小贱");
    session.update(customer);
 
    tx.commit();
    session.close();
}

            4) 删除方法:

                void delete(Object obj);

// 删除操作
public void demo4(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 直接创建对象,删除
/*  Customer customer = new Customer();
    customer.setCust_id(1l);
    session.delete(customer);*/
 
    // 先查询再删除(推荐)--级联删除
    Customer customer = session.get(Customer.class, 2l);
    session.delete(customer);
 
    tx.commit();
    session.close();
}

            5) 保存或更新:

                void saveOrUpdate(Object obj)

// 保存或更新
public void demo5(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    /*Customer customer  = new Customer();
    customer.setCust_name("王凤");
    session.saveOrUpdate(customer);*/
 
    Customer customer = new Customer();
    customer.setCust_id(3l);
    customer.setCust_name("李如花");
    session.saveOrUpdate(customer);
 
    tx.commit();
    session.close();
}

            6) 查询所有:

// 查询所有
public void demo6(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    // 接收HQL:Hibernate Query Language 面向对象的查询语言
    /*Query query = session.createQuery("from Customer");
    List<Customer> list = query.list();
    for (Customer customer : list) {
        System.out.println(customer);
    }*/
 
    // 接收SQL:
    SQLQuery query = session.createSQLQuery("select * from cst_customer");
    List<Objects[]> list = query.list();
    for (Objects[] object : list) {
        System.out.println(Arrays.toString(object));
    }
    tx.commit();
    session.close();
}

四、持久化类的编写规则

    1.什么是持久化?

        1) 持久化

            将内存中的一个对象持久化到数据库的过程,其中Hibernate框架正是持久化框架。

        2) 持久化类

            一个Java类与数据库的表建立了映射关系,那么该类在Hibernate中称为是持久化类。

    2.编写规则?

        ①对持久化类提供一个无参数构造方法,原因:Hibernate底层需要使用反射生成实例。
        ②属性需要私有,对私有属性提供public的get和set方法,原因:Hibernate中获取,设置对象的值。
        ③对持久化类提供一个唯一标识OID与数据库主键对应,原因:数据库中通过主键确定是否是同一个记录。
        ④持久化类中属性尽量保证使用包装类类型,原因:基本数据类型默认是0,包装类类型默认值是null。
        ⑤持久化类不要用final进行修饰,原因:使得持久化类不能产生子类,从而不会产生代理对象,延迟加载策略就会失效。

五、主键生成策略

    1.主键的分类

        1) 自然主键

            主键的本身就是表中的一个字段(实体中一个具体的属性)。

        2) 代理主键

            主键的本身不是表中必须的一个字段(不是实体中的某个具体的属性)。

    2.生成策略

        1) increment

            Hibernate中提供的自动增长机制,适用short、int、long类型的主键,在单线程中使用。

        2) identity

            数据库底层的自动增长机制,适用short、int、long类型的主键。(支持Mysql,不支持Oracle)

        3) sequence

            采用序列的方式,适用short、int、long类型的主键。(支持Oracle、不支持Mysql)

        4) uuid

            适用于字符串类型的主键,使用Hibernate中的随机方式生成字符串主键。

        5) native

            本地策略,可以在identity和sequence之间自由切换。

        6) assigned

            Hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。

六、持久化类的三种状态

    1.瞬时态

        这种对象没有唯一标识OID,被session所管理。

    2.持久态

        这种对象有唯一标识OID,被session所管理。

    3.脱管态

        这种对象有唯一标识OID,没有被session管理。

// 测试三种状态
public void demo1(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
 
    Customer customer  = new Customer(); // 瞬时态对象:没有持久化标识OID,没有被session管理
    customer.setCust_name("王小西");
    Serializable id = session.save(customer); // 持久化对象:有持久化标识OID,被session管理
    tx.commit();
    session.close();
 
    System.out.println(customer); // 脱管态对象:有持久化标识OID,没有被session管理
}

    4.持久化对象的状态转换

        1) 瞬时态转化到其他态

            获取瞬时态:使用new关键词创建。
            瞬时态转化为持久态:执行Session的save()或saveOrUpdate()方法。
            瞬时态转化为脱管态:为瞬时态对象设置持久化标识OID。

        2) 持久态转化到其他态

            获取持久态:通过Hibernate中session的get、load、Query查询等方法从数据库中获得。
            持久态转化为瞬时态:执行Session的delete方法。
            持久态转化为脱管态:执行Session的evict()、close()或clear()方法。

        3) 脱管态转化到其他态

            获取脱管态:不能直接获得,需通过其他态进行转化。
            脱管态转化到瞬时态:将脱管态对象的持久化标识OID设置为null。
            脱管态转化为持久态:执行Session的update()、saveUpdate()或lock()方法。

七、Hibernate的一级缓存

    1.什么是缓存?

        是一种优化的方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。

    2.Hibernate的缓存

        一级缓存:称为是Session级别的缓存,一级缓存生命周期与Session一致(由Session中的一系列Java集合构成,自带不可卸载)。
        二级缓存:是SessionFactory级别的缓存,需要配置缓存。

    3.Hibernate中的事务管理

        除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的核心配置文件中对事务进行配置。

<!-- 指定hibernate操作数据库时的隔离级别 
    #hibernate.connection.isolation 1|2|4|8     
    0001    1   读未提交
    0010    2   读已提交
    0100    4   可重复读
    1000    8   串行化
-->
<property name="hibernate.connection.isolation">4</property>
 
<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>

八、Hibernate其他API

    1.Query

        1) 基本查询:

//基本查询
public void fun1(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1> 书写HQL语句
    String hql = " from Customer "; // 查询所有Customer对象
    //2> 根据HQL语句创建查询对象
    Query query = session.createQuery(hql);
    //3> 根据查询对象获得查询结果
    List<Customer> list = query.list(); // 返回list结果
    //query.uniqueResult();//接收唯一的查询结果
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        2) 别名查询

//别名查询
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();
}

        3) 排序查询

//排序查询
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();
}

        4) 条件查询

            按位置绑定

//条件查询
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1> 书写HQL语句
    String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
    //2> 根据HQL语句创建查询对象
    Query query = session.createQuery(hql);
    //设置参数
    //query.setLong(0, 1l);
    query.setParameter(0, 1l);
    //3> 根据查询对象获得查询结果
    Customer c = (Customer) query.uniqueResult();
 
    System.out.println(c);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

            按名称邦定

//条件查询
public void fun4(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1> 书写HQL语句
    String hql = " from Customer where cust_id = :cust_id "; // 查询所有Customer对象
    //2> 根据HQL语句创建查询对象
    Query query = session.createQuery(hql);
    //设置参数
    query.setParameter("cust_id", 1l);
    //3> 根据查询对象获得查询结果
    Customer c = (Customer) query.uniqueResult();
 
    System.out.println(c);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        5) 投影查询

            查询对象的某个或某些属性。

// 投影查询
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();
}

        6) 分页查询

//分页查询
public void fun5(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1> 书写HQL语句
    String hql = " from Customer  "; // 查询所有Customer对象
    //2> 根据HQL语句创建查询对象
    Query query = session.createQuery(hql);
    //设置分页信息 limit ?,?
    query.setFirstResult(1);
    query.setMaxResults(1);
    //3> 根据查询对象获得查询结果
    List<Customer> list =  query.list();
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        7) 分组统计查询

//分组统计查询
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();
}

        8) 多表查询

//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();
}

    2.Criteria

        1) 基本查询

//基本查询
public void fun1(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
 
    //查询所有的Customer对象
    Criteria criteria = session.createCriteria(Customer.class);
 
    List<Customer> list = criteria.list();
 
    System.out.println(list);
 
    //Customer c = (Customer) criteria.uniqueResult();
 
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联 
}

        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) 条件查询

//条件查询
//HQL语句中,不可能出现任何数据库相关的信息的
// >                gt
// >=               ge
// <                lt
// <=               le
// ==               eq
// !=               ne
// in               in
// between and      between
// like             like
// is not null      isNotNull
// is null          isNull
// or               or
// and              and
public void fun2(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //添加查询参数 => 查询cust_id为1的Customer对象
    criteria.add(Restrictions.eq("cust_id", 1l));
    //执行查询获得结果
    Customer c = (Customer) criteria.uniqueResult();
    System.out.println(c);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        4) 分页查询

//分页查询
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //设置分页信息 limit ?,?
    criteria.setFirstResult(1);
    criteria.setMaxResults(2);
    //执行查询
    List<Customer> list = criteria.list();
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        5) 查询总记录数

//查询总记录数
public void fun4(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //设置查询的聚合函数 => 总行数
    criteria.setProjection(Projections.rowCount());
    //执行查询
    Long count = (Long) criteria.uniqueResult();
 
    System.out.println(count);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        6) 离线条件查询

            脱离session使用

//离线条件查询
public void demo6(){
    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
    detachedCriteria.add(Restrictions.like("cust_name", "李%"));
 
    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();
}

    3.SQLQuery

        1) 基本查询

//基本查询
public void fun1(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer";
 
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
 
    //3 调用方法查询结果
    List<Object[]> list = query.list();
    //query.uniqueResult();
 
    for(Object[] objs : list){
        System.out.println(Arrays.toString(objs));
    }
 
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}
//基本查询
public void fun2(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer";
 
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
 
    //3 调用方法查询结果
    List<Customer> list = query.list();
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        2) 条件查询

//条件查询
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer where cust_id = ? ";
 
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
 
    query.setParameter(0, 1l);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
 
    //3 调用方法查询结果
    List<Customer> list = query.list();
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

        3) 分页查询

//分页查询
public void fun4(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer  limit ?,? ";
 
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
 
    query.setParameter(0, 0);
    query.setParameter(1, 1);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
 
    //3 调用方法查询结果
    List<Customer> list = query.list();
 
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

九、Hibernate一对多关联映射

    1.一的情况配置

        1) 创建持久类(假如一个客户有多个联系人)

// 一个客户有多个联系人:客户中应该放有联系人的集合。
private Set<LinkMan> linkMans = new HashSet<LinkMan>();

        2) 客户的映射

<!-- 配置一对多的映射:放置的多的一方的集合 -->
<!-- 
    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="com.jzfblog.hibernate.domain.LinkMan"/>
</set>

    2.多的情况配置

        1) 创建持久类(一个联系人对应一个客户)

// 面向对象的ORM
private Customer customer;

        2) 联系人的映射

<!-- 配置多对一的关系:放置的是一的一方的对象 -->
<!-- 
    many-to-one标签
        * name      :一的一方的对象的属性名称。
        * class     :一的一方的类的全路径。
        * column    :在多的一方的表的外键的名称。
 -->
<many-to-one name="customer" class="com.jzfblog.hibernate.domain.Customer" column="lkm_cust_id"/>

十、Hibernate一对多级联操作

    1.什么叫做级联

        级联指的是,操作一个对象的时候,是否会同时操作其关联的对象。

    2.什么是级联的方向性

        操作一的一方的时候,是否操作到多的一方。
        操作多的一方的时候,是否操作到一的一方。

    3.级联保存或更新

        1) 保存客户

<!-- 
    set标签 :
        * name  :多的一方的对象集合的属性名称。
        * cascade:级联
-->
<set name="linkMans" cascade="save-update" inverse="true">
    ...
</set>

        2) 保存联系人

<!-- 
    many-to-one标签
        * name      :一的一方的对象的属性名称。
        * class     :一的一方的类的全路径。
        * column    :在多的一方的表的外键的名称。
 -->
<many-to-one name="customer" class="com.jzfblog.hibernate.domain.Customer" cascade="save-update" column="lkm_cust_id"/>

    4.级联删除

        删除一边的时候,同时将另一方的数据也一并删除。

<!-- 
    set标签 :
        * name  :多的一方的对象集合的属性名称。
        * cascade:级联
-->
<set name="linkMans" cascade="save-update, delete" inverse="true">
    ...
</set>

十一、Hibernate多对多关联映射

    1.用户的配置(用户与角色多对多关系)

<!-- 建立与角色的多对多的映射关系 -->
<!-- 
    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="com.jzfblog.hibernate.domain.Role" column="role_id"/>
</set>

    2.角色的配置(角色与用户多对多关系)

        因为多对多的关系中,采用的是中间表查询,所以必须有一方放弃外键维护权,一般由被动的一方放弃。

<!-- 与用户的多对多的映射关系 -->
<!-- 
    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="com.jzfblog.hibernate.domain.User" column="user_id"/>
</set>

十二、Hibernate的抓取策略(优化)

    1.什么是延迟加载?

        也可以说是懒加载,执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。

    2.延迟加载的分类

        1) 类级别的延迟加载

            指的是通过load方法查询某个对象,是否采用延迟。(使懒加载失效:在class标签上配置的lazy属性或使用final修饰持久类)。

        2) 关联级别的延迟

            指的是在查询到某个对象的时候,查询其关联的对象,是否采用延迟加载。(使懒加载失效:在set或many-to-one标签上配置lazy属性)。

    3.什么是抓取策略?

        Hibernate的抓取策略是Hibernate提升性能的一种手段,可以在获取关联对象的时候,对发送的语句进行优化,往往需要与延迟加载配合使用。

    4.set上的fetch和lazy

fetch:抓取策略,控制SQL语句格式
    select          :默认值,发送普通的select语句,查询关联对象
    join            :发送一条迫切左外连接查询关联对象
    subselect       :发送一条子查询查询其关联对象
lazy:延迟加载,控制查询关联对象的时候是否采用延迟
    true            :默认值,查询关联对象的时候,采用延迟加载
    false           :查询关联对象的时候,不采用延迟加载
    extra           :极其懒惰。
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。

    5.many-to-one上的fetch和lazy

fetch:抓取策略,控制SQL语句格式。
    select      :默认值,发送普通的select语句,查询关联对象。
    join        :发送一条迫切左外连接。
lazy:延迟加载,控制查询关联对象的时候是否采用延迟。
    proxy       :默认值,proxy具体的取值,取决于另一端的<class>上的lazy的值。
    false       :查询关联对象,不采用延迟。
    no-proxy    :(不会使用)
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。

    6.批量抓取

        同时查询多个对象的关联对象的时候,可以采用批量抓取进行优化。如果要实现批量抓取,可以通过配置batch-size来完成。

打赏 蒋振飞

取消

感谢您的支持,我会继续努力的!

扫码支持
一分也是爱     一块不嫌多

点击 支付宝 或 微信 打赏蒋振飞

打开支付宝扫一扫,即可进行扫码打赏哦

评论列表