柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • Java基础

  • JavaWeb

  • 拓展技术

  • 框架技术

  • 数据库

    • MySQL
    • JDBC
    • Hibernate
      • Hibernate架构
        • 配置对象
        • 会话工厂对象
        • 会话对象
        • 事务对象
        • 查询对象
        • 约束对象
      • 配置属性
      • 映射文件
      • Hibernate应用
        • 搭建环境 IDEA
        • 连接操作
      • 注解
      • 反向工程
      • 关联映射
        • 一对多
        • 多对多
      • 高级查询
        • Query
        • Criteria
      • 缓存机制
        • 一级缓存
        • 二级缓存
      • Hibernate问题
    • Mybatis
    • Redis
    • Redis原理篇
  • 数据结构

  • Spring

  • SpringMVC

  • SpringBoot

  • SpringClound

  • Ruoyi-Vue-Plus

  • 后端
  • 数据库
柏竹
2020-02-18
目录

Hibernate

# Hibernate

Hibernate 将 Java对象与数据库表之间建立起映射关系,并提供了一系列数据访问接口,可随心所欲对库进行操作

好处:

  • Dao层开发简单
  • 兼容性好支持大多数主流数据库
  • 有二级缓存机制
  • 省略手动编写SQL语句(自动生成

Hibernate 开发包: Hibernate 官网 (opens new window)

目录说明:

  • documentation:开发文档
  • lib:依赖jar包
  • project:工程实例

学习参考文档:

  1. https://www.w3cschool.cn/hibernate/skzl1idz.html (opens new window)
  2. http://c.biancheng.net/hibernate/ (opens new window)

# ORM

ORM 是 Object Relational Mapping 的缩写,译为“对象关系映射”,它解决了对象和关系型数据库之间的数据交互问题

库与对象的关系

数据库 类对象
表 类
表记录(数据) 对象
表字段 对象属性

ORM缺点

  • 学习成本高
  • 自动生成SQL会消耗资源
  • 复杂的SQL难以处理(有时候不如手写SQL

好处上面有了(总之是JDBC使用的优化版

# Hibernate架构

# 配置对象

用于 连接数据库 / 创建类和表映射关系 的主要 配置文件

默认全局配置文件:hibernate.cfg.xml

# 会话工厂对象

SessionFactory对象 用于 分配线程的应用(安全线程),以防异步错乱的情况

# 会话对象

Session对象 用于与数据库的物理连接

详细说明:https://www.w3cschool.cn (opens new window)

# 事务对象

Transaction对象 每个事务代表 一个单元CRUD操作 (一个以上

# 查询对象

org.hibernate.Query对象 用于 自定义SQL / Hibernate语句 查询的数据集

对象获取

==Session.createQuery(String hql);==

常用方法(结果集获取

返回 方法 说明
R uniqueResult() 查询结果的单条数据,没有则null
List<R> list() 查询结果集以list形式的结果
Iterator<R> iterate() 查询结果集以迭代器形式的结果

注意:list()方法 返回的数据 如果不为 实体对象的属性,那么它返回的是 Object[]数组

# 约束对象

Criteria对象 指定查询对象

# 配置属性

属性 说明
hibernate.dialect 配选定指定 库 生成对应的SQL
hibernate.connection.driver_class 加载 JDBC驱动
hibernate.connection.url 连接库的url
hibernate.connection.username 用户名
hibernate.connection.password 密码
hibernate.connection.pool_size 连接池中连接的数量
hibernate.connection.autocommit 允许JDBC自动提交模式

mapping标签

  • resource 指定的是需要已经配置好的 ORM映射xml文件
  • class 指定实体对象(用于注解)

示例:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
   <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
       
   <property name="hibernate.connection.url">jdbc:mysql://localhost/test</property>
   <property name="hibernate.connection.username">root</property>
   <property name="hibernate.connection.password">root123</property>

   <mapping resource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration> 

# 映射文件

映射文件 主要用于 让配置文件对应对接的映射配置,但也与实体类对接

命名规则: ==<实体类名>.hbm.xml==

标签描述:

  • <hibernate-mapping>:根元素的 XML 文件

  • <class>:指定 实体类 -> 数据库表 的特定映射

    • name:实体类(全限定名
    • table:数据库表名称
  • <id>:类属性ID / 表ID字段 关联(唯一!!)

    • name:类属性名

    • column:表字段名

    • type:映射类型

    • <generator> 自动生成主键值

      • class:主键自增形式

        generator.class值 说明
        identity 库底层自增机制
        increment Hibernate实现自增
        assigned 字符串主键(算法生成
        sequence 序列生成主键
  • <property>:实体类属性 与 库表字段的匹配

    • name:类属性名
    • column:表字段名
    • type:映射类型

映射的数据类型:https://www.w3cschool.cn/hibernate/fzum1iem.html

示例:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name="Employee" table="EMPLOYEE">
      <meta attribute="class-description">
         This class contains the employee detail. 
      </meta>
      <id name="id" type="int" column="id">
         <generator class="identity"/>
      </id>
      <property name="firstName" column="first_name" type="string"/>
      <property name="lastName" column="last_name" type="string"/>
      <property name="salary" column="salary" type="int"/>
   </class>
</hibernate-mapping>

# Hibernate应用

Hibernate上机操作应用

# 搭建环境 IDEA

搭建步骤:

  1. 引入lib
  2. 连接数据库
  3. 项目结构 -> 模块 -> 选中项目 ->添加 Hibernate框架 (手动添加/生成 框架需要指定全局配置配置文件)

# 连接操作

应用前提:

  • 已经包含有 实体类/数据库数据 ,且他们的 实体类属性/数据库表字段 数据类型一致
  • ORM映射关系和全局配置已经完善

连接步骤:

  1. 读取解析 全局配置文件

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

  2. 读取解析映射信息,创建SessionFactiory

    ==SessionFactory sf = conf.buildSessionFactory();==

  3. 获取Session ==Session session = sf.openSession();==

  4. 启动事务

    ==Transaction tx = session.beginTransaction();==

  5. CRUD操作数据 (通过session进行操作

  6. 提交事务

  7. 关闭资源

应用工具类

注意:由于新版使用的是 服务注册的形式 进行应用的,因此步骤可能有不一样

package com.sans.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public class HibernateUtil {
    private static ServiceRegistry sr;
    private static SessionFactory sf;
    private static ThreadLocal<Session> localThread = new ThreadLocal<>();
    
    static {
        Configuration config = new Configuration().configure();
        sr = new ServiceRegistryBuilder().applySettings(
                config.getProperties()).buildServiceRegistry();
        config.buildSessionFactory(sr);
        sf = config.buildSessionFactory(sr);
    }
    
    /**
     * 获取会话
     */
    public static Session getSession() {
        Session session = localThread.get();
        if (session == null || ! session.isOpen()) {
            session = sf.openSession();
            localThread.set(session);
        }
        return session;
    }
    
    /**
     * 关闭会话
     */
    public static void close() {
        Session session = localThread.get();
        if (session != null) {
            session.close();
            localThread.remove();
            sf.close();
        }
    }
}

# 注解

Hibernate注解 是摆脱了 xml 配置文件的应用

应用前提:

  • Hibernate 3.x 以上的注释包
  • 关系jar包:
    • annotations.jar
    • hibernate-comons-annotations.jar
    • ejb3-persistence.jar

注释 范围 参数 说明
@Entity 类 - 标志位实体类 bean
@Table 类 String name 表名称
String catalog 目录
String schema 模式
UniqueConstraint[] uniqueConstraints 约束
映射表的配置
@Id 属性 - 主键
@GeneratedValue 属性 GenerationType strategy 策略
String generator
主键自动生成策略(一般默认即可)
@Column 属性 String name 允许唯一
int length 指定数据长度
boolean nullable 非空
boolean unique 唯一
定义属性与字段的细节属性

示例:

SQL:

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

实体对象:

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
   @Id @GeneratedValue
   @Column(name = "id")
   private int id;

   @Column(name = "first_name")
   private String firstName;

   @Column(name = "last_name")
   private String lastName;

   @Column(name = "salary")
   private int salary;  

   public Employee() {}
   public int getId() {
      return id;
   }
   public void setId( int id ) {
      this.id = id;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   public String getLastName() {
      return lastName;
   }
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   public int getSalary() {
      return salary;
   }
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

# 反向工程

反向工程操作原意 数据库表 -> 实体类

IDEA反向工程步骤:

**前提:**项目已 引入Hibernate框架

  1. 双击Shift -> 操作项搜索Persistence
  2. 选中项目右键 -> 生成持久映射
  3. 指定数据库映射即可

添加 数据构架的映射关系 添加关系映射关系一般用于 ==一对一 / 一对多 / 多对多== 的情况应用

确认必要信息

  • 源/目标 特定名称 (指定实体对象的属性名)

  • 源/目标 属性类型 (多则集合/少则对象

  • 联接列 必须选中 源的表字段/目标的表字段 两者是外键关系(一定要是外键关系

  • 多对多情况:需要手动指定联接表(第三表)进行对两表的进行连接

    需要手动确认4个列 分别为 ==源id / 第三表外键源id / 目标id / 第三表外键目标id==

# 关联映射

在关联映射当中有三种形式,分别为:

  • 一对一
  • 一对多
  • 多对多

# 一对多

一方: 多方 的实体集合 ,通过标签 <set> 完成

多方: 一方 的实体类,通过标签 <many-to-one>

必要标签说明:

<many-to-one>:多对一

  • name:关联对象的属性名
  • column:实体类对应的外键表字段名
  • class:关联对象类(全限定名

<set>:一对多

  • name:关联对象属性名
  • <key>.column:关联对象的外键名
  • <one-to-many>.class:关联对象类(全限定名

一般情况会反向自动生成的xml

联级操作:

<set>.cascade :联级操作

  • delete :联级删除
  • all : 联级增删改
  • sace-update :联级 增加/修改

一对多示例:(部门一 - 员工多)

Staff员工表

字段名 类型 说明 外键
id int - key
name varchar 名称 -
deptId int 部门id dept.id

Dept部门表

字段名 类型 说明 外键
id int - key
name varchar 部门名称 -

Staff员工实体-xml配置

// Staff.java 员工实体对象
public class Staff {
    private int id;
    private String name;
    // 主要关系对象
    private Dept dept;
    //get、set配置。。。
}
....
<!-- Staff.hbm.xml 配置 --> 
<hibernate-mapping>
    <!-- oneToMany.Staff 包路径 / staff 表名 --> 
    <class name="oneToMany.Staff" table="staff">
        <id name="id" column="id">
            <generator class="increment"></generator>
        </id>
        <property name="name"></property>
    	<!--  
                name: Staff实体类中的dept属性
                column: 子表中被外键约束修饰的字段名
				class: Staff相关联的Dept类
        -->
        <many-to-one name="dept" column="deptId" class="oneToMany.Dept"></many-to-one>
    </class>
</hibernate-mapping>

Dept员工实体-xml配置

public class Dept {
    private int id;
    private String name;
    // 建议手动创建初始化集合对象
    private Set<Staff> staffSet = new HashSet<>(0);
	// get、set配置。。。
}
....
<!-- Staff.hbm.xml 配置 -->
<hibernate-mapping>
    <class name="oneToMany.Dept" table="dept">
        <id name="id" column="id">
            <generator class="increment"></generator>
        </id>
        <property name="name"></property>
    	<!-- key:子表被外键约束修饰的字段名 --> 
        <set name="staffSet" cascade="all">
            <key column="deptId"/>
            <one-to-many class="oneToMany.Staff"/>
        </set>
    </class>    
</hibernate-mapping>

测试访问:

// 多对一
@Test
public void add(){
    // 假设已经获取到了 Session 对象
    
    //创建新部门
    Dept dept = new Dept();
    dept.setName("er部门");

  //创建新的职员
    Staff staff = new Staff();
    staff.setName("www");

  //给职员中添加部门
    staff.setDept(dept);
        
  //给部门中添加职员
    dept.getStaffSet().add(staff);
        
  //保存部门
    session.save(dept);
}

@Test
public void del(){
	// 假设已经获取到了 Session 对象
    // 指定查询id : 2
	Dept dept = (Dept) sesslin.get(Dept.class,2);
    session.delete(dept);
  	
    // 删除会连同指定相同的id:2的部门一起删除
}

@Test
public void find(){
    // 假设已经获取到了 Session 对象
 	Dept dept = (Dept) sesslin.get(Dept.class,2);
    System.out.println(dept);
    for(Staff staff : detp.getSeaff()){
        System.out.println(staff);
    }
}

# 多对多

多对多关系 是两表之间对多关系,通常会以第三表为中间作为两表联系的关系表。两张表都只和关系表间建立主外键关系!

<many-to-many>:多对多

  • name:关联对象的属性名
  • column:实体类对应的外键表字段名
  • class:关联对象类(全限定名

应用说明:

  • 多对多的应用 也需要 cascade 联级操作 的操作

**多对多示例:**(功能多 - 角色多) (不同角色有不同的功能

Menu菜单表

字段名 类型 说明 外键
m_id int - key
m_name varchar 菜单名称 -
m_state int 状态 -

Role角色表

字段名 类型 说明 外键
r_id int - key
r_name varchar 角色名称 -
r_state int 状态 -

关系表

字段名 类型 说明 外键
id int - key
m_id int 菜单id menu.id
r_id int 角色id role.id

Role角色实体-xml配置

public class Role {
    private int rId;
    private String rName;
    private Integer rState;
    private Set<Menu> menus = new HashSet<>(0);
	// get/set ... 
}
...
<!-- Role.hbm.xml 配置 -->
<hibernate-mapping>
    <!-- com.sans.pojo.Role 包路径 / role 表名 / hospital 数据库名 -->
    <class name="com.sans.pojo.Role" table="role" schema="hospital">
        <id name="rId">
            <column name="r_id" sql-type="int"/>
            <generator class="native"/>
        </id>
        <property name="rName">
            <column name="r_name" sql-type="varchar(80)" length="80" not-null="true"/>
        </property>
        <property name="rState">
            <column name="r_state" sql-type="int" not-null="true"/>
        </property>
        <!-- 联级操作第三表 需要配置 cascade="all" -->
        <set name="menus" table="role_menu" cascade="all">
            <!-- 外键字段 -->
            <key column="r_id"/>
            <!-- 集合对应的实体类 -->
            <many-to-many class="com.sans.pojo.Menu" column="m_id"/>
        </set>
    </class>
</hibernate-mapping>

Menu菜单实体-xml配置

public class Menu {
    private int mId;
    private String mName;
    private Integer mState;
    private Set<Role> roles = new HashSet<>(0);
	// get/set ...
}
....
<!-- Menu.hbm.xml 配置 -->
<hibernate-mapping>
    <class name="com.sans.pojo.Menu" table="menu" schema="hospital">
        <id name="mId">
            <column name="m_id" sql-type="int"/>
            <generator class="native"/>
        </id>
        <property name="mName">
            <column name="m_name" sql-type="varchar(80)" length="80" not-null="true"/>
        </property>
        <property name="mState">
            <column name="m_state" sql-type="int" not-null="true"/>
        </property>
        <!-- 联级操作第三表 需要配置 cascade="all" -->
        <set name="roles" table="role_menu" cascade="all">
            <!-- 外键字段 -->
            <key column="m_id"/>
            <!-- 集合对应的实体类 -->
            <many-to-many class="com.sans.pojo.Role" column="r_id"/>
        </set>
    </class>
</hibernate-mapping>

测试:

@Test
public void findByMenu() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    Menu menu = (Menu) session.get(Menu.class , 4);
    System.out.println("menu : " + menu);
    System.out.println("menu.roles : " + menu.getRoles());
    
    tx.commit();
    HibernateUtil.close();
}

@Test
public void findByRole() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    
    Role role = (Role) session.get(Role.class,1);
    System.out.println("role : " + role);
    System.out.println("role.menus : " + role.getMenus());
    
    tx.commit();
    HibernateUtil.close();

}

// 联级添加
@Test
public void add() {

    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    Menu menu = new Menu("xx管理",22);
    System.out.println("menu : " + menu);
    
    Role role1 = new Role("医生",1);
    Role role2 = new Role("主管",1);
    
    menu.getRoles().add(role1);
    menu.getRoles().add(role2);
    
    session.save(menu);
    
    tx.commit();
    session.close();
}

// 联级删除
@Test
public void del() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    // 根据指定的 Role.id进行删除
    Role role = new Role();
    role.setrId(39);
    
    // 指定 Menu.id进行删除
    // Menu menu = new Menu();
    // menu.setmId(23);
    
    session.delete(role);
    
    tx.commit();
    HibernateUtil.close();
}

# 高级查询

Hibernate 框架 提供了两个用于查询的对象分别为 Query、Criteria对象

Criteria对象 应用起来方法较多,自行了解:

https://www.w3cschool.cn/hibernate/ugov1ie8.html

# Query

query查询方式 依靠自行编写的 hql语句进行查询数据

query对象获取

==Session.createQuery(String hql)==

query常用方法

获取结果集方法

返回 方法 说明
R uniqueResult() 查询结果的单条数据,没有则null
List<R> list() 查询结果集以list形式的结果
Iterator<R> iterate() 查询结果集以迭代器形式的结果

**注意:**list()方法 返回的数据 如果不为 实体对象的属性,那么它返回的是 Object[]数组

其他方法

返回 方法 说明
Query setXX( String/int , XX) (XX为数据类型名) 填充hql语句的 数据/占位符
Query setFirstResult(int firstResult) 设置 查询起始行数
Query setMaxResults(int maxResults) 设置 查询最大行数

更多方法可以在自行查看源码

query查询示例

示例说明:

  • 仅展现功能代码块
  • 两表关系为 一对多 (一部门 - 多员工)

**数据库表**

dept部门表

字段名 类型 说明 外键
deptno int id key
dname varchar 部门名 -
loc varhcar 区 -

emp员工表

字段名 类型 说明 外键
empno int id key
ename varchar 员工名称 -
sal decimal (浮点型 工资 -
deptno int 部门id dept.deptno
public class Demo {

    // 对象查询
    @Test
    public void test01() {
        // 查 部门对象
        String hql = "from Dept";
        Session session = HibernateUtil.getSession();
        Query query = session.createQuery(hql);
        List<Dept> list = query.list();
        for (Dept dept : list) {
            System.out.println("dept : " + dept);
        }
    }
    
    // 属性查询
    @Test
    public void test02() {
        // 查 指定部门
        String hql = "select loc,deptno from Dept";
        Session session = HibernateUtil.getSession();
        Query query = session.createQuery(hql);
        List<Object[]> list = query.list();
        for (Object[] row : list) {
            System.out.println(row[0] + "\t - \t" + row[1]);
        }
        HibernateUtil.close();
    }
    
    // 约束查询1
    @Test
    public void test03() {
        String hql = "from Dept where dname = ?";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        query.setString(0 , "会计部");
        
        List<Dept> list = query.list();
        for (Dept dept : list) {
            System.out.println(dept);
        }
        
        tx.commit();
        HibernateUtil.close();
    }
    
    // 约束查询2
    @Test
    public void test04() {
        String hql = "from Dept where dname = :name ";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        query.setString("name" , "会计部");
        List<Dept> list = query.list();
        for (Dept dept : list) {
            System.out.println(dept);
        }
        tx.commit();
        HibernateUtil.close();
    }
    
    // 模糊查询
    @Test
    public void test11() {
        String hql = "from Emp where ename like :name";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        // 注意:不能含有单引号直接引用
        String name = "张";
        query.setString("name","%"+name+"%");
        List<Emp> list = query.list();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    
        tx.commit();
        HibernateUtil.close();
    }
    
    // 聚合查询
    @Test
    public void test05() {
        String hql = "select count(*) from Dept";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        Long count = (Long) query.uniqueResult();
        System.out.println("count : " + count);
        
        tx.commit();
        HibernateUtil.close();
    }
    
    // 分页查询
    @Test
    public void test06() {
        String hql = "from Emp";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
    
        int index = 2;
        int pageSize = 5;
        // 指定 起始位置 和 总量
        query.setFirstResult((index - 1) * pageSize);
        query.setMaxResults(pageSize);
        List<Emp> list = query.list();
        for (Emp e : list) {
            System.out.println(e);
        }
    
        tx.commit();
        HibernateUtil.close();
    }
    
    // 内连接
    @Test
    public void test07() {
        String hql = "from Emp e inner join e.dept";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
    
        // 将 emp的外键 deptno结合 dept 连接查询
        List<Object[]> list = query.list();
        for (Object[] row : list) {
            Emp emp = (Emp) row[0];
            Dept dept = (Dept) row[1];
            System.out.println("==========");
            System.out.println("emp : " + emp);
            System.out.println("dept : " + dept);
        }
    
        tx.commit();
        HibernateUtil.close();
    }
    
    // 追切内连接
    // 解决封装的问题
    @Test
    public void test08() {
        String hql = "from Emp e inner join fetch e.dept";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        List<Emp> list = query.list();
        for (Emp emp : list) {
            System.out.println(emp);
        }
        
        tx.commit();
        HibernateUtil.close();
    }
    
    // 左外连接
    @Test
    public void test09() {
        String hql = "from Dept d left outer join d.emps";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        List<Object[]> list = query.list();
        for (Object[] row : list) {
            Dept dept = (Dept) row[0];
            Emp emp = (Emp) row[1];
            System.out.println("dept : " + dept.getDname());
            if (emp != null) {
                System.out.println(" | "+emp);
            }else{
                System.out.println(" | 无员工");
            }
        }
        
        tx.commit();
        HibernateUtil.close();
    }
    
    // 追切左连接
    @Test
    public void test10() {
        String hql = "select distinct d from Dept d left outer join fetch d.emps";
        Session session = HibernateUtil.getSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery(hql);
        
        List<Dept> list = query.list();
        for (Dept dept : list) {
            System.out.println("dept : " + dept.getDname());
            Set<Emp> emps = dept.getEmps();
            if (emps != null && emps.size() > 0) {
                for (Emp emp : emps) {
                    System.out.println("\t" + emp.getEname());
                }
            } else {
                System.out.println("\t无员工");
            }
            
        }
        
        tx.commit();
        HibernateUtil.close();
    }

}

# Criteria

org.hibernate.Criteria是 面向对象的方式在进行数据查询,无需手写hql语句

特点:

  • 面向对象查询
  • 摆脱hql语句拼接的应用

Criteria对象获取

==Session.createCriteria(Class Bean)==

常用方法

获取结果集

返回 方法 说明
List list() 获取结果集列表
Object uniqueResult() 获取单个结果,没有则null

查询约束

返回 方法 参数 说明
Criterion add(Criterion criterion) 约束criterion对象 添加 约束条件
Criterion setMaxResults(int maxResults) 行最大值 设置 查询最大行数
Criterion setFirstResult(int firstResult) 行起始值 设置 查询起始行数
Criterion createCriteria(String associationPath) 属性数据集名称 添加数据集 内连接

org.hibernate.criterion.Criterion约束对象(一般应用传递约束

org.hibernate.criterion.Restrictions标准约束对象

Restrictions对象 内置封装了常用约束静态方法

常用约束方法

返回 方法 说明
Criterion idEq(Object value) 比较id
Criterion eq(String propertyName, Object value) 比较指定属性
Criterion like(String propertyName, Object value) 模糊指定属性
Criterion ilike(String propertyName, Object value) 模糊指定属性(省略大小写
Criterion and(Criterion lhs, Criterion rhs) 合并约束(同时满足)
Criterion or(Criterion lhs, Criterion rhs) 满足约束(其中满足)
Criterion not(Criterion expression) 约束取反(满足取反)
Criterion between(String propertyName, Object lo, Object hi) 选区范围值
.... .... ....

方法比较多 自行查询API

org.hibernate.criterion.Example实例对象约束

Example对象 内置实例对象查询的方法一般情况直接写入实例对象即可

// sfrom emp
List results = session.createCriteria(Emp.class)
      			.add( Example.create(emp).ignoreCase())
      			.list();

示例:

数据库表

dept部门表

字段名 类型 说明 外键
deptno int id key
dname varchar 部门名 -
loc varhcar 区 -

emp员工表

字段名 类型 说明 外键
empno int id key
ename varchar 员工名称 -
sal decimal (浮点型 工资 -
deptno int 部门id dept.deptno

PS:由于员工的工资属性sal 应用的是 BigDecimal 数据类型

// 普通类表查询
@Test
public void test01() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    Criteria cr = session.createCriteria(Emp.class);
    List<Emp> list = cr.list();
    for (Emp emp : list) {
        System.out.println(emp);
    }
    
    tx.commit();
    HibernateUtil.close();
}

// 约束查询
@Test
public void test02() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();

    Criteria cr = session.createCriteria(Emp.class);
    // 约束查 大于等于
    cr.add(Restrictions.ge("sal",new BigDecimal(5000)));
    List<Emp> list = cr.list();
    for (Emp emp : list) {
        System.out.println(emp);
    }
    
    tx.commit();
    HibernateUtil.close();
}


// 实例查询
@Test
public void test03() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    Criteria cr = session.createCriteria(Emp.class);

    Emp emp = new Emp();
    emp.setJob("CLERK");

    cr.add(Example.create(emp));
    List<Emp> list = cr.list();
    for (Emp e : list) {
        System.out.println(e);
    }
    
    tx.commit();
    HibernateUtil.close();
}

// 链式内连接查询
@Test
public void test04() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    List<Dept> depts =
            session.createCriteria(Dept.class)
                    .add(Restrictions.eq("dname","cqc"))
                    .createCriteria("emps")
                    .add(Restrictions.eq("ename","j4"))
                    .list();
    for (Dept dept : depts) {
        System.out.println(dept);
    }
    
    tx.commit();
    HibernateUtil.close();
}

// 表达式and约束查询
@Test
public void test05() {
    Session session = HibernateUtil.getSession();
    Transaction tx = session.beginTransaction();
    
    // 查工资大于5k 且 职位为 CLERK
    Criterion crSal = Restrictions.gt("sal",new BigDecimal(5000));
    Criterion crJob = Restrictions.eq("job","CLERK");

    List<Emp> emps =
    session.createCriteria(Emp.class)
            .add(Restrictions.and(crSal,crJob))
            .list();

    for (Emp emp : emps) {
        System.out.println(emp);
    }
    
    tx.commit();
    HibernateUtil.close();
}

# 缓存机制

# 一级缓存

Hibernate一级缓存是强制性的缓存,在 Session层(会话)

**清空缓存条件:**Session关闭、数据更变

# 二级缓存

Hibernate一级缓存是选择性的缓存,主要负责跨会话缓存对象。

需要直接配置策略

# Hibernate问题

  1. hql语句 问题

    • hql语句中的 表名的首字母一定要大写 (因:与类名一致,否则找不着
    • 遵守数据库命名规则
  2. 联级操作 问题

    • 要手动添加 <set>.cascade属性/<generator>.classid自增策略 的应用(因:反向生成不会生成

    • 在联级添加数据时,尽可能避免指定外键id值添加数据(因:id值约束可能影响数据的添加

    • 在联级添加数据时,一方 配置的 <set>.inverse属性为true ,会产生二级数据的外键id为空,解决方式方案:将含有主键的一方设为 关系维护方即可

      原因: 以上的设置是 将 一方的 关系维护 交给多方管理,那么多方 在插入数据时会 根据对象的联级关系进行插入的,而一方的主键id生成在写入数据库之后生成的,因此二级的外键id为空

    • 在联级删除 多的一方,<set>.cascade属性值不能为none

    • 在联级删除 单的一方时,不能含有该属性cascade

  3. 反向生成 问题

    • 反向生成xml,不会生成 <generator>.classid自增策略(因:id可能会相同导致异常
    • 反向生成实体对象,实体对象的 对多关系 的 集合数据 需要初始化 (因:不初始化联级操作可能会出现异常
  4. 对多数据 问题

    • 多对一 查询:<many-to-one>标签 添加 ==insert="false" update="false"==属性(因:在查询中可能会出现重复列的问题
    • 多对多 删除:多对多含有关系表的情况下,只要一方的数据被删除完,另一方还会存在数据指定的是双方的外键id(因:两表的外键约束的在第三方的关系表中,因此两表的是互补干扰的!
#Hibernate#数据库
上次更新: 2023/03/12, 00:43:49

← JDBC Mybatis→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式