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
配置数据库
创建文件 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"/>
编写测试代码
@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中配置将配置文件自动构建打包
<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
封装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中的缓存,一级缓存)
单向多对一
HIbernate映射
自动生成表
也可以将xml配置文件中的update的构建表的方式注解打开
<!-- 是否⾃动⽣成数据库 -->
<property name="hibernate.hbm2ddl.auto">update</property>
配置实体类对象
设有一个student表,以及一个grade表
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是多对一、一对多、一对一、多对多各种关系之间的一种级联操作行为。
一般使用save-update,其他选项一般较少使用,级联插入
在存储的时候只需要存一方就行
维护关系
加上 inverse="true"由对方来维护关系,此时一端不再维护,当使用一对多来插入时,不会再更改grade_id字段
强制让多方来维护关系,因为多对一的插入较为高效