Hibernate-学习笔记汇总
一、入门
1.概念:hibernate 是一个数据库持久层框架,解决的是数据库CRUD的问题。
2.需要的jar包
2.1 Hibernate核心jar包
2.2 Hibernate第三方依赖
2.3 数据库驱动jar如 ojdbc6.jar mysql.jar
2.3 maven依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- 添加Hibernate依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.10.Final</version>
</dependency>
<!-- 添加Log4J依赖 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.6.4</version>
</dependency>
<!-- 添加javassist -->
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
<!-- mysql数据库的驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
3.Hibernate配置文件
3.1 hibernate.cfg.xml 核心配置文件
属性 | 说明 |
---|---|
dialect | 方言,告知hibernate连接的是哪种数据库 |
show_sql | true/false |
3.2xxx.hbm.xml 映射文件,文件名以.hbm.xml结尾
4.Hibernate核心对象
4.1 Configuration,读取 hibernate 相关配置文件
4.2 SessionFactory,创建 session 对象
4.3 Session,内部封装了 Connection,负责对数据做CRUD操作
4.4 Transaction 事务
// hibernate增删改查需要手动控制事务
tx.begin();
tx.commit();
tx.rollback();
5.Query查询,复杂查询,涉及HQL,后续会有篇章描述
6.开发步骤:
6.1 O 实体对象
6.2 R 创建数据库中的表
6.3 M 映射文件
6.4 映射文件注册到 hibernate.cfg.xml
核心配置文件中
6.5 API 测试
7.代码示例
7.1 POJO对象
/**
* @author jyc
* @date 2022/9/3 20:41
*/
package com.jyc;
import java.util.Date;
public class Person {
private Integer id;
private String name;
private double salary;
private Date birthday;
}
7.2 创表语句
CREATE TABLE s_PERSON(
s_ID int primary key auto_increment,
s_name varchar(50),
s_salary double(12,2),
s_birthday date
)
7.3 Person对象的配置文件 person-hnm.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>
<class name="com.jyc.Person" table="s_person">
<id name="id" column="s_id" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="name" column="s_name" type="java.lang.String"></property>
<property name="salary" column="s_salary" type="java.lang.Double"></property>
<property name="birthday" column="s_birthday" type="java.util.Date"></property>
</class>
</hibernate-mapping>
7.4 hibernate.cfg.xml
配置文件
<!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 name="foo">
<!-- 数据库连接参数 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate?characterEncoding=utf-8</property>
<property name="connection.username">root</property>
<property name="connection.password">1234</property>
<!-- hibernate相关参数 -->
<property name="show_sql">true</property>
<property name="format_sql">false</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 注册映射文件 -->
<mapping resource="person-hnm.xml"/>
</session-factory>
</hibernate-configuration>
7.5 注册映射文件到 hibernate-cfg.xml
7.6 API测试
7.6.1 插入
/**
* 用于测试插入
*/
@Test
public void testInert(){
Person person = new Person();
person.setName("JC");
person.setSalary(999999);
person.setBirthday(new Date());
Configuration cfg = new Configuration();
// 读取配置文件
cfg.configure();
// 构建sessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 构建session
Session session = sessionFactory.openSession();
Transaction tx = session.getTransaction();
tx.begin();
session.save(person);
tx.commit();
}
7.6.2 查询
/**
* 用于测试查询
*/
@Test
public void testGet(){
Configuration cfg = new Configuration();
// 读取配置文件
cfg.configure();
// 构建sessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 构建session
Session session = sessionFactory.openSession();
Person dbPerson = (Person)session.get(Person.class, 1);
System.out.println("dbPerson = " + dbPerson);
}
7.6.3 更新
/**
* 用于测试更新
*/
@Test
public void testUpdate(){
Configuration cfg = new Configuration();
// 读取配置文件
cfg.configure();
// 构建sessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 构建session
Session session = sessionFactory.openSession();
Transaction tx = session.getTransaction();
tx.begin();
Person dbPerson = (Person)session.get(Person.class, 1);
System.out.println("dbPerson = " + dbPerson);
dbPerson.setSalary(66666);
dbPerson.setName("jc");
session.update(dbPerson);
tx.commit();
}
7.6.4 删除
/**
* 用于测试删除
*/
@Test
public void testDelete(){
Configuration cfg = new Configuration();
// 读取配置文件
cfg.configure();
// 构建sessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 构建session
Session session = sessionFactory.openSession();
Transaction tx = session.getTransaction();
tx.begin();
Person person = new Person();
person.setId(1);
session.delete(person);
tx.commit();
}
8.提示
8.1 hibernate方言位置
8.2 为什么不需要输入 hibernate.cfg.xml 的文件路径?
二、封装HibernateUtil
1.HibernateUtil 的工具类
/**
* @author 贾宇超
* @date 2022/9/3 23:57
*/
package com.jyc;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory sessionFactory = null;
static {
Configuration cfg = new Configuration();
// 读取配置文件
cfg.configure();
// 构建sessionFactory
sessionFactory = cfg.buildSessionFactory();
}
public static Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
2.SessionFactory.getCurrentSession()
方法 | 说明 |
---|---|
SessionFactory.openSession() | 每一次调用都会创建新的session |
SessionFactory.getCurrentSession() | 会把创建好的session放到ThreadLoacl中,保证一个线程用同一个session |
getCurrentSession()
注意事项:
2.1 必须在hibernate.cfg.xml中配置
2.2 必须运行在事务中,查询也不例外。
2.3 事务结束后会自动关闭
3.getCurrentSession()
在hibernate.cfg.xml
中的配置
<!-- getCurrentSession在 hibernate.cfg.xml 的配置 -->
<property name="current_session_context_class">thread</property>
三、应用注解(Annotation)替换 映射文件
1.创建实体对象
/**
* @author jyc
* @date 2022/9/3 20:41
*/
package com.jyc;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "t_user")
public class Student {
@Id
@GenericGenerator(name="student_id",strategy = "increment")
@GeneratedValue(generator = "student_id")
@Column(name = "t_id")
private Integer id;
@Column(name = "t_name")
private String name;
@Column(name = "t_age")
private Integer age;
@Column(name = "t_bir")
private Date bir;
}
2.创建表
CREATE TABLE t_user(
t_ID int primary key auto_increment,
t_name varchar(50),
t_age int(3),
t_bir date
)
3.注册类文件到 hibernate.cfg.xml
中
<mapping class="com.jyc.Student"/>
四、hibernate 关联关系映射
1.一对一
1.1 实体对象
1.1.1 存有外键的主体
核心注解
@OneToOne
@JoinColumn(name="department_id")
@Cascade(CascadeType.ALL)
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GenericGenerator(name="employee_pk",strategy = "increment")
@GeneratedValue(generator = "employee_pk" )
@Column(name = "id")
private Integer id;
@Column
private String username;
@Column
private Double salary ;
@Column
private Integer age;
@OneToOne // 关系属性注解
@JoinColumn(name="department_id")
// 关于外键注解
@Cascade(CascadeType.ALL)
private Department department;
1.1.1 另一个 一
核心注解 @OneToOne(mappedBy = "department")
注意:department 依赖于 Persion 对象中 的 department 属性
@Entity
@Table(name = "department")
public class Department {
@Id
@GenericGenerator(name="department_pk",strategy = "increment")
@GeneratedValue(generator = "department_pk" )
@Column(name = "id")
private Integer id;
@Column
private String department_name;
@Column
private Integer department_id ;
@Column
private String note;
@OneToOne(mappedBy = "department")
private Employee employee;
1.2 表
CREATE TABLE department(
ID int(6) primary key auto_increment,
DEPARTMENT_NAME varchar(50),
DEPARTMENT_ID int(6),
NOTE varchar(100)
);
INSERT INTO `department` VALUES (101, '研发部', 100, NULL);
INSERT INTO `department` VALUES (102, '公关部', 110, NULL);
INSERT INTO `department` VALUES (103, '宣策部', 120, NULL);
INSERT INTO `department` VALUES (104, '礼仪部', 130, NULL);
CREATE TABLE employee(
ID int(6) primary key auto_increment,
USERNAME varchar(50),
SALARY double(8, 2),
AGE int(3),
DEPARTMENT_ID int(6)
);
INSERT INTO `employee` VALUES (110, 'John111', 8200.00, 50, 101);
INSERT INTO `employee` VALUES (111, 'Ismael', 7700.00, 40, 103);
INSERT INTO `employee` VALUES (112, 'Jose Manuel', 7800.00, 30,102);
INSERT INTO `employee` VALUES (113, 'Luis111', 6900.00, 20, 103);
INSERT INTO `employee` VALUES (114, 'Den', 11000.00, 18, 101);
INSERT INTO `employee` VALUES (115, 'Alexander11', 3100.00, 15, 101);
INSERT INTO `employee` VALUES (116, 'Shelli', 2900.00, 24, 104);
1.3 注册实体类到 hibernate.cfg.xml
<mapping class="com.jyc.Department"/>
<mapping class="com.jyc.Employee"/>
1.4 api测试
1.5 注意
toString()方法,两个依赖对象不要互相调用,不然会报错:栈溢出,stackOverFlow
2. 一对多
注意:如果关系属性为集合,则必须声明为集合的接口类型,并进行初始化,记得提供get() set() 方法
2.1 实体
2.1.1 单向关系a 一个部门中的所有员工,
2.1.1.1 一,部门
核心注解 @OneToMany
@Entity
@Table(name = "department")
public class Department {
@Id
@GenericGenerator(name="department_pk",strategy = "increment")
@GeneratedValue(generator = "department_pk" )
@Column(name = "d_id")
private Integer id;
@Column
private String department_name;
@Column
private Integer department_id ;
@Column
private String note;
@OneToMany
@JoinColumn(name = "d_id")
@Cascade(CascadeType.ALL)
private Set<Employee> employee;
2.1.1.2 多,员工
新增日期注解 @Temporal(TemporalType.DATE)
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GenericGenerator(name="employee_pk",strategy = "increment")
@GeneratedValue(generator = "employee_pk" )
@Column(name = "id")
private Integer id;
@Column
private String username;
@Column
private Double salary ;
@Column
private Integer age;
@Temporal(TemporalType.DATE)
private Date bir;
2.1.2 单向关系b 显示员工及部门信息
2.1.2.1 部门
@Id
@GenericGenerator(name="department_pk",strategy = "increment")
@GeneratedValue(generator = "department_pk" )
@Column(name = "d_id")
private Integer id;
@Column
private String department_name;
@Column
private Integer department_id ;
@Column
private String note;
2.1.2.1 员工
核心注解
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GenericGenerator(name="employee_pk",strategy = "increment")
@GeneratedValue(generator = "employee_pk" )
@Column(name = "id")
private Integer id;
@Column
private String username;
@Column
private Double salary ;
@Column
private Integer age;
@Temporal(TemporalType.DATE)
private Date bir;
@ManyToOne
@JoinColumn(name="d_id")
@Cascade(CascadeType.ALL)
private Department department;
2.1.3 双向关系b 既想看员工属于哪个部门,又想看哪个部门有多少员工
2.1.2.1 部门
核心注解 @OneToMany(mappedBy = "department")
@Entity
@Table(name = "department")
public class Department {
@Id
@GenericGenerator(name="department_pk",strategy = "increment")
@GeneratedValue(generator = "department_pk" )
@Column(name = "d_id")
private Integer id;
@Column
private String department_name;
@Column
private Integer department_id ;
@Column
private String note;
@OneToMany(mappedBy = "department")
@Cascade(CascadeType.ALL)
private Set<Employee> employees = new HashSet<>();
2.1.2.1 员工
核心注解
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GenericGenerator(name="employee_pk",strategy = "increment")
@GeneratedValue(generator = "employee_pk" )
@Column(name = "id")
private Integer id;
@Column
private String username;
@Column
private Double salary ;
@Column
private Integer age;
@Temporal(TemporalType.DATE)
private Date bir;
@ManyToOne
@JoinColumn(name="d_id")
@Cascade(CascadeType.ALL)
private Department department;
1.2 表 (与第一套表的区别是:新增了Date属性bir) 修改了字段名d_id
CREATE TABLE department(
d_ID int(6) primary key auto_increment,
DEPARTMENT_NAME varchar(50),
DEPARTMENT_ID int(6),
NOTE varchar(100)
);
INSERT INTO `department` VALUES (100, '研发部', 100, NULL);
INSERT INTO `department` VALUES (101, '公关部', 110, NULL);
INSERT INTO `department` VALUES (102, '宣策部', 120, NULL);
INSERT INTO `department` VALUES (103, '礼仪部', 130, NULL);
CREATE TABLE employee(
ID int(6) primary key auto_increment,
USERNAME varchar(50),
SALARY double(8, 2),
AGE int(3),
d_id int(6),
BIR date
);
INSERT INTO `employee` VALUES (110, 'John111', 8200.00, 50, 101,SYSDATE());
INSERT INTO `employee` VALUES (111, 'Ismael', 7700.00, 40, 103,SYSDATE());
INSERT INTO `employee` VALUES (112, 'Jose Manuel', 7800.00, 30,102,SYSDATE());
INSERT INTO `employee` VALUES (113, 'Luis111', 6900.00, 20, 103,SYSDATE());
INSERT INTO `employee` VALUES (114, 'Den', 11000.00, 18, 101,SYSDATE());
INSERT INTO `employee` VALUES (115, 'Alexander11', 3100.00, 15, 101,SYSDATE());
INSERT INTO `employee` VALUES (116, 'Shelli', 2900.00, 24, 104,SYSDATE());
1.3 注册
<mapping class="com.jyc.Department"/>
<mapping class="com.jyc.Employee"/>
3.多对多
3.0 注意:双向关系的注解位置可以互换。
3.1 实体
3.1.1 学生
核心注解:@ManyToMany
@JoinTable
@Entity
@Table(name = "student")
public class Student {
@Id
@GenericGenerator(name="student_id",strategy = "increment")
@GeneratedValue(generator = "student_id")
@Column
private Integer id;
@Column
private String name;
@Column
private Integer age;
@ManyToMany
@JoinTable(name="t_s_c",
joinColumns = {@JoinColumn(name = "s_id")},
inverseJoinColumns = {@JoinColumn(name = "c_id")})
@Cascade(CascadeType.ALL)
private Set<Course> courses = new HashSet<>();
}
3.1.2 课程
@Entity
@Table(name = "course")
public class Course {
@Id
@GenericGenerator(name="course_pk",strategy = "increment")
@GeneratedValue(generator = "course_pk")
private Integer id;
@Column
private String name;
@Column
private Integer score;
@ManyToMany(mappedBy = "courses")
@Cascade(CascadeType.ALL)
private Set<Student> students = new HashSet<>();
}
3.2 表
CREATE TABLE Student(
ID int primary key auto_increment,
name varchar(50),
age int(3)
)
insert into student values(1,'张三',19);
insert into student values(2,'李四',18);
insert into student values(3,'王五',21);
CREATE TABLE course(
ID int primary key auto_increment,
name varchar(50),
score int(2)
)
insert into course values(1,'spring',6);
insert into course values(2,'struts2',3);
insert into course values(3,'springmvc',4);
insert into course values(4,'hibernate',2);
CREATE TABLE t_s_c(
ID int primary key auto_increment,
c_id int,
s_id int
)
insert into t_s_c values(1,1,1);
insert into t_s_c values(2,1,2);
insert into t_s_c values(3,1,3);
insert into t_s_c values(4,2,1);
insert into t_s_c values(5,3,1);
insert into t_s_c values(6,4,1);
3.3 注册
<mapping class="com.jyc.Student"/>
<mapping class="com.jyc.Course"/>
3.4 API测试
3.4.1 一个课程被多个学生选择
/**
* 用于测试 多对多 课程被多个学生选择
*/
@Test
public void testManyAndManyByCourse(){
org.hibernate.Session currentSession = HibernateUtils.getCurrentSession();
Transaction transaction = currentSession.getTransaction();
transaction.begin();
Course course = (Course)currentSession.get(Course.class, 1);
Set<Student> students = course.getStudents();
students.forEach( student -> {
System.out.println("student = " + student);
});
System.out.println("course = " + course);
transaction.commit();
}
3.4.1 一个学生选择多个课程
/**
* 用于测试 多对多 学生选择了多少课程
*/
@Test
public void testManyAndManyByStudent(){
org.hibernate.Session currentSession = HibernateUtils.getCurrentSession();
Transaction transaction = currentSession.getTransaction();
transaction.begin();
Student student = (Student)currentSession.get(Student.class, 1);
Set<Course> courses = student.getCourses();
courses.forEach(course -> {
System.out.println("course = " + course);
});
System.out.println("student = " + student);
transaction.commit();
}
3.4.1 多个学生选择多个课程
/**
* 用于测试 多对多 学生选择了多少课程
*/
@Test
public void testManyAndManyByStudentByList(){
org.hibernate.Session currentSession = HibernateUtils.getCurrentSession();
Transaction transaction = currentSession.getTransaction();
transaction.begin();
Query query = currentSession.createQuery(" from Student ");
List<Student> students = query.list();
students.forEach( student -> {
System.out.println("student = " + student);
Set<Course> courses = student.getCourses();
courses.forEach(course -> {
System.out.println("course = " + course);
});
System.out.println("");
} );
transaction.commit();
}
五、主键生成器 Generator
前提:主键生成器的注解必须应用在ID属性之上,也就是自然主键(唯一且无业务含义)。
使用:
@GenericGenerator(name="course_pk",strategy = "increment")
@GeneratedValue(generator = "course_pk")
类型 | 特点 | 注意 |
---|---|---|
increment | 查询当前表ID的最大值+1作为新纪录的主键 | 多线程访问,或者分布式系统,未添加分布式锁解决方案,会产生主键冲突问题 |
sequence | 调用数据库的sequence | 需要数据库支持,如Oracle、DB2、Postgre strategy=“sequence” 默认调用 hibernate_sequence 注解:strategy = “sequence”,parameters = {@Parameter(name=“sequence”,value=“course_seq”)} |
identity | 支持主键自增长的数据库 | MySQL、SQLServer |
uuid | 全球唯一的字符串主键 | 无法利用主键索引 |
assigned | 手工分配主键生成器 |
六、JPA 规范与 Hibernate 的关系
1.JAVA Persistence APi 是从JAVAEE5 诞生的一组接口,Hibernate是JPA实现的技术。
2.非JPA注解:
@GenericGenerator
@Cascade
3.JPA提供的替代注解
Sequence
Identity
七、HQL(Hibernate Query Language)
1.查询所有数据
currentSession.createQuery(" from Student ");
List<Student> students = query.list();
2.查询数据,使用占位符增加查询条件
Query query = currentSession.createQuery(" from Student as s where s.id = ? ");
query.setString(0,"1");
List<Student> students = query.list();
3.查询苏剧,新增查询条件,返回单条记录
Query query = currentSession.createQuery(" from Student as s where s.id = ? ");
query.setString(0,"1");
Student student= (Student)query.uniqueResult();
4.注意:
4.1 HQL类似于SQL语句
4.2 from 后加入类名
4.3 没有 select 子句,封装对象时 select 每一行会封装成一个OBject()
4.4 如果使用列,需要通过 as 定义表别名,通过别名.属性的方式表达
5.HQL多表操作
5.1 隐式多表连接
通过关系属性完成多表操作,看似是一张表的操作,实质是多张表的处理。
存在问题:HQL翻译的SQL语句,执行效率低,特殊的表操作不支持
5.2 显示多表连接
5.1 join关键字
5.2 inner join
5.3 迫切内连接(fetch)
5.3.1 把每一行的查询结果进行封装
5.3.2 SQL:
selecte e.*,d.* from t_employee e inner join t_department d on e.d_id = d.id
5.3.3 HQL(用的是类和属性):
from Employee as e inner join fetch e.department
5.4 left join
5.5 out join 右外连接不能加入fetch
5.6 full join 不能书写HQL
八、Hibernate 缓存 Cache
1. Session缓存
同一个session中的同一个查询,只会与数据库交互一次,获取到的内容会存放如session的map对象中作为缓存使用,Map对象的key = pk + 类型 ,value = 对象。
注意:
1.1 必须明确以主键为条件的查询,才可以利用Session缓存
1.2 session.get()方法才可以利用session缓存,HQL不可以
1.3 除了查询(get()、query())外,session的save()、update()、delete()方法操作的实体同样可以保存到session的缓存中。
1.4 清空 session缓存的方式
session.close(); //等价于事务结束
session.clear();
session.evict(entity);
2. Hibernate 的缓存体系
2.1 一级缓存:sesion的缓存,事务级别缓存
2.2 二级缓存:sessionFactory缓存,应用级缓存
3.二级缓存
3.1 二级缓存默认是被hibernate关闭的
3.2 Hibernate 借用第三方缓存框架完成二级缓存的实现。
ehcache、oscache、jbosscache、memcache、redis
4.二级缓存的使用步骤
4.1 引入外部二级缓存jar、配置文件
4.2 启动hibernate二级缓存,在 hibernate-cfg.xml
中配置
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
4.3 在需要放置二级缓存的实体上面加入注解,表示它需要放入二级缓存中
4.4 @Cache
READ_ONLY 只读策略
READ_WRITE 可读可写
注意:
查询缓存的key与HQL,查询参数以及分布参数有关,而且一旦查询涉及到的任何一张表的数据发生了变化,缓存就失效了,所以在生产环境中命中率较低。查询缓存保存的是结果集的id列表,而不是结果集本身 ,命中缓存的时候,会根据id一个一个地先从二级缓存查找 ,找不到再查询数据库。
查询缓存通常是和二级缓存联合使用的。
5.Query_Cache 查询缓存
一级缓存,二级缓存,必须明确地使用主键进行查询
,
查询缓存 没有必须使用主键的约束
,所以主要应用在Quey操作中
<property name="cache.use_query_cache">true</property>
// 查询缓存要想应用成功,必须HQL完全一致。
query.setCacheable(true);
九、Hibernate 对象状态
状态 | 特点 |
---|---|
临时(transinet) | 数据没有存储到数据库 |
持久化 (persistent) | 实体的数据存储在了数据库,并且实体纳入了session的缓存 |
游离状态 | 实体的数据存储在了数据库,并且实体没有纳入session的缓存 |
十、Hibernate 延迟加载(懒加载 lazy)
类型 | 说明 |
---|---|
加载 | 把数据库中的数据,查询到内存中 |
立即加载 | 调用了对应的查询方法后,hibernate 不管用户需不需要这个数据, 都立即发送sql查询。get()|queyr() |
延迟加载 | 当调用了对应的查询方法后,hibernate不会立即发送sql查询语句,只有当用户需要使用数据时,才会查询。 |
1.一般属性的延迟加载
当调用了session.load()方法后,hibernate 不会立即发送 sql 查询数据,只有当用户第一次使用属性数据时,才会查询。
2.关系属性的延迟加载
调用了查询方法后,hibernate不会立即发送sql查询关系属性数据,只有当用户第一次使用关系属性数据时,才会查询。Hibernate引入延迟加载是为了减少内存的占用。
延迟加载的异常:
org.hibernate.LazyInitializationException: 当延迟加载时,发现 session 已经关闭(等价于事务结束)
解决延迟加载:
# 1.扩大事务边界,把延迟加载的代码,放置在事务的内部。
可以把事务扩大到过滤器中
Spring解决了这个问题OpenSessionInView--->Filter--Spring
# 2.改变延迟加载的默认策略
关系属性 @OneToMany( fetch=FetchType.EARGE )