随笔- 62  文章- 1  评论- 5  阅读- 13061 

Hibernate

加入maven依赖

<!-- hibernate -->
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.7.Final</version>
</dependency>
使用javassist是因为

安装IDEA插件

JPA Buddy

image-20230624205726091

配置数据库

创建文件 hibernate.cfg.xml

配置数据库连接

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/xsd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///db1?serverTimezone=GMT%2B8&useUnico</property>
<property name="connection.username">root</property>
<property name="connection.password">password</property>
</session-factory>
</hibernate-configuration>

配置方言等其他配置

<!-- 数据库⽅⾔ -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 打印SQL -->
<property name="show_sql">true</property>
<!-- 格式化SQL -->
<property name="format_sql">true</property>
<!-- 是否⾃动⽣成数据库 -->
<property name="hibernate.hbm2ddl.auto">update</property>

配置一个实体类的CRUD

创建实体类A

@Data
public class A implements Serializable {
private Integer id;
private String value;
// private static final long serialVersionUID = 1L;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

同级包下,配置mapping

SensorData.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!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.jmu.design.domain.SensorData" table="sensor_data">
<id name="id">
<generator class="native"/>
</id>
<property name="type" column="type"/>
<property name="updateTime" column="update_time"/>
<property name="value" column="value"/>
</class>
</hibernate-mapping>

在hibernate配置文件中添加映射关系

<!-- 关联对象配置文件 -->
<mapping resource="com/jmu/design/domain/SensorData.hbm.xml"/>

image-20230623154029549

编写测试代码

@Test
public void init(){
//初始化注册服务对象
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
//获取Session工厂
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
SensorData sensorData = new SensorData();
sensorData.setType("type1");
sensorData.setValue(123);
session.save(sensorData);
session.close();
}

然后出现未找到配置文件,maven中配置将配置文件自动构建打包

image-20230623155921785

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>

然后还需要添加一个依赖,否则3.x版本会出现异常

<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>

CRUD测试

@Test
public void init(){
//初始化注册服务对象
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
//获取Session工厂
SessionFactory sessionFactory = configuration.buildSessionFactory();
//获取Session
Session session = sessionFactory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//增
A a = new A();
a.setValue("123");
session.save(a);
//删
session.delete(a);
//查
List from_a = session.createQuery("from A").list();
for (Object o : from_a) {
System.out.println(o);
}
//改
A a1 = (A) session.get(A.class, 2);
System.out.println(a1.toString());
a1.setValue(String.valueOf(111111));
session.update(a1);
transaction.commit();
session.close();
}

Get和load的区别

get请求是立即加载的过程,先查询缓存,缓存没有查询数据库

load是懒加载机制的,只有它被使用的时候,才会去查询数据库

清理缓存

session.clear();

数据库的更新方式

一般使用update

image-20230624210503998

封装Hibernate的工具类

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.data.redis.core.index.PathBasedRedisIndexDefinition;
public class HibernateUtil {
private static Configuration configuration;
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> session = new ThreadLocal<>();
static {
configuration = new Configuration().configure("hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
}
public static Session getSession(){
Session session = HibernateUtil.session.get();
if (session==null || !session.isOpen()) {
if(sessionFactory == null){
buildSessionFactory();
}
//获取一个session
session = sessionFactory==null?null:sessionFactory.openSession();
//放入线程
HibernateUtil.session.set(session);
}
return session;
}
private static void buildSessionFactory() {
sessionFactory = configuration.buildSessionFactory();
}
public static void closeSession() {
Session session = HibernateUtil.session.get();
HibernateUtil.session.set(null);
if(session!=null && session.isOpen()){
session.close();
}
}
}

Hibernate对象的生命周期

对象状态及生命周期

Hibernate中对象有三种状态:瞬时状态(Transient)、持久状态(Persistent)、游离状态(Detached)。
瞬时状态:刚刚使用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的Java对象被称为临时对象。Session中没有,数据库中没有。
持久化状态:已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象被称为持久化对象。Session中有,数据库中有。
游离状态:已经被持久化,但不处于Session的缓存中。处于游离状态的Java对象被称为游离对象。Session中没有,数据库中有。(session中的缓存,一级缓存)

image-20230624211235138

单向多对一

HIbernate映射

image-20230624215629802

自动生成表

image-20230624220153329

也可以将xml配置文件中的update的构建表的方式注解打开

<!-- 是否⾃动⽣成数据库 -->
<property name="hibernate.hbm2ddl.auto">update</property>

配置实体类对象

设有一个student表,以及一个grade表

image-20230624220430480

Student.java

import lombok.Data;
import java.io.Serializable;
@Data
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
private Grade grade;
}

Student.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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.jmu.design.domain">
<class name="com.jmu.design.domain.Student" table="student">
<id name="id">
<generator class="native"/>
</id>
<property name= "name"/>
<property name="age"/>
<!--
多对一
name字段名称
class 对应的类型
-->
<many-to-one name="grade" class="Grade" not-null="true" column="grade_id"/>
</class>
</hibernate-mapping>

Grade.java

import lombok.Data;
import java.io.Serializable;
@Data
public class Grade implements Serializable {
private Integer id;
private String name;
}

Grade.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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.jmu.design.domain">
<class name="com.jmu.design.domain.Grade" table="grade">
<id name="id">
<generator class="native"/>
</id>
<property name= "name"/>
</class>
</hibernate-mapping>

要记得mapping的映射也得加上

<mapping resource="com/jmu/design/domain/Student.hbm.xml"/>
<mapping resource="com/jmu/design/domain/Grade.hbm.xml"/>

测试文件

public void manyToOneTest(){
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
//创建实例对象
Grade grade1 = new Grade();
grade1.setName("基础");
Grade grade2 = new Grade();
grade2.setName("高级");
session.save(grade1);
session.save(grade2);
Student student1 = new Student();
student1.setName("张三");
student1.setAge(10);
student1.setGrade(grade1);
Student student2 = new Student();
student2.setName("李四");
student2.setAge(20);
student2.setGrade(grade2);
Student student3 = new Student();
student3.setName("王五");
student3.setAge(30);
student3.setGrade(grade1);
session.save(student1);
session.save(student2);
session.save(student3);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtil.closeSession();
}
}

单向一对多

配置实体类

Student.java

import lombok.Data;
import java.io.Serializable;
@Data
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
// private Grade grade;
}

Grade.java

import lombok.Data;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Data
public class Grade implements Serializable {
private Integer id;
private String name;
private Set<Student> students = new HashSet<>();
}

Student.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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.jmu.design.domain">
<class name="com.jmu.design.domain.Grade" table="grade">
<id name="id">
<generator class="native"/>
</id>
<property name= "name"/>
<set name="students">
<key column="grade_id" not-null="true"/>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>

Student.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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.jmu.design.domain">
<class name="com.jmu.design.domain.Student" table="student">
<id name="id">
<generator class="native"/>
</id>
<property name= "name"/>
<property name="age"/>
<!--
多对一
name字段名称
class 对应的类型
-->
<!-- <many-to-one name="grade" class="Grade" not-null="true" column="grade_id"/>-->
</class>
</hibernate-mapping>

测试代码

插入的话和上面的一样

将student加入到grade的students集合中,就会自动映射到关系

查询:

@Test
public void oneToMany(){
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Grade grade = (Grade) session.get(Grade.class, 3);
System.out.println(grade.toString());
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtil.closeSession();
}
}

一对多在存储时,会先插入grade,然后插入student,之后发现这个student在grade的集合中,他们两个有关系,才会用update语句来更改student表中的grade_id,因此效率上来说是不如多对一的

双向多对一

就是把之前注释掉的配置文件和对应的实体类的字段打开

然后存的时候,用单向一对多或者单向多对一的方式都行

双向关系的时候记得把not-null删了

建议使用多对一,不用使用update语句,效率高

级联操作

在双向一对多的学习中,我们发现每次保存对象时,学生对象和年纪对象都需要我们持久化至session,既然它们两者有关联关系,可不可以只持久化其中一端,另一端就会自动的被持久化呢,这个属性就是Hibernate的cascade。 cascade是多对一、一对多、一对一、多对多各种关系之间的一种级联操作行为。

image-20230625000004881

一般使用save-update,其他选项一般较少使用,级联插入

在存储的时候只需要存一方就行

image-20230625000515785

维护关系

加上 inverse="true"由对方来维护关系,此时一端不再维护,当使用一对多来插入时,不会再更改grade_id字段

image-20230625000852646

强制让多方来维护关系,因为多对一的插入较为高效

 posted on     阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示

目录导航