主流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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();//设置添加信息People people = new People();people.setName("张三");people.setMoney(1000.0);//添加session.save(people);//提交事务session.beginTransaction().commit();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();//创建 CustomerCustomer customer = new Customer();customer.setName("张三");//创建 OrdersOrders orders = new Orders();orders.setName("订单1");//建立关联关系orders.setCustomer(customer);//保存session.save(customer);session.save(orders);//提交事务session.beginTransaction().commit();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Customer customer = session.get(Customer.class, 12);System.out.println(customer);//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Customer customer = session.get(Customer.class, 12);System.out.println(customer.getOrders());//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Customer customer = session.get(Customer.class, 12);System.out.println(customer);//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Customer customer = session.get(Customer.class, 12);System.out.println(customer.getOrders().size());//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Orders orders = session.get(Orders.class, 4);System.out.println(orders);//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Orders orders = session.get(Orders.class, 4);System.out.println(orders.getCustomer());//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();People people = new People();people.setName("李四");session.save(people);//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();People people = session.get(People.class,1);people.setMoney(1999.0);//更新session.update(people);session.beginTransaction().commit();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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;@Overridepublic 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;@Overridepublic 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession session = sessionFactory.openSession();Customer customer = session.get(Customer.class,15);session.delete(customer);session.beginTransaction().commit();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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);}//关闭sessionsession.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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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) {//创建ConfigurationConfiguration configuration = new Configuration().configure();//获取SessionFactorySessionFactory sessionFactory = configuration.buildSessionFactory();//获取SessionSession 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();}
}