主流的ORM(Object Relation Mapping:对象关系映射)框架,将面向对象映射成面向关系
一 Hibernate第一天
JavaEE的三层结构
- web层(视图层)
- servicer层(服务层)
- dao层(持久层)
MVC思想:
- M:模型
- V:视图
- C:控制器
1 hibernate概述
hibernate是应用在dao层中
hibernate底层代码就是jdbc,不需要写sql语句实现
hibernate开源轻量级框架
2 hibernate入门案例
- 导入相关依赖
- 创建Hibernate配置文件
- 创建实体类
- 创建实体类-关系映射文件
- 调用HibernateAPI完成操作
3 hibernate配置文件
Maven
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
<!--允许读取src下面的xml文件-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
hibernate.cfg.xml
// 核心配置:session-factory
// SessionFactory:针对单个数据库映射经过编译的内存镜像文件,将数据库转换为一个Java可以识别的镜像文件
// 构建SessionFatory非常耗费资源,所以通常一个工程只需要创建一个SessionFactory
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据源的配置 -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test?userUnicode&characterEncoding=UTF-8</property>
<!-- C3P0连接池 -->
<property name="hibernate.c3p0.acquire_increment">10</property>
<property name="hibernate.c3p0.idle_test_period">10000</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_size">30</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_statements">10</property>
<!-- 数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 打印sql -->
<property name="show_sql">true</property>
<!-- 格式化sql -->
<property name="format_sql">true</property>
<!-- 是否自动生成数据表 -->
<property name="hibernate.hbm2ddl.auto"></property>
</session-factory>
</hibernate-configuration>
4 创建实体关系映射文件
<?xml version="1.0"?>
<!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.wackyboy.domain.Customer" table="customer">
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
</class>
</hibernate-mapping>
5 实体关系映射文件注册到Hibernate的配置文件中
<!-- 注册实体关系映射文件 -->
<mapping resource="com/wackyboy/domain/People.hbm.xml"></mapping>
6 使用HibernateAPI完成数据操作
package com.wackyboy.test;
import com.wackyboy.domain.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 20:40
*/
public class Test {
public static void main(String[] args) {
// 创建Configuration
Configuration cfg = new Configuration().configure();
// 获取SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 获取Session对象
Session session = sessionFactory.openSession();
People people = new People();
people.setName("张三");
people.setMoney(10000);
session.save(people);
// 事务的提交
session.beginTransaction().commit();
session.close();
}
}
二 第二天
1 Hibernate的级联操作
一对多关系
客户和订单:客户一订单多
package com.wackyboy.domain;
import lombok.Data;
import java.util.Set;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 19:33
*/
@Data
public class Customer {
private Integer id;
private String name;
private Set<Orders> orders;
}
package com.wackyboy.domain;
import lombok.Data;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 19:54
*/
@Data
public class Orders {
private Integer id;
private String name;
private Customer customer;
}
多对多关系
学生选课:一门课可被多人选择,一个可选择多门课程
数据库中是通过两个一对多关系来维护的, 学生和课程都是主表,额外增加一张中间表作为从表,两张主表和中间表都是一对多的关系
package com.wackyboy.domain;
import lombok.Data;
import java.util.Set;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:24
*/
@Data
public class Account {
private Integer id;
private String name;
private Set<Course> courses;
}
package com.wackyboy.domain;
import java.util.Set;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:26
*/
public class Course {
private Integer id;
private String name;
private Set<Account> accounts;
}
2 Hibernate实现一对多
Customer的配置:
<?xml version="1.0"?>
<!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.wackyboy.domain.Customer" table="customer">
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<set name="orders" table="orders">
<key column="cid"></key>
<one-to-many class="com.wackyboy.domain.Orders"></one-to-many>
</set>
</class>
</hibernate-mapping>
- set标签来配置实体类中集合属性orders
- name实体类属性名
- table表名
- key外键
- one-to-many与集合泛型的实体类对应
Order的配置:
<?xml version="1.0"?>
<!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.wackyboy.domain.Orders" table="orders">
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<many-to-one name="customer" class="com.wackyboy.domain.Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>
- many-to-one配置实体类对应的对象属性
- name属性名
- class属性对应的类
- column外键
需要在Hiberbate配置文件中进行注册
<!-- 注册实体关系映射文件 -->
<mapping resource="com/wackyboy/domain/People.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Customer.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Orders.hbm.xml"></mapping>
HibernateAPi调用
package com.wackyboy.test;
import com.sun.org.apache.xpath.internal.operations.Or;
import com.wackyboy.domain.Customer;
import com.wackyboy.domain.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:54
*/
public class Test2 {
public static void main(String[] args) {
// 创建Configuration
Configuration cfg = new Configuration().configure();
// 获取SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 获取Session对象
Session session = sessionFactory.openSession();
// 创建Customer对象
Customer customer = new Customer();
customer.setName("李四");
// 创建Orders
Orders orders = new Orders();
orders.setName("订单1");
// 建立关联关系
orders.setCustomer(customer);
// 保存
session.save(customer);
session.save(orders);
// 提交事务
session.beginTransaction().commit();
session.close();
}
}
3 Hibernate实现多对多
<?xml version="1.0"?>
<!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.wackyboy.domain.Account" table="t_account">
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<set name="courses" table="account_course">
<key column="aid"></key>
<many-to-many class="com.wackyboy.domain.Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
- name实体类对应的集合属性名
- table中间表名
- key外键
- many-to-many与集合泛型的实体类对应
- column属性与中间表的外键字段名对应
- 注册到Hibernate配置文件中
package com.wackyboy.test;
import com.wackyboy.domain.Account;
import com.wackyboy.domain.Course;
import com.wackyboy.domain.Customer;
import com.wackyboy.domain.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.HashSet;
import java.util.Set;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:54
*/
public class Test3 {
public static void main(String[] args) {
// 创建Configuration
Configuration cfg = new Configuration().configure();
// 获取SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 获取Session对象
Session session = sessionFactory.openSession();
Course course = new Course();
course.setName("Java");
Account account = new Account();
account.setName("tiantian");
Set<Course> courses = new HashSet<Course>();
courses.add(course);
account.setCourses(courses);
session.save(course);
session.save(account);
// 提交事务
session.beginTransaction().commit();
session.close();
}
}
三 第三天
1 Hibernate的延迟加载
延迟加载、惰性加载、懒加载
使用延迟加载么一提高程序的运行效率,Java程序与数据库交互的频次越低,程序的运行效率越高,Hibernate的延迟加载很好的做到了这一点
场景
- 客户和订单,当我们查询客户对象的时候,因为有级联设置,所以会将对应的订单信息一并查询出来,这样就需要发送两条SQL语句,分别查询客户信息和订单信息
- 延迟加载的思路:当我们查询客户的时候,如果没有访问订单的数据,只发送一条SQL语句查询客户的信息,如果需要访问订单数据,则发送两条SQL
- 延迟加载可以看作是一种优化机制,根据具体的需求,自动选择要执行得到SQL语句数量
案例一:一对多
- 查询Customer,对Orders进行延迟加载设置,在customer.hbm.xml中进行设置, 延迟加载默认开启
<set name="orders" table="orders" lazy="true">
<key column="cid"></key>
<one-to-many class="com.wackyboy.domain.Orders"></one-to-many>
</set>
- 查询Customer
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:54
*/
public class Test4 {
public static void main(String[] args) {
// 创建Configuration
Configuration cfg = new Configuration().configure();
// 获取SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 获取Session对象
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class, 4);
System.out.println(customer);
Sytem.out.println(customer.getOrders());
session.close();
}
}
lazy 除了可以设置true个false之外,还可以设置extra,extra是比true更加懒惰的一种加载方式,或者说是更加只能的一种加载方式
也可以通过Orders来设置Customer的延迟加载,orders.hbm.xml中进行设置, lazy=”proxy”
<many-to-one name="customer" class="com.wackyboy.domain.Customer" column="cid" lazy="proxy"></many-to-one>
- no-proxy:当调用方法需要访问customer的成员变量时,发送SQl语句查询Customer,否则不查询
- proxy:无论调用的方法需要访问customer的成员变量,都会发送SQL语句查询
案例二:多对多
2 Hibernate的配置文件
<hibernate-configuration>
<session-factory>
<!-- 数据源的配置 -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&userUnicode&characterEncoding=UTF-8</property><!--serverTimezone=Asia/Shanghai-->
<!-- C3P0连接池 -->
<property name="hibernate.c3p0.acquire_increment">10</property>
<property name="hibernate.c3p0.idle_test_period">10000</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_size">30</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_statements">10</property>
<!-- 数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 打印sql -->
<property name="show_sql">true</property>
<!-- 格式化sql -->
<property name="format_sql">true</property>
<!-- 是否自动生成数据表 -->
<property name="hibernate.hbm2ddl.auto"></property>
<!-- 注册实体关系映射文件 -->
<mapping resource="com/wackyboy/domain/People.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Customer.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Orders.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Account.hbm.xml"></mapping>
<mapping resource="com/wackyboy/domain/Course.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
- hibernate.xml:配置Hibernate的全局环境
- 数据库的基本信息
- 继承C3P0,设置数据库连接信息
- Hibernate的基本信息
- 注册实体关系映射文件
- hbm.xml:实体关系映射文件
- hibernate-mapping
- package:实体类对应的包名
- schema:数据库schema的名称
- catalog:数据库catalog的名称
- default-cascade:默认的级联关系,默认为none
- default-access:Hibernate用来访问属性的策略
- default-lazy:指定了未明确著名lazy属性的Java属性和集合类,Hibernate会采用什么样的加载风格,默认为true
- auto-import:指定我们是否可以在查询语句中使用非全限定类名,默认为true,如果项目中有两个同名的持久化类,最好在这两个对应的映射文件中配置为false
- class属性:
- name
- table
- schema:数据库schema的名称,会覆盖上级
- catalog:数据库catalog的名称,同上
- proxy:指定一个接口,在延迟加载时作为代理使用
- dynamic-update:动态更新
- dynamic-insert:动态添加
- where:查询时给SQL添加where条件
- id属性
- name:实体类属性名
- type:实体类属性数据类型,此处可以设置两种类型的数据:Java数据类型或者Hibernate映射类型,实体类的属性护具类型必须与数据表对应的字段类型一致
- Java数据类型映射到Hibernate映射类型,再由Hibernate映射类型映射到SQL数据类型上
- column:数据表的主键字段名
- generator:主键生成策略
- hilo算法
- increment:Hinerbate自增
- identity:数据库自增
- native:本地策略,根据底层数据库自动选择主键的生成策略
- uuid.hex算法
- select算法
- property属性
- name:实体类的属性名
- column:
- hibernate-mapping
<class name="com.wackyboy.domain.People" table="people" dynamic-insert="true" dynamic-update="true">
<class name="com.wackyboy.domain.People" table="people" dynamic-insert="true" where="id = 1">
package com.wackyboy.test;
import com.wackyboy.domain.Orders;
import com.wackyboy.domain.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
/**
* @Author: WackyBoy
* @Date: 2021/3/4 21:54
*/
public class Test6 {
public static void main(String[] args) {
// 创建Configuration
Configuration cfg = new Configuration().configure();
// 获取SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 获取Session对象
Session session = sessionFactory.openSession();
String hql = "from People";
Query query = session.createQuery(hql);
List<People> list = query.list();
for(People people : list) {
System.out.println(people);
}
session.beginTransaction().commit();
session.close();
}
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.wackyboy.domain">
<class name="Course" table="t_course">
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<set name="accounts" table="account_course">
<key column="cid"></key>
<many-to-many class="Account" column="aid"></many-to-many>
</set>
</class>
</hibernate-mapping>