Hibernate
主流ORM框架 Object Relation Mapping 对象关系映射,将面向对象映射成面向关系。
如何使用
1、导入相关依赖
2、创建 Hibernate 配置文件
3、创建实体类
4、创建实体类-关系映射文件
5、调用 Hibernate API 完成操作
具体操作
1、创建Maven工程,pom.xml
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.10.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2、创建配置文件 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>
<!-- 数据源配置 -->
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///study?useUnicode=true&characterEncoding=UTF-8</property>
<property name="connection.username">root</property>
<property name="connection.password">4444</property>
<!-- C3P0 -->
<property name="hibernate.c3p0.acquire_increment">10</property> <!--不够时增10个-->
<property name="hibernate.c3p0.idle_test_period">10000</property> <!--设置失效释放资源时间-->
<property name="hibernate.c3p0.timeout">5000</property> <!--设置超时时间-->
<property name="hibernate.c3p0.min_size">5</property> <!--最大连接数-->
<property name="hibernate.c3p0.max_size">30</property> <!--最小连接数-->
<property name="hibernate.c3p0.max_statements">10</property> <!--JDBC执行sql最大限流数-->
<!--配置方言-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 指定当前Session上下文为线程 -->
<property name="current_session_context_class">thread</property>
<!-- 控制台显示sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化显示 -->
<property name="hibernate.format_sql">true</property>
<!-- 自动建表,无则创建,有则更新 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注册映射文件 -->
<mapping resource="com/cqkgkj/pojo/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>
3、创建实体类
import lombok.Data;
@Data
public class Student {
private Integer id;
private Integer age;
private String name;
}
4、创建实体关系映射文件,与实体在同一目录下,名字为 “实体名.hbm.xml”
<?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.cqkgkj.pojo">
<class name="Student" table="student">
<!-- id主键自增 -->
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" />
<property name="age" />
</class>
</hibernate-mapping>
5、实体关系映射文件注册到 hibernate 映射文件中
<!-- 注册映射文件 -->
<mapping resource="com/cqkgkj/pojo/Student.hbm.xml" />
6、使用 Hibernate API 完成数据操作
import com.cqkgkj.pojo.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class MyTest {
@Test
public void test1(){
//1.加载主配置文件与映射文件
Configuration configure = new Configuration().configure();
//2.创建Session工厂对象
SessionFactory sessionFactory = configure.buildSessionFactory();
//3.开启Session对象
Session session = sessionFactory.getCurrentSession();
// Session session = sessionFactory.openSession();
try {
//4.开启事务
session.beginTransaction();
Student student = new Student();
student.setAge(22);
student.setName("李四");
//5.执行操作
session.save(student);
//6.提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//7.回滚事务
session.getTransaction().rollback();
} finally {
//8.关闭事务
session.close();
}
}
}
7、pom.xml 中需要配置 resource
<!--读取java文件夹下的配置文件-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
Hibernate 级联操作
1、一对多关系
班级和学生:每个班级有多个学生,但每个学生只能属于一个班级,所以班级是一,学生是多。
数据库中一的一方是主表,多的一方是从表,通过外键关系来维护。
面向对象中
package com.cqkgkj.pojo;
import lombok.Data;
import java.util.Set;
@Data
public class Student {
private Integer id;
private Integer age;
private String name;
private Set<Class> classes;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
2、多对多关系
学生选课:一门课程可以被多个学生选择,一个学生可以选择多门课程,学生是多,课程也是多。
数据库中是通过两个一对多关系来维护的,学生和课程都是主表,额外增加一张中间表作为从表,两张主表和中间表都是一对多关系。
package com.cqkgkj.pojo;
import lombok.Data;
import java.util.Set;
@Data
public class Account {
private Integer id;
private String name;
private Set<Course> courses;
}
package com.cqkgkj.pojo;
import lombok.Data;
import java.util.Set;
@Data
public class Course {
private Integer id;
private String name;
private Set<Account> accounts;
}
Java 和数据库对于这两种关系的体现完全是两种不同的方式,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 package="com.cqkgkj.pojo">
<class name="Class" table="t_class">
<!-- id主键自增 -->
<id name="id">
<generator class="native"></generator>
</id>
<property name="cname"></property>
<set name="students" table="t_student">
<key column="cid"></key>
<one-to-many class="Student"></one-to-many>
</set>
</class>
</hibernate-mapping>
- set 标签来配置实体类中的集合属性students
- name 实体类的属性名
- table 表名
- key 外键
- one-to-many 与集合泛型的实体类对应
<?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.cqkgkj.pojo">
<class name="Student" table="t_student">
<!-- id主键自增 -->
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<property name="age"></property>
<many-to-one name="classObj" class="Class" ></many-to-one>
</class>
</hibernate-mapping>
-
many-to-one 配置实体类对应的对象属性
-
name 属性名
-
class 属性对应的类
-
column 外键
需要在 Hibernate 配置文件中进行注册
<!-- 注册映射文件 -->
<mapping resource="com/cqkgkj/pojo/Student.hbm.xml" />
<mapping resource="com/cqkgkj/pojo/Class.hbm.xml" />
一对多
Hibernate API
import com.cqkgkj.pojo.Class;
import com.cqkgkj.pojo.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class MyTest {
@Test
public void test2(){
//1.加载主配置文件与映射文件
Configuration configuration = new Configuration().configure();
//2.创建Session工厂对象
SessionFactory sessionFactory = configuration.buildSessionFactory();
//3.开启Session对象
Session session = sessionFactory.openSession();
try {
//4.开启事务
session.beginTransaction();
//创建Student
Student student = new Student();
student.setAge(22);
student.setName("张三");
//创建Class
Class classObj = new Class();
classObj.setCname("一班");
//建立关联关系
student.setClassObj(classObj);
//5.执行操作
session.save(student);
session.save(classObj);
//6.提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//7.回滚事务
session.getTransaction().rollback();
}finally {
session.close();
}
}
}
这里有几个需要注意的点,我在学习的时候遇到的错误:
- 实体关系映射文件的 的 name 和 的 name 要与实体类里表示关系的对象变量名相同;
- session.save() 保存数据库是,先保存表示一的对象,在保存表示多的对象,不然外键插入异常。
多对多
配置实体关系映射文件
<?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.cqkgkj.pojo">
<class name="Account" table="account">
<!-- id主键自增 -->
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" ></property>
<set name="courses" table="account_course">
<key column="aid" ></key>
<many-to-many class="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://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cqkgkj.pojo">
<class name="Course" table="course">
<!-- id主键自增 -->
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" ></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>
name 实体类对应的集合属性名
table 中间表名
key 外键
many-to-many 与集合泛型的实体类对应
column 属性与中间表的外键字段名对应
注册 Hibernate 配置文件中
<mapping resource="com/cqkgkj/pojo/Account.hbm.xml" />
<mapping resource="com/cqkgkj/pojo/Course.hbm.xml" />
编写测试类代码
import com.cqkgkj.pojo.Account;
import com.cqkgkj.pojo.Course;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
public class MyTest {
@Test
public void test3(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
try{
session.beginTransaction();
Account account = new Account();
account.setName("张三");
Course course = new Course();
course.setName("Java");
Set<Account> accounts = new HashSet<>();
accounts.add(account);
// 设置对应关系
course.setAccounts(accounts);
session.save(account);
session.save(course);
session.getTransaction().commit();
} catch (Exception e){
session.getTransaction().rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Hibernate 延时加载
默认开启
import com.cqkgkj.pojo.Account;
import com.cqkgkj.pojo.Course;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
public class MyTest {
@Test
public void test4(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
try{
session.beginTransaction();
Account account = session.get(Account.class, 2);
System.out.println(account);
session.getTransaction().commit();
} catch (Exception e){
session.getTransaction().rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
查询一张表的数据,当需要查询关联的数据时,才会在另一张表中查询关联数据。
<set name="courses" table="account_course" lazy="false">
<key column="aid" ></key>
<many-to-many class="Course" column="cid"></many-to-many>
</set>
在 关联的属性标签中使用标签属性 lazy=“false” 关闭延时加载,则每次查询数据时,其关联的其他表的数据也会一起查出来。