Hibernate

关系数据库ORM框架

配置文件

hibernate.cfg.xml

核心配置文件,基本配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydb</property>
<!-- 控制台输出sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 是否格式化sql语句 -->
<property name="format_sql">false</property>
<!-- 自动生成表结构 -->
<property name="hbm2ddl.auto">update</property>
<!-- 数据库方言配置 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 引入ORM 映射文件 -->
<mapping resource="com/ljc/bean/User.hbm.xml" />
</session-factory>
</hibernate-configuration>

*.hbm.xml

bean映射文件,与javabean放在同一个包下,*为bean的名称,如User.hbm.xml,基本配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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.ljc.bean">
<class name="User" table="user">
<id name="id" column="id">
<!-- 主键生成策略 -->
<generator class="native"></generator>
</id>
<property name="name" column="username"></property>
<property name="password" column="password"></property>
</class>
</hibernate-mapping>

常用Api

Configuration

构造: //无参的configure()默认加载src根目录下的hibernate.cfg.xml,有参的为加载指定目录

1
Configuration config = new Configuration().configure();

SessionFactory

类似于JDBC连接池,用于管理所有session

1
SessionFactory sessionFactory = config.buildSessionFactory();

sessionFactory缓存配置信息:数据库配置信息、映射文件、预定义HQL语句 等
其线程安全,可以是成员变量,多个线程同时访问时,不会出现线程并发访问问题。

1
2
3
4
//获得新的session
sessionFactory.openSession();
//获得当前线程中绑定的session
sessionFactory.getCurrentSession();

getCurrentSession在事务提交或者回滚之后会自动关闭,而openSession需手动关闭
如果使用openSession而没有手动关闭,多次之后会导致连接池溢出
openSession每次创建新的session对象,getCurrentSession使用现有的session对象(单例)

hibernate支持将创建的session绑定到本地线程中,底层使用ThreadLocal,在程序之间共享session
但必须在hibernate.cfg.xml 配置以下属性才可使用getCurrentSession()

1
<property name="hibernate.current_session_context_class">thread</property>

Session

类似于JDBC的Connection,实现数据库的增删改查,单线程,线程不安全,不能编写成员变量

插入操作

1
2
3
4
5
6
7
//创建对象
User user = new User();
user.setId(123);
user.setName("LJC");
user.setPassword("123456");
//保存
session.save(user);

删除操作

1
2
3
4
//通过id查询出要删除的对象
User user = (User) session.get(User.class,1);
//删除
session.delete(user);

更新操作

1
2
3
4
5
6
// 通过id查询出要修改的对象
User user = (User) session.get(User.class, 1);
// 在查询结果上,进行修改
user.setName("ljc");
//更新
session.update(user);

查询操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//get方式通过id查询(方法被调用时立刻发送sql语句查询)
User user1 = (User) session.get(User.class,1);
//load方式通过id查询(调用时并没有查询数据库,返回代理对象/懒加载,当需要使用该对象的时候,才查询数据)
User user2 = (User) session.load(User.class,1);
//HQL方式
Query query = session.createQuery("from com.ljc.bean.User");
List<User> list = query.list();
//Criteria方式
Criteria criteria = session.createCriteria(User.class);
List<User> list1 = criteria.list();
//原生sql方式
SQLQuery query1 = session.createSQLQuery("select * from user");
// addEntity 将查询结果封装到指定对象中
query1.addEntity(User.class);
List<User> list2 = query.list();

Transaction

1
2
3
4
5
6
7
8
//打开事务
Transaction ts = session.beginTransaction();
//提交事务
ts.commit();
//回滚事务
ts.rollback();
//获得已经打开的事务对象
session.getTransaction();

如果提交或回滚事务,底层将自动关闭session

Query

封装HQL语句

1
2
3
4
5
6
7
8
9
10
11
//封装HQL
Query query = session.createQuery("from com.ljc.bean.User");
//将HQL语句执行,并返回结果(多行)
query.list();
//将HQL语句执行,并返回结果(一行)
query.uniqueResult();
//分页
//开始索引数startIndex
query.setFirstResult(0);
//每页显示个数 pageSize
query.setMaxResults(2);

多表映射

一对多/多对一

  1. 一对多

数据库:通过添加主外键的关联,表现一对多的关系(在多的一方加入外键,引用一的一方的主键)
代码中:通过在一方持有多方的集合实现,即在”一”的一端中使用元素表示持有”多”的一端的对象

  1. 多对一

多对一的关系和关系数据库中的外键参照关系最匹配,即在己方(多方)表中的一个外键参照另一个表的主键
通过在多方持有一方的引用实现,需要在”多”的一端使用配置

1
2
3
4
5
6
7
一方:
<set name="集合属性名" >
<key column="外键名" />
<one-to-many class="多的一方的类型" />
</set>
多方:
<many-to-one name="属性名" column="外键名" class="一的一方类型" />
  1. inverse

表示反转,是节点的一个属性(用来指定关联关系的维护),可以指定关联关系的方向,默认值为false(不反转)
//即表示一的一方要不要放弃维护外键关系
1、一方的hbm.xml文件的节点的inverse属性指定了关联关系的控制方向,默认由one方来维护
2、关联关系中,inverse=”false”则为主动方,由主动方负责维护关联关系
3、在一对多关联中,设置one方的inverse为true,这将有助于性能的改善
4、只存在于集合标记的元素中,Hibernate提供的集合元素包括

1
2
3
4
5
6
<!-- 配置单向一对多关系,设置inverse为true,由多方进行关联关系的维护 -->
<set name="stu" table="stu" inverse="true">
<!-- 指定关联的外键列 -->
<key column="gid"></key>
<one-to-many class="com.entity.Student"/>
</set>

  1. cascade

级联操作
1、当设置了cascade属性不为none时,Hibernate会自动持久化所关联的对象
2、cascade属性的设置会带来性能上的变动,需要谨慎设置

1
2
3
4
5
属性值 含义和作用
all 对所有操作进行级联操作
save-update 执行保存和更新操作时进行级联操作
delete 执行删除时进行级联操作
none 对所有操作不进行级联操作

多对多

数据库:使用中间表,分别引用两方的ID
对象: 两方都使用set集合表达

1
2
3
4
<set name="courses" table="t_student_course" >
<key column="sid" ></key>
<many-to-many class="Course" column="cid" ></many-to-many>
</set>

加载策略/优化查询

策略种类:延迟加载、立即加载
策略的应用:类级别的加载策略、关联级别的加载策略

类级别加载策略

即get与load方法查询数据的方式
其中load属性是否懒加载由hbm文件中class元素的lazy属性决定

  1. lazy=”true”:先返回一个代理对象,使用代理对象的属性时,才去查询数据库(默认值)
  2. lazy=”false”:与get一致,会立即加载数据

关联级别加载策略

在查询有关联关系的数据时,加载一方的数据是否需要将另一方立即查询出
默认: 与我关联的数据,在使用时才会加载.

关系中主要由的两个属性:fetch、lazy来设置

缓存

Hibernate 提供缓存机制

  1. 一级缓存:session级别缓存,在一次请求中共享数据
  2. 二级缓存:sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存

一级缓存

当获得一次会话session,hibernate在session中创建多个集合map,用于存放操作数据
如果之后需要相应的数据,优先从session缓存中获取,如果有就使用,有再查询数据库
当session关闭时,一级缓存销毁

一级缓存中的快照
与一级缓存一样的存放位置,对一级缓存数据备份,保证数据库的数据与一级缓存的数据一致
如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库

1
2
3
4
session.evict(user); 用于将某个对象从Session的一级缓存中清除
session.clear(); 用于将一级缓存中的所有对象全部清除
session.refresh(user); 保证一级缓存的数据与数据库的数据保持一致
session.flush(); 手动刷新缓存,默认情况提交commit()刷新

二级缓存

SessionFactory的缓存两部分

  1. 内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供给框架自己使用,对外只读,不能操作
  2. 外置缓存:使用另一个Map,用于存放用户自定义数据,默认不开启,需要第三方实现类。外置缓存即二级缓存

由4部分构成:类级别缓存/集合级别缓存/时间戳缓存/查询缓存(二级缓存的第2大部分,三级缓存)

通常使用EHCache:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernatede查询缓存提供了支持

二级缓存的适用场景:很少被修改的数据/不是很重要的数据,允许出现偶尔并发的数据/不会被并发访问的数据

1
2
3
4
5
6
7
一级缓存 二级缓存
缓存范围范围 事务范围 应用范围,当前应用内所有事务共享
并发访问策略 不会出现并发问题 序提供并发访问策略
数据过期策略 无 缓存对象的最大数目/最长时间等
缓存的软件实现 框架包含 第三提供,可插拔集成
物理介质 内存 内存和硬盘
启用方式 默认启用,不可关闭 默认不启用,选择性开启