主流ORM框架Object Relation Mapping对象关系映射,将面向对象映射成面向关系。
如何使用
1、导入相关依赖
2、创建Hibernate配置文件
3、创建实体类
4、创建实体类-关系映射文件
5、调用Hibernate API完成操作
具体操作
1、创建 Maven工程,在pom.xml中导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
2、在resources下创建hibernate.cfg.xml文件,并配置其相关信息
在resources下创建hibernate.cfg.xml文件
核心配置:session-factory
SessionFactory: 针对单个数据库映射经过编译的内存镜像文件,将数据库转换为一个java可以识别的镜像文件。
构建SessionFactory非常耗费资源,所以通常一个工程只需要创建一个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>
<!-- Hibernate 连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">Wrw156970</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<!-- 配置 C3P0 数据源 -->
<!-- 连接池不够时,新增10个 -->
<property name="hibernate.c3p0.acquire_increment">10</property>
<!-- 失效时间 -->
<property name="hibernate.c3p0.idle_test_period">2000</property>
<!-- 超时时间 -->
<property name="hibernate.c3p0.timeout">2000</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 执行最大连接数 -->
<property name="hibernate.c3p0.max_statements">10</property>
<!-- Hibernate 的基本配置 -->
<!-- Hibernate 使用的数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 运行时是否打印 SQL -->
<!-- <property name="show_sql">true</property> -->
<property name="hibernate.show_sql">true</property>
<!-- 运行时是否格式化 SQL -->
<!-- <property name="format_sql">true</property>-->
<property name="hibernate.format_sql">true</property>
<!-- 生成数据表的策略 -->
<!-- <property name="hbm2ddl.auto">update</property>-->
<!-- 加载Hibernate时,验证数据库表结构与Hibernate映射的结构是否匹配。如果不匹配,会抛出异常-->
<property name="hibernate.hbm2ddl.auto">validate</property>
</session-factory>
</hibernate-configuration>
3、创建实体类
package org.example.entity;
import lombok.Data;
@Data
public class Orders {
private Integer id;
private String name;
private Customer customer;
}
package org.example.entity;
import lombok.Data;
import java.util.Set;
@Data
public class Customer {
private Integer id;
private String name;
private Set<Orders> orders;
}
4、创建实体关系映射文件
package org.example.entity;
import lombok.Data;
@Data
public class People {
private Integer id;
private String name;
private Double money;
}
类映射文件名为类名.hbm.xml,如下面文件名为People.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.People" table="people">
<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>
<property name="money" type="java.lang.Double">
<column name="money"></column>
</property>
</class>
</hibernate-mapping>
5、实体关系映射文件注册到Hibernate 的配置文件中。
<!-- 注册实体关系映射文件 -->
<mapping resource="org/example/entity/People.hbm.xml"></mapping>
6、使用Hibernate Api完成数据操作。
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//设置添加信息
People people = new People();
people.setName("张三");
people.setMoney(1000.0);
//添加
session.save(people);
//提交事务
session.beginTransaction().commit();
//关闭session
session.close();
}
}
7、pom.xml 中需要配置 resource。
<!-- 允许读取src/main/java路径下的xml文件 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
其完整项目结构
Hibernate 级联操作
1、一对多关系
客户和订单:每个客户可以购买多个产品,生成多个订单,但是一个订单只能属于一个客户,所以客户是一,订单是多。
数据库中一的一方是主表,多的一方是从表,通过主外键关系来维护
面向对象中
package org.example.entity;
import lombok.Data;
import java.util.Set;
@Data
public class Customer {
private Integer id;
private String name;
private Set<Orders> orders;
}
package org.example.entity;
import lombok.Data;
@Data
public class Orders {
private Integer id;
private String name;
private Customer customer;
}
2、多对多关系
学生选课:一门课程可以被多个学生选择,一个学生可以选择多门课程,学生是多,课程也是多。
数据库中是通过两个一对多关系来维护的,学生和课程都是主表,额外增加一张中间表作为从表,两张主表和中间表都是一对多关系。
面向对象中
package org.example.entity;
import lombok.Data;
import java.util.Set;
@Data
public class Account {
private Integer id;
private String name;
private Set<Course> courses;
}
package org.example.entity;
import lombok.Data;
import java.util.Set;
@Data
public class Course {
private Integer id;
private String name;
private Set<Account> accounts;
}
Java 和数据库对于这两种关系的体现完全是两种不同的方式,Hibernate 框架的作用就是将这两种方式进行转换
Hibernate 实现一对多
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Orders"></one-to-many>
</set>
</class>
</hibernate-mapping>
- set 标签配置实体类中的集合属性 orders
- name 实体类属性名
- table 表名
- key 外键
- one-to-many 与集合泛型的实体类对应
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>
- many-to-one 配置实体类对应
- name 属性名
- class 属性对应的类
- column 外键
需要在 Hibernate 配置文件中进行注册
<!-- 注册实体关系映射文件 -->
<mapping resource="org/example/entity/Customer.hbm.xml"></mapping>
<mapping resource="org/example/entity/Orders.hbm.xml"></mapping>
一对多
Hibernate Api
package org.example;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test2 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.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
session.close();
}
}
一对多完整项目结构
Hibernate 实现多对多
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Account" column="aid"></many-to-many>
</set>
</class>
</hibernate-mapping>
- name 实体类对应的集合属性名
- table 中间表名
- key 外键
- many-to-many 与集合泛型的实体类对应
- column 属性与中间表的外键字段名对应
注册 Hibernate 配置文件中
<!-- 注册实体关系映射文件 -->
<mapping resource="org/example/entity/Account.hbm.xml"></mapping>
<mapping resource="org/example/entity/Course.hbm.xml"></mapping>
Hibernate Api
package org.example;
import org.example.entity.Account;
import org.example.entity.Course;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.HashSet;
import java.util.Set;
/**
* @author 王润伟
* @date 2024年05月26日 2:03
*/
public class Test3 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Course course = new Course();
course.setName("java");
Account account = new Account();
account.setName("张三");
Set<Course> courses = new HashSet<Course>();
courses.add(course);
account.setCourses(courses);
session.save(course);
session.save(account);
//提交事务
session.beginTransaction().commit();
//关闭session
session.close();
}
}
多对多完整项目结构
Hibernate 延迟加载
延迟加载、惰性加载、懒加载
使用延迟加载可以提高程序的运行效率,java 程序与数据库交互的频率越低,程序运行的效率就越高,所以我们应该尽量减少 java 程序与数据库的交互次数,Hibernate 延迟加载就很好的做到了这一点。
客户和订单,当我们查询客户对象时,因为有级联设置,所以会将对应的订单信息一并查询出来,这样就需要发送两条 SQL 语句,分别查询客户信息和订单信息。
延迟加载的思路是:当我们查询客户的时候,如果没有访问订单数据,只发送一条SQL语句查询客户信息,如果需要访问订单数据,则发送两条SQLL。
延迟加载可以看作是一种优化机制,根据具体的需求,自动选择要执行的SQL语句数量。
一对多
1、查询Customer,对 orders进行延迟加载设置,在customer.hbm.xml进行设置,延迟加载默认开启。
<set name="orders" table="orders" lazy="true">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
2、查询Customer
查询customer主表属性结果,只执行一条SQL
package org.example;
import org.example.entity.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test4 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class, 12);
System.out.println(customer);
//关闭session
session.close();
}
}
查询customer下关联的次表Orders结果,执行两条SQL
package org.example;
import org.example.entity.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test4 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class, 12);
System.out.println(customer.getOrders());
//关闭session
session.close();
}
}
去掉延迟加载,查询customer主表也会执行两条
<set name="orders" table="orders" lazy="false">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
package org.example;
import org.example.entity.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test4 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class, 12);
System.out.println(customer);
//关闭session
session.close();
}
}
lazy除了可以设置true和false之外,还可以设置extra,extra是比 true更加懒惰的一种加载方式,或者说是更加智能的一种加载方式,通过例子看区别:
查询Customer对象,打印该对象对应的orders集合的长度
设置lazy为true
package org.example;
import org.example.entity.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test4 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class, 12);
System.out.println(customer.getOrders().size());
//关闭session
session.close();
}
}
查询结果会先查询次表数据,再统计数量,查询SQL数量统计语句复杂
设置lazy为extra
<set name="orders" table="orders" lazy="extra">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
查询结果用count统计次表查询的行数,大大简化SQL,查询效率增强
也可以通过Orders 来设置Customer的延迟加载,orders.hbm.xml中进行设置
这里azy设置为proxy,即启用懒加载
<many-to-one name="customer" class="org.example.entity.Customer" column="cid" lazy="proxy"></many-to-one>
package org.example;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test5 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Orders orders = session.get(Orders.class, 4);
System.out.println(orders);
//关闭session
session.close();
}
}
查询结果只执行一次SQL语句
查询orders表下的关联属性tcustomer,执行两次SQL语句
package org.example;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test5 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Orders orders = session.get(Orders.class, 4);
System.out.println(orders.getCustomer());
//关闭session
session.close();
}
}
no-proxy:当调用方法需要访问customer的成员变量时,发送SQL语句查询Customer,否则不查询。
proxy:无论调用方法是否需要访问customer的成员变量,都会发送SQL语句查询Customer。
多对多
查询Course,加载对应的Account,默认延迟加载开启,其实现结果跟一对多,一那方使用方式一致,就是<set>标签那方,这里就不做演示。
注意:当级联关系查询时会出现查询无线循环然后报错,这是因为两个关系表之间映射的对象的toString方法彼此包含关联的对象,这时查询就陷入循环,反复查询关联的表信息。
解决方法:重新toString方法,去掉关联对象属性,把@Data注解换成@Getter和@Setter。
Hibernate 配置文件
- hibernate.cfg.xml
- hbm.xml
Hibernate.cfg.xml
hibernate.xml配置Hibernate的全局环境。
1、数据库的基本信息。
<?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 连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">Wrw156970</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<!-- 配置 C3P0 数据源 -->
<!-- 连接池不够时,新增10个 -->
<property name="hibernate.c3p0.acquire_increment">10</property>
<!-- 失效时间 -->
<property name="hibernate.c3p0.idle_test_period">2000</property>
<!-- 超时时间 -->
<property name="hibernate.c3p0.timeout">2000</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 执行最大连接数 -->
<property name="hibernate.c3p0.max_statements">10</property>
<!-- Hibernate 的基本配置 -->
<!-- Hibernate 使用的数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 运行时是否打印 SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 运行时是否格式化 SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注册实体关系映射文件 -->
<mapping resource="org/example/entity/People.hbm.xml"></mapping>
<mapping resource="org/example/entity/Customer.hbm.xml"></mapping>
<mapping resource="org/example/entity/Orders.hbm.xml"></mapping>
<mapping resource="org/example/entity/Account.hbm.xml"></mapping>
<mapping resource="org/example/entity/Course.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
1、数据库的基本信息
<property name="connection.username">root</property>
<property name="connection.password">Wrw156970</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
2、集合C3P0,设置数据库连接池信息。
<!-- 连接池不够时,新增10个 -->
<property name="hibernate.c3p0.acquire_increment">10</property>
<!-- 失效时间 -->
<property name="hibernate.c3p0.idle_test_period">2000</property>
<!-- 超时时间 -->
<property name="hibernate.c3p0.timeout">2000</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 执行最大连接数 -->
<property name="hibernate.c3p0.max_statements">10</property>
3、Hibernate 基本信息。
<!-- 运行时是否打印 SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 运行时是否格式化 SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
- update:动态创建表,如果表存在,则直接使用,如果表不存在,则创建,一般使用此属性。
- create:无论表是否存在,都会重新创建。
- create-drop:初始化创建表,程序结束时删除表。
- validate:校验实体关系映射文件和数据表是否对应,不能对应直接报错。
4、注册实体关系映射文件
<!-- 注册实体关系映射文件 -->
<mapping resource="org/example/entity/People.hbm.xml"></mapping>
<mapping resource="org/example/entity/Customer.hbm.xml"></mapping>
<mapping resource="org/example/entity/Orders.hbm.xml"></mapping>
<mapping resource="org/example/entity/Account.hbm.xml"></mapping>
<mapping resource="org/example/entity/Course.hbm.xml"></mapping>
实体关系映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Account" column="aid"></many-to-many>
</set>
</class>
</hibernate-mapping>
hibernate-mapping 属性
- package: 给 class 节点对应的实体类统一设置包名,此处设置包名,class 的 name 属性就可以省略包名。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.example.entity">
<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>
- 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的名称,会覆盖hibernate-mapping的schema
- catalog:数据库catalog的名称,会覆盖hibernate-mapping 的catalog
- proxy︰指定一个接口,在延迟加载时作为代理使用
- dynamic-update:动态更新
- dynamic-insert:动态添加
dynamic-insert 的使用
未使用时执行插入部分属性的效果
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test6 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
People people = new People();
people.setName("李四");
session.save(people);
//关闭session
session.close();
}
}
这里只设置 name 的值,没有设置 money 的值,而执行的 SQL 语句却包含新增 money 这项。
在 class 标签设置 dynamic-insert 为 true
<class name="org.example.entity.People" table="people" dynamic-insert="true">
</class>
使用时执行插入部分属性的效果,发现新增了设置值的name属性
dynamic-update 的使用
未使用时执行更新部分属性的效果
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test7 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
People people = session.get(People.class,1);
people.setMoney(1999.0);
//更新
session.update(people);
session.beginTransaction().commit();
//关闭session
session.close();
}
}
这里只修改money属性,执行更新语句时却更新全部属性
在 class 标签设置 dynamic-update 为 true
<class name="org.example.entity.People" table="people" dynamic-update="true">
</class>
使用时执行部分属性更新的效果,发现只更新了修改的 money 属性
- where:查询时给SQL添加where条件
查询某表所有数据具体实现
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test8 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//查询people表的所有数据
String hql = "from People";
Query query = session.createQuery(hql);
List<People> peoples = query.list();
for (People p : peoples) {
System.out.println(p);
}
session.beginTransaction().commit();
//关闭session
session.close();
}
}
查询结果为指定表的所有数据
在查询的映射文件的 class 标签中添加 where 属性,设置其筛选条件,这里我设置其值为 id=2
<class name="org.example.entity.People" table="people" where="id=2">
</class>
查询结果为 id=2 的数据
id属性
- name:实体类属性名
- type:实体类属性数据类型
此处可以设置两种类型的数据:Java 数据类型或者 Hibernate 映射类型。实体类的属性数据类型必须与数据表对应的字段数据类型一致:
int 对应 int,String 对应 varchar
如何进行映射?
Java 数据类型映射到Hibernate映射类型,再由Hibernate 映射类型映射到 SQ L数据类型 Java ---》Hibernate ---〉 SQL
- column:数据表的主键字段名
- generator:主键生成策略
1、hilo算法
2、increment: Hibernate 自增
3、identity:数据库自增
4、native:本地策略,根据底层数据库自动选择主键的生成策略
5、uuid.hex 算法
6、select 算法
property属性
- name:实体类的属性名
- column:数据表字段名
- type:数据类型
- update:该字段是否可以修改,默认为 true
- insert:该字段是否可以添加,默认为 true
- lazy:延迟加载策略
实体关系映射文件属性
1、inverse
Customer 和 Orders 是一对多关系,一个 Customer 对应多个 Orders,实体类中用一个 set 集合来表示对应的 Orders。
Customer 对象和 Customer.hbm.xml 映射文件
package org.example.entity;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;
@Getter
@Setter
public class Customer {
private Integer id;
private String name;
private Set<Orders> orders;
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Customer.hbm.xml 中使用 set 标签来配置映射关系。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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" lazy="extra">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
</class>
</hibernate-mapping>
Orders 对象和 Orders.hbm.xml 映射文件
package org.example.entity;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Orders {
private Integer id;
private String name;
private Customer customer;
@Override
public String toString() {
return "Orders{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.example.entity.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="org.example.entity.Customer" column="cid" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
package org.example;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test9 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = new Customer();
customer.setName("张三");
Orders orders1 = new Orders();
orders1.setName("订单1");
orders1.setCustomer(customer);
Orders orders2 = new Orders();
orders2.setName("订单2");
orders2.setCustomer(customer);
session.save(customer);
session.save(orders1);
session.save(orders2);
session.beginTransaction().commit();
//关闭session
session.close();
}
}
package org.example;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.HashSet;
import java.util.Set;
public class Test9 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = new Customer();
customer.setName("张三");
Orders orders1 = new Orders();
orders1.setName("订单1");
orders1.setCustomer(customer);
Orders orders2 = new Orders();
orders2.setName("订单2");
orders2.setCustomer(customer);
Set<Orders> orders = new HashSet<Orders>();
orders.add(orders1);
orders.add(orders2);
customer.setOrders(orders);
session.save(customer);
session.save(orders1);
session.save(orders2);
session.beginTransaction().commit();
//关闭session
session.close();
}
}
因为 Customer 和 Orders 都在维护一对多关系,所以会重复设置主外键约束关系。
如何避免 这种情况?
1、在Java 代码中去掉一方维护关系代码。
2、通过配置来解决
<set name="orders" table="orders" lazy="extra" inverse="true">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
inverse属性是用来设置是否将维护权交给对方,默认是false,不交出维护权,双方都在维护,将它设置为true,表示 Customer放弃维护。
cascade:用来设置级联操作
因为映射文件主外键的关联,使其得先删除次表外键数据,再删除主表的主键数据,不然会报错
第一种方式:先循环删除外键数据,再删除要删除的主键数据
package org.example;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test10 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class,16);
//用迭代器删除外键数据
Iterator<Orders> iterator = customer.getOrders().iterator();
while (iterator.hasNext()){
session.delete(iterator.next());
}
//删除主键数据
session.delete(customer);
session.beginTransaction().commit();
//关闭session
session.close();
}
}
第二种方式:实体关系映射文件中设置cascade属性值为delete完成级联删除。
<set name="orders" table="orders" lazy="extra" inverse="true" cascade="delete">
<key column="cid"></key>
<one-to-many class="org.example.entity.Orders"></one-to-many>
</set>
package org.example;
import org.example.entity.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test10 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class,15);
session.delete(customer);
session.beginTransaction().commit();
//关闭session
session.close();
}
}
Hibernate HQL
HQL: Hibernate Query Language,是 Hibernate 框架提供的一种查询机制,它和 SQL 类似,不同的是 HQL 是面向对象的查询语句,让开发者能够以面向对象的思想来编写查询语句,对 Java 编程是一种好友好的方式。
HQL不能直接参与数据库的交互,中间层语言。
Java ---》HQL ---〉Hibernate ---》sQL ---〉DB
HQL 只能完成查询、修改、删除,新增是无法操作的。
1、查询对象
查询表中所有数据,自动完成对象的封装,返回List集合。
HQL进行查询,from 关键字后面不能写表名,必须写表对应的实体类名。
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test8 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//查询people表的所有数据
String hql = "from People";
Query query = session.createQuery(hql);
List<People> peoples = query.list();
for (People p : peoples) {
System.out.println(p);
}
session.beginTransaction().commit();
//关闭session
session.close();
}
}
2、分页查询
HQL分页查询可以通过调用query的方法来完成。
1、setFirstResult() 设置起始下标
2、setMaxResults() 设置截取长度
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test11 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//分页查询
String hql = "from People";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(3);
List<People> list = query.list();
for (People people : list){
System.out.println(people);
}
//关闭session
session.close();
}
}
查询结果,因下标0为起始,这里 这里 query.setFirstResult(1)就是表的第二行开始, query.setMaxResults(3)就是第二行开始往下三行都是分页查询数据。
3、where条件查询
HQL直接追加where关键字作为查询条件,与SQL没有区别。
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
public class Test11 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//where查询
String hql = "from People where id = 2";
Query query = session.createQuery(hql);
People people = (People) query.list().get(0);
System.out.println(people);
session.close();
}
}
query.list() 返回一个集合,此时集合中只有一个对象,通过下标 0 取出该对象。
注意:用 query.list().get() 取数据时,如果查询的数据集为空会报错。
解决方法:使用 query.uniqueResult() 方法则既可以查询数据,也不怕查询数据为空会报错,当数据集为空时会返回 null。
//where查询
String hql = "from People where id = 0";
Query query = session.createQuery(hql);
//使用 query.uniqueResult() 方法获取对象数据
People people = (People) query.uniqueResult();
System.out.println(people);
不会抛出异常。
4、模糊查询
查询名称包含 “三” 的所有记录
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test12 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//like模糊查询
String hql = "from People where name like '%三%'";
Query query = session.createQuery(hql);
List<People> peoples = query.list();
for (People people : peoples) {
System.out.println(people);
}
session.close();
}
}
5、order by
按照id进行排序
升序
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test13 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//按照id升序查询,不设置asc默认为升序
//String hql = "from People order by id";
String hql = "from People order by id asc ";
Query query = session.createQuery(hql);
List<People> peoples = query.list();
for (People people : peoples) {
System.out.println(people);
}
session.close();
}
}
降序
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test13 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//like模糊查询
String hql = "from People order by id desc ";
Query query = session.createQuery(hql);
List<People> peoples = query.list();
for (People people : peoples) {
System.out.println(people);
}
session.close();
}
}
asc 是升序排列,desc是降序排列
6、查询实体对象的属性
package org.example;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
public class Test14 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//where查询
String hql = "select name from People where id = 2";
Query query = session.createQuery(hql);
String name = (String) query.uniqueResult();
System.out.println(name);
session.close();
}
}
7、占位符
package org.example;
import org.example.entity.People;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test15 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
String hql = "from People where name = :name";
Query query = session.createQuery(hql);
query.setString("name","张三");
List<People> peoples = query.list();
for (People people : peoples) {
System.out.println(people);
}
session.close();
}
}
8、级联查询
package org.example;
import org.example.entity.Customer;
import org.example.entity.Orders;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class Test16 {
public static void main(String[] args) {
//创建Configuration
Configuration configuration = new Configuration().configure();
//获取SessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
String hql1 = "from Customer where name = :name";
Query query1 = session.createQuery(hql1);
query1.setString("name","张三");
Customer customer = (Customer) query1.list().get(0);
String hql2 = "from Orders where customer = :customer";
Query query2 = session.createQuery(hql2);
query2.setEntity("customer",customer);
List<Orders> list = query2.list();
for (Orders orders : list) {
System.out.println(orders);
}
session.close();
}
}