0 回顾

0.1 hibernate主键生成策略

  1. 自然主键:

    1. assigned
  2. 代理主键:

    1. identity
    2. increment
    3. native
    4. hilo
    5. sequence
    6. uuid

0.2 hibernate基本查询

0.2.1 HQL

  • HQL:

    • session.createQuery(HQL);
    • Query - list()/uniqueResult()

      • setParameter(index/name, args);
      • setString/Int()

0.2.2 Criteria

  • Criteria:

    • session.createCriteria(class);
    • add(Restrictions.idEq(id)/eq("name", arg))
    • list/uniqueResult

0.2.3 SQL

  • SQL:

    • session.createSQLQuery(sql);,API同Query
    • addEntity(class) -> 指定封装类型

0.3 hibernate事务

  • 事务级别

    1. 读未提交、
    2. 读已提交、
    3. 可重复读、
    4. 串行化
  • 开启事务:

    • servicedao:执行sql,用到同一个session
    • getCurrentSession()
    • property:current_session_context_class=thread

      <!-- 配置session和当前线程绑定
                  "current_session_context_class" thread
      -->
      <property name="current_session_context_class">thread</property>

一、表关联的关系

  1. 1-n:在n的一方添加1的一方的主键作为外键
  2. n-n:需要第三张表存储各自外键

1.1 一对多(1-n)

1.1.1 添加关联关系

//
    @Test
    public void test01() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 准备Customer对象
        Customer c1 = new Customer();
        c1.setCust_name("百度");
        Customer c2 = new Customer();
        c2.setCust_name("网易");
        
        // 2> 准备Linkman对象
        Linkman l1 = new Linkman();
        l1.setLkm_name("老王");
        Linkman l2 = new Linkman();
        l2.setLkm_name("老张");
        Linkman l3 = new Linkman();
        l3.setLkm_name("老李");
        Linkman l4 = new Linkman();
        l4.setLkm_name("老刘");
        
        // 3>添加关联关系
        c1.getLinkmen().add(l1);
        c1.getLinkmen().add(l2);
        
        l1.setCustomer(c1);
        l2.setCustomer(c1);
        
        c2.getLinkmen().add(l3);
        c2.getLinkmen().add(l4);
        
        l3.setCustomer(c2);
        l4.setCustomer(c2);
        
        // 4> 将对象持久化
        session.save(c1);
        session.save(c2);
        // cascade="save-update" 可以省略如下代码
//        session.save(l1);
//        session.save(l2);
//        session.save(l3);
//        session.save(l4);
        
        // --------------------
        tx.commit();
        session.close();
    }

1.1.1.1 被引用表(1表)配置文件

<?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 package="beans">
    <class name="Customer" table="cst_customer" >
        <id name="cust_id" >
            <generator class="native" ></generator>
        </id>
        <property name="cust_name" ></property>
        <property name="cust_source"></property>
        <property name="cust_industry"></property>
        <property name="cust_level"></property>
        <property name="cust_phone"></property>
        <property name="cust_mobile"></property>
        
        <!-- 配置一对多关系 -->
        <!-- set:表示一对多
              |- name:多的一方属性名
              |- inverse:是否放弃外键维护,
                            默认为"false",不放弃
                            true,放弃维护,只有 1的一方 才能放弃
              |- cascade:级联操作选项
                      save-update:保存Customer的时候,自带的Linkman一起保存
                      delete:级联删除
                      all: save-update + delete
             key - column:表示自己被别人引用的外键名
             one-to-many - class:多的一方的引用类型
         -->
        <set name="linkmen" inverse="true" cascade="save-update">
            <key column="lkm_cust_id"></key>
            <one-to-many class="Linkman"/>
        </set>
        
    </class>
</hibernate-mapping>
  • <font color="red">重点</font>
        <set name="linkmen" inverse="true" cascade="save-update">
            <key column="lkm_cust_id"></key>
            <one-to-many class="Linkman"/>
        </set>
  • 属性辨析:

    • set

      1. name多的一方属性名
      2. inverse:是否放弃外键维护

        • 默认为"false",不放弃
        • true,放弃维护,只有 1的一方 才能放弃
      3. cascade:级联操作选项

        • save-update:保存Customer的时候,自带的Linkman一起保存
        • delete:级联删除
        • all: save-update + delete
    • key

      1. column:表示<font color="red">自己被别人引用</font>的外键名
    • one-to-many

      1. class多的一方的引用类型

1.1.1.2 被应用表(n表)配置文件

<?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 package="beans">
    <class name="Linkman" table="cst_linkman" >
        <id name="lkm_id" >
            <generator class="native" ></generator>
        </id>
        <property name="lkm_name" ></property>
        <property name="lkm_gender"></property>
        <property name="lkm_phone"></property>
        <property name="lkm_mobile"></property>
        <property name="lkm_email"></property>
        <property name="lkm_qq"></property>
        <property name="lkm_position"></property>
        <property name="lkm_memo"></property>
        
        <!-- 配置多对一关系 -->
        <!-- many-to-one:
                |- name:引用一的一方的属性名
                |— column:外键字段
                |- class:外键对应类型是什么
         -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer" ></many-to-one>
        
    </class>
</hibernate-mapping>
  • <font color="red">重点</font>
<!-- 配置多对一关系 -->
<!-- many-to-one:
       |- name:引用一的一方的属性名
       |— column:外键字段
       |- class:外键对应类型是什么
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" ></many-to-one>
  • 属性辨析

    • many-to-one

      1. name:引用1的一方的属性名
      2. column:外键字段
      3. class:外键对应类型

1.1.2 删除操作

    // 删除客户1
    @Test
    public void test02() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 查找id为1的客户对象
        Customer customer = session.get(Customer.class, 2l);
        
        System.out.println(customer.getLinkmen());
        
        // 2> 删除customer对象
        session.delete(customer);
        // 所关联的联系人一起删掉:cascade=delete
        // --------------------
        tx.commit();
        session.close();
    }
    
//----------------------------------
    // 删除客户2,保留他原先的联系人
    @Test
    public void test03() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 查找id为1的客户对象
        Customer customer = session.get(Customer.class, 2l);
        
        System.out.println(customer.getLinkmen());
        // 2> 取消关联关系 - 外键
        for (Linkman lk : customer.getLinkmen()) {
            lk.setCustomer(null);//手动取消
        }
        
        // 3> 删除customer对象
        session.delete(customer);
        
        // --------------------
        tx.commit();
        session.close();
    }

1.2 多对多(n-n)

1.2.1 添加用户、角色/权限

    @Test
    // 添加用户、角色/权限
    public void test01() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 准备User对象
        User u1 = new User();
        u1.setUser_code("zhangsan");
        u1.setUser_name("张三");
        
        User u2 = new User();
        u2.setUser_code("lucy");
        u2.setUser_name("露西");
        
        // 2> 准备Role对象
        Role r1 = new Role();
        r1.setRole_name("经理");
        
        Role r2 = new Role();
        r2.setRole_name("保安");
        
        // 3>添加关联关系
        u1.getRoles().add(r1);
        u1.getRoles().add(r2);
        u2.getRoles().add(r1);
        u2.getRoles().add(r2);
        
        r1.getUsers().add(u1);
        r1.getUsers().add(u2);
        r2.getUsers().add(u1);
        r2.getUsers().add(u2);
        
        // 4> 将对象持久化
        session.save(u1);
        session.save(u2);
//        session.save(r1);
//        session.save(r2);
        
        // --------------------
        tx.commit();
        session.close();
    }

1.2.2 添加新的权限

    @Test
    // 给lucy添加新的权限
    public void test02() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 获得lucy对象
        User lucy = session.get(User.class, 2l);
        
        // 2> 新建新的权限
        Role role = new Role();
        role.setRole_name("财务");
        
        // 3> 设置关联关系
        lucy.getRoles().add(role);
        role.getUsers().add(lucy);
        
        // 4> 保存role
        session.save(role);
        
        // --------------------
        tx.commit();
        session.close();
    }

1.2.3 删除权限

    @Test
    // 给张三删除 除了保安以外的权限
    public void test03() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // 1> 获得张三对象
        User user = session.get(User.class, 1l);
        
        // 2> 获得经理对象
        Role role = session.get(Role.class, 1l);
        
        // 3> 从张三中删除经理
        user.getRoles().remove(role);
        role.getUsers().remove(user);
        
        // HashSet 删除原理 hashCode equals(Role 和 User必须重写equals和hashCode放法)
        
        // --------------------
        tx.commit();
        session.close();
    }    

1.2.4 中间表的配置文件

  • User
        <!-- 多对多关系 -->
        <!-- set: 多对多
               |- name: 包含的属性名
               |- table: 第三张表
             key:
               |- column: 别人引用“我”的外键名  - 第三张表中
             many-to-many:
               |- class: 包含的属性对应的完整类名
               |- column: “我”引用别人的外键
         -->
        <set name="roles" table="sys_user_role" cascade="save-update">
            <key column="user_id"></key>
            <many-to-many class="Role" column="role_id"></many-to-many>
        </set>
  • Role表
        <!-- 多对多哪方放弃外键维护,都可以
             业务角度来说,是后添加的来维护外键
         -->
        <set name="users" table="sys_user_role" inverse="true">
            <key column="role_id"></key>
            <many-to-many class="User" column="user_id"></many-to-many>
        </set>
  • 总结:<font color="red">set属性中多了table属性,中间表的表名</font>

    • 外键维护:

      • 一对多元素添加的时候,外键添加了两次,说明外键被双方维护
      • 减少不必要的外键维护,<font color="red">一定需要有一方放弃外键维护</font>
      • inverse="true",减少不必要的sql语句
    • 级联操作:减少java代码书写

      • cascade

        • save-update
        • delete
        • all

二、查询总结

2.1 oid查询 - get/load

  • 根据主键查询

2.2 对象属性导航查询 - customer.getLinkmen()

  • 通过查询结果的属性进行导航查询

2.3 HQL

2.3.1 查询全部

  • HQL语句:from com.ruki.crm.Customer
@Test
    public void test01() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
//        String hql = "from Customer"; // 简化写法:工程中只有唯一的Custoemr类
        // from Customer - hql:*不能用
        String hql = "from beans.Customer"; // 完整写法
//        String hql = "from java.lang.Object"; // 查询所有对象
        // select cust_id, cust_name from cst_customer
        // 查询出来的结果,每条记录都封装成一个Object数组
        String hql1 = "select cust_id, cust_name from Customer";
        // 要求:有对应的构造器
        String hql2 = "select new Customer(cust_id, cust_name) from Customer";
        
        Query query = session.createQuery(hql2);
        List list = query.list();
        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }
  • <font color="red">重点步骤</font>

    1. 写HQL语句:

      1. 查询所有的完整写法:String hql = "from beans.Customer";
      2. 查询含特定字段的Customer对象:String hql2 = "select new Customer(cust_id, cust_name) from Customer";

        • <font color="red">前提是必须要有有参构造器</font>
    2. 传入HQL语句,生成Query对象。Query query = session.createQuery(hql2);
    3. Query对象,返回查询结果。List list = query.list();

2.3.2 条件查询

  • 在HQL语句中添加where条件即可

2.3.3 分页查询

@Test
    // 分页查询
    public void test02() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        String hql = "from Linkman";
        
        Query query = session.createQuery(hql);
        // 设置分页显示 最开始条数、每页显示条数
        // select * from cst_customer limit 0, 2;
        query.setFirstResult(0); // startRow 从0开始
        
        query.setMaxResults(2); // pageSize
        
        List list = query.list();
        System.out.println(list);
        
        // --------------------
        tx.commit();
        session.close();
    }

2.3.4 聚合函数

@Test
    // 聚合函数
    public void test03() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        // select count(*) from cst_customer
        // select count(cust_id) from Customer
        String hql = "select count(cust_id) from Customer";
        Query query = session.createQuery(hql);
        Number count = (Number) query.uniqueResult();
        
        System.out.println(count);
        // --------------------
        tx.commit();
        session.close();
    }
  • <font color="red">重点步骤</font>

    • HQL语句的编写,在原生sql语句中进行改进

      -- 原生sql 
      select count(*) from cst_customer
      -- HQL
      select count(cust_id) from Customer
      

2.3.5 表链接(关联查询)

  • 关联查询的sql语句

    -- 内连接 
    -- 隐式内连接:等值链接 
    select * from cst_customer c,cst_linkman l 
      where c.cust_id = l.lkm_cust_id 
    -- 显示内连接: 
    select * from cst_customer c 
      [inner] join cst_linkman l
      on c.cust_id = l.lkm_cust_id 
    -- 左外 
    select * from cst_customer c 
      [outer] left join cst_linkman l 
      on c.cust_id = l.lkm_cust_id 
    -- 右外 
    select * from cst_customer c 
      [outer] right join cst_linkman l 
      on c.cust_id = l.lkm_cust_id 
    

2.3.5.1 迫切内连接

from Customer c join fetch c.linkmen
  • fetch将返回结果包装成对象

2.3.5.2 迫切左外连接

from Customer c left join fetch c.linkmen

2.3.5.3 迫切右外连接

from Customer c right join fetch c.linkmen
    @Test
    public void test05() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
//        String hql = "from Customer c join fetch c.linkmen";
//        String hql = "from Customer c left join fetch c.linkmen";
        String hql = "from Customer c right join fetch c.linkmen";
        Query query = session.createQuery(hql);
        List list = query.list();

        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.3.6 排序

@Test
    // 排序
    public void test04() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        String hql = "from Customer order by cust_id desc";
        Query query = session.createQuery(hql);
        List list = query.list();
        
        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.4 Criteria(没有HQL和SQL语句)

2.4.1 查询全部

  • 没有添加任何条件,即为查询全部。
@Test
    // 查询全部
    public void test01() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        Criteria criteria = session.createCriteria(Customer.class);
        List list = criteria.list();
        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.4.2 条件查询

  • 添加条件:criteria.add(Restrictions.le("lkm_id", 9l));
@Test
    // 条件查询全部
    /*
     * =         eq(属性名,值)
     * >        gt(属性名,值)
     * >=        ge
     * <        lt
     * <=        le
     * <>        ne
     * in        in(属性名,集合)
     * between and    between(属性名,值1,值2)
     * like        like
     * is null    isNull
     * is not null    isNotNull
     * or         or(条件1,条件2,条件3...)    
     * and        add/and
     * select * from cst_linkman where lkm_name like '%李%' or lkm_id > 8
     */
    public void test06() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        Criteria criteria = session.createCriteria(Linkman.class);
        criteria.add(Restrictions.le("lkm_id", 9l))
            .add(
                Restrictions.or(
                        Restrictions.like("lkm_name", "%李%"),
                        Restrictions.gt("lkm_id", 8l)));
        List list = criteria.list();
        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.4.3 分页查询

  • 设置起始数据位置:criteria.setFirstResult(0);
  • 设置最大查询数量:criteria.setMaxResults(2);
@Test
    // 分页查询
    public void test02() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.setFirstResult(0);
        criteria.setMaxResults(2);
        
        List list = criteria.list();
        System.out.println(list);

        // --------------------
        tx.commit();
        session.close();
    }

2.4.4 聚合函数

  • 添加聚合函数字段:criteria.setProjection(Projections.rowCount());
@Test
    // 聚合函数
    public void test03() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        Criteria criteria = session.createCriteria(Customer.class);
        // select count(*) from customer where id>5;
        // Projections
        criteria.setProjection(Projections.rowCount());
//        criteria.add(arg0)
        
        List list = criteria.list();
        criteria.uniqueResult();
        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.4.5 排序

  • 添加排序规则:criteria.addOrder(Order.desc("cust_id"));
@Test
    // 排序
    public void test04() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------
        Criteria criteria = session.createCriteria(Customer.class);
        
        // criteria添加排序规则
        criteria.addOrder(Order.desc("cust_id"));
        
        List list = criteria.list();

        System.out.println(list);
        // --------------------
        tx.commit();
        session.close();
    }

2.5 Criteria离线查询(在session前添加条件)

  • 创建离线Criteria对象:DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
  • 添加条件:dc.add(Restrictions.like("cust_name", "%李%"));
@Test
    public void test01() {
        // 模拟web层/service
        // 凭空创造Criteria对象
        DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
        // dc拼接条件的用法和Criteria完全一样
        dc.add(Restrictions.like("cust_name", "%李%"));
        
        List<Customer> list = findCustomerByCriteria(dc);
        System.out.println(list);
    }
    
    // 条件的拼接,以后可以在web层、也可以在service层
    // 问题 Criteria 和 session绑定 
    // session最大范围,service层
    // web层拼接条件 提供了离线版Criteria对象
    // 模拟dao
    public List<Customer> findCustomerByCriteria(DetachedCriteria dc) {
        Session session = HibernateUtils.openSession();
        Criteria criteria = dc.getExecutableCriteria(session);
        return criteria.list();
    }

2.6 SQL查询

  1. 写SQL语句:String sql = "select * from cst_customer where cust_name=?";
  2. 获得SQLQuery对象:SQLQuery sqlQuery = session.createSQLQuery(sql);
  3. 设置查询参数:sqlQuery.setParameter(0, "阿里巴巴");
  4. 获得结果集:Customer customer = (Customer) sqlQuery.uniqueResult();
  • <font color="red">具体代码见Hibernate_02笔记中的5.3部分</font>

三、查询优化策略

3.1 类级别:懒加载

  • lazy - true/false

    • 默认true
  • get - 不存在查询优化策略,查的时候直接获得结果
  • load - 查询时,得到代理对象

    • 使用对象的时候,才真正查询,获得内容

3.2 表关联级别

  • fetch:

    • select :默认,单表查询
    • join:关联查询
    • subselect:子查询
  • lazy:

    • true :默认,懒加载
    • false:关闭懒加载
    • extra:及其懒惰
  • 结论:优化策略使用默认值
package test;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;

import beans.Customer;
import utils.HibernateUtils;

public class QueryDemo {
    @Test
    public void test01() {
        Session session = HibernateUtils.openSession();
        
        Customer customer = session.load(Customer.class, 3l);
        
        System.out.println(customer);
    }
    
    @Test
    // fetch: select - 单表查询 (默认)
    // lazy: true - 懒加载 (默认)
    //          false - 立即加载(查父表时,子表同步查询)
    //         extra - 极其懒惰,用到什么数据,查什么数据
    public void test02() {
        Session session = HibernateUtils.openSession();
        
        Customer customer = session.load(Customer.class, 3l);
        
        System.out.println(customer);
        
        System.out.println(customer.getLinkmen().size());
        System.out.println(customer.getLinkmen());
    }
    @Test
    // fetch: join - 关联查询
    // lazy: 失效
    public void test03() {
        Session session = HibernateUtils.openSession();
        
        Customer customer = session.load(Customer.class, 3l);
        
        System.out.println(customer);
        
        System.out.println(customer.getLinkmen().size());
        System.out.println(customer.getLinkmen());
    }
    
    @Test
    // fetch: subselect - 子查询
    // lazy: true
    public void test04() {
        Session session = HibernateUtils.openSession();
        
        String sql = "from Customer";
        Query query = session.createQuery(sql);
        
        List<Customer> list = query.list();
        
        for (Customer c : list) {
            System.out.println(c);
            System.out.println(c.getLinkmen().size());
            System.out.println(c.getLinkmen());
        }
        
    }
}
Last modification:August 29th, 2019 at 08:16 pm