Hibernate五大关键接口
在Hibernate的API中有5个非常重要的接口:Configuration、SessionFactory、Session、Transaction和Query,它们是Hibernate组成的核心。
Configuration
负责Hibernate配置工作,创建SessionFactory对象,在Hibernate启动过程中,Configuration类的实例首先定位在映射文件位置,读取配置,然后创建SessionFactory对象。
##SessionFactory
SessionFactroy接口负责初始化Hibernate。它充当数据存储源的代理,使用工厂模式创建Session对象。需要注意的是SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
Session
Session 接口对于Hibernate 开发人员来说是一个最重要的接口。在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。这在实际项目中非常很重要,因为在程序中,可能会不断地创建以及销毁Session对象,如果Session 的开销太大,会给系统带来不良影响。但是Session对象是非线程安全的,因此在你的设计中,最好是一个线程只创建一个Session对象。 Session可以看作介于数据连接与事务管理一种中间接口。我们可以将Session想象成一个持久对象的缓冲区,Hibernate能检测到这些持久对象的改变,并及时刷新数据库。我们有时也称Session是一个持久层管理器,因为Session负责执行被持久化对象的增、删、改、查操作,类似于JDBC的Connection和Statement, 诸如存储持久对象至数据库,以及从数据库从获得它们。需要注意的是,Hibernate的Session不同于JSP 应用中的HttpSession。在Hibernate中,我们使用Session这个术语时,指的是Hibernate 自己的Session。
Transaction
负责事务相关的操作,它代表的是Hibernate事务,本质上也是数据库事务。一般在Hibernate的增删改中出现,但是使用Hibernate一般使用Spring去管理事务。
Query
负责执行各种数据查询功能,它可以使用Hibernate特有的HQL语言和SQL语言两种方式。
*.hbm.xml基本配置
Hibernate的基本映射信息的配置文件,也就是系统中每一个类与其对应的数据库表之间
的关联信息,这种配置文件一般命名为:类名.hbm.xml,下面我们通过一个具体的代码示例来看一下类名.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">
<!-- package声明POJO类所在的包,如果不写那么在class中需要填写POJO类的完全限定名 -->
<hibernate-mapping>
<!--
class指一个POJO类
该类必须提供公共的无参构造方法-通过反射产生对象
属性用private修饰,并且生成对应的get/set方法
类不能用final来修饰-hibernate需要产生代理类(cglib),否则出错
name表示POJO类名或者完全限定名
table可选,表示POJO类对应数据库中的表名;如果不写默认是类名
-->
<class name="cn.hibernate.pojo.User" table="user">
<!--
id对应数据库表中的主键
name指实体类的标识属性名
column表示对应数据库表的列名,如果不写则数据库中列名和属性名一致
length表示数据库表中对应数据类型的长度,如果不写有默认长度
type表示类型,如果不写hibernate可以找到对应pojo类的属性的类型
-->
<id name="id">
<!--
主键生成策略
increment:用于为long,short或者int类型生成唯一标识,
只有在没有其他进程往同一张表中插入数据时才能使用.在集群下不要使用
identity:对DB2,MySQL, MS SQL Server, Sybase
和HypersonicSQL的内置标识字段提供支持。
返回的标识符是long, short或者int类型的。
sequence:在支持序列的数据库中使用(oracle),
返回的标识符是long, short或者int类型的。
<generator class="sequence">
<param name="sequence">user_sequence</param>
</generator>
uuid:UUID被编码为一个32位16进行数字的字符串.
native:根据底层数据库的能力选择identity,sequence 或者hilo中的一个.
assigned:自己指定主键.
-->
<generator class="native"></generator>
</id>
<!--
实体类的属性
name:指明POJO类属性名称(区分大小写)column:表示对应数据库表的列名,如果不写则数据库中列名和属性名一致
两种写法效果一致.
-->
<property name="username">
<column name="username"></column>
</property>
<property name="password"/>
</class>
</hibernate-mapping>
Hibernate对象生命周期
Hibernate中对象有三种状态: 瞬时状态(Transient)、持久状态(Persistent)、游离状(Detached)。
- 瞬时状态:刚刚使用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的Java对象被称为临时对象。Session中没有,数据库中没有。
- 持久化状态:已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象被称为持久化对象。Session中有,数据库中有。
- 游离状态:已经被持久化,但不处于Session的缓存中。处于游离状态的Java对象被称为游离对象。Session中没有,数据库中有
##对象状态转换相关方法
- 瞬时状态转为持久状态
使用Session对象的save()或saveOrUpdate()方法保存对象后,该对象的状态由瞬时状态转换为持久状态。使用Session对象的get()或load()方法获取对象,该对象的状态是持久状态。 - 持久状态转为瞬时状态
执行Session对象的delete()方法后,对象由原来的持久状态变为瞬时状态,因为此时该对象没有任何的数据库数据关联。 - 持久状态转为游离状态
执行了Session对象的evict()、clear()或close()方法,对象由原来的持久状态转为游离状态。 - 游离状态转为持久状态
重新获取Session对象,执行Session对象的update()或saveOrUpdate()方法,对象由游离状态转为持久状态,该对象再次与Session对象相关联。 - 游离状态转为瞬时状态
执行Session对象的delete()方法,对象由游离状态转为瞬时状态。处于瞬时状态或游离状态的对象不再被其他对象引用时,会被Java虚拟机按照垃圾回收机制处理。
##封装一个可重复调用的HibernateUtil.java工具类
public class HibernateUtil {
private static final ThreadLocal<Session> THREAD_LOCAL = new ThreadLocal<Session>();
private static SessionFactory sessionFactory = null;
private static StandardServiceRegistry serviceRegistry = null;
// 通过静态块初始化对象
static{
try {
serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
}catch (Exception e ){
System.out.println("创建SessionFactory失败");
e.printStackTrace();
}
}
// 获取session
public static Session getSession(){
Session session = THREAD_LOCAL.get();
if (null == session || !session.isOpen()){
if (null ==sessionFactory){
rebuildSessionFactoty();
}
session = (null != sessionFactory) ? sessionFactory.openSession() : null;
THREAD_LOCAL.set(session);
}
return session;
}
// 初始化SessionFactory
public static void rebuildSessionFactoty(){
try {
serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(serviceRegistry)
.buildMetadata().buildSessionFactory();
} catch (Exception e) {
System.out.println("创建SessionFactory失败");
e.printStackTrace();
}
}
// 关闭session
public static void closeSession(){
Session session = THREAD_LOCAL.get();
THREAD_LOCAL.set(null);
if (null != session && session.isOpen()){
session.close();
}
}
}
new -> save -> close -> update
@Test
public void testSave() {
Session session = null;
Transaction tx = null;
User user = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
// 构造对象 -> 瞬时状态,session中没有,数据库中没有
user = new User();
user.setUsername("刘德华");
user.setPassword("123");
// 调用save() -> 持久状态,user被session管理,session中有,数据库中有
session.save(user);
/*
* 在持久状态下,脏数据检查:当提交事务时或清理缓存时,发现session中的数据和
* 数据库中的数据不一致时,将会把session中的数据更新到数据库中
*/
user.setUsername("张学友");
// 在保存以后再修改对象将会产生多条sql语句,效率较低,建议在save前修改
session.flush();
tx.commit();
} catch (Exception e) {
e.printStackTrace();get/load -> clear/evict
tx.rollback();
} finally {
HibernateUtil.closeSession();
}
// session被关闭 -> 游离状态,session中没有,数据库中有
System.out.println("姓名:" + user.getUsername());
user.setUsername("梁朝伟");
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
// 调用update() -> 持久状态,user被session管理,session中有,数据库中有
// 如果此时先get()|load()获取到user -> 持久状态,session中有,数据库中有
// 再调用delete() -> 瞬时状态,sesison中没有,数据库中没有
session.update(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
HibernateUtil.closeSession();
}
// 游离状态
}
get/load -> clear/evict
@Test
public void testGet1() {
Session session = null;
Transaction tr = null;
User user = null;
try {
session = HibernateUtil.getSession();
tr = session.beginTransaction();
// get() -> 持久状态,user被session管理,session中有,数据库中有
// get()会立即查询该对象:范围从session,SessionFactory,数据库
user = (User) session.get(User.class, 1);
System.out.println("姓名:" + user.getUsername());
tr.commit();
// clear()清除session缓存中所有对象,evict()清除指定对象
session.clear();
// session.evict(user);
// clear()|evict() -> 游离状态,不被session管理,数据库中不会被更改
user.setUsername("张国荣");
System.out.println(user.getUsername());
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
} finally {
HibernateUtil.closeSession();
}
/*get/load的区别:get会立即去查询对象,load在使用才去查询(懒加载),get找不到对象时返回null,load找不到对象时抛异常。*/
}
@Test
public void testGet2() {
Session session = null;
Transaction tr = null;
User user = null;
try {
session = HibernateUtil.getSession();
tr = session.beginTransaction();
// get() -> 持久状态,user被session管理,session中有,数据库中有
// get()会立即查询该对象:范围从session,SessionFactory,数据库
// get()如果找不到对象不会抛异常,返回null
user = (User) session.get(User.class, 10);
System.out.println("姓名:" + user.getUsername());
tr.commit();
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
} finally {
HibernateUtil.closeSession();
}
}
@Test
public void testLoad() {
Session session = null;
Transaction tr = null;
User user = null;
try {
session = HibernateUtil.getSession();
tr = session.beginTransaction();
// load() -> 持久状态
// load()不会立即去查询对象,到使用时才会查询(懒加载):范围从session,SessionFactory,数
//据库
// load()当对象不存在时会抛出org.hibernate.ObjectNotFoundException异常
user = (User) session.load(User.class, 10);
System.out.println("姓名:" + user.getUsername());
tr.commit();
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
} finally {
HibernateUtil.closeSession();
}
}
get/load的区别:get会立即去查询对象,load在使用才去查询(懒加载),get找不到对象时返回null,load找不到对象时抛异常。
update
@Test
public void testUpdate() {
Session session = null;
Transaction tr = null;
User user = null;
try {
session = HibernateUtil.getSession();
tr = session.beginTransaction();
// 手动构造的瞬时状态对象也可以修改,但是需要指定所有属性,不建议使用
//user = new User();
//user.setId(3);
//user.setUsername("李四");
// get() -> 持久状态,user被session管理,session中有,数据库中有
user = (User) session.get(User.class, 2);
// 通过从数据库中加载该对象然后再修改可以进行判断进而避免异常,提高程序的健壮性
if (null != user) {
user.setUsername("老王");
// update() -> 持久状态,user被session管理,session中有,数据库中有
session.update(user);
}
tr.commit();
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
} finally {
HibernateUtil.closeSession();
}
}
注意:先获取对象进行判断再更新,可以避免异常,提高程序的健壮性
delete
@Test
public void testDelete() {
Session session = null;
Transaction tr = null;
User user = null;
try {
session = HibernateUtil.getSession();
tr = session.beginTransaction();
// 手动构造的瞬时状态对象,指定主键也是可以删除该对象的,但是不建议这么用
//user = new User();
//user.setId(5);
// get() -> 持久状态,user被session管理,session中有,数据库中有
user = (User) session.get(User.class, 10);
// 通过从数据库中加载该对象然后删除可以进行判断进而避免异常,提高程序的健壮性
if (null != user) {State Mem Session DB
// delete() -> 瞬时状态,session中没有,数据库中没有
session.delete(user);
}
tr.commit();
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
} finally {
HibernateUtil.closeSession();
}
}
注意:先获取对象进行判断再删除,可以避免异常,提高程序的健壮性。
对象三种状态的比较
State | Memory | Session | DB |
---|---|---|---|
Transient | y | n | n |
Persistent | y | y | y |
Detached | y | n | y |