Hibernate 学习详解
Hibernate简介
Hibernate框架
简介
Hibernate 是数据持久化框架之一,也是一个开发源代码的ORM(对象关系映射) 解决方案;
Hibernate 内部封装了通过JDBC 访问数据库的操作,
创始人:Gavin King
EJB 3.0专家委员会成员,JBoss核心成员之一,《Hibernate in Action》的作者;
Hibernate是ORM解决方案
基于ORM HIbernate在对象模型——关系数据库之间建立了一座桥梁;
通过Hibernate 可以实现不在需要编写SQL语句操作关系型数据库中的表
使用APl 直接操作JavaBean对象就可以实现数据 存储 查询 更改 删除…提高了程序开发速度…
Hibernate的优缺点
优点:
- 简化了JDBC 繁琐的编码,提高持久化代码的开发速度, 降低了维护成本;
- 支持面向对象的特效:组合 继承 多态…使开发者不必在, 对象模型 数据模型之间来回切换;
- 可移植性好(对于多种数据库之间来回切换几乎不受影响), 开源免费!!
缺点:
- 不适合需要使用数据库的特定优化机制的情况
- 不适合大规模的批量数据处理 (底层固定的SQL对于高数据的查询不方便优化~)
Hibernate 和 Mybatis比较
都属于ORM框架,为数据层提供持久化操作的支持;
- Hibernate的ORM实现更加完善,提供了对象状态管理、级联操作等功能
- 完全面向对象,语句与数据库无关,开发者无需关注SQL的生成,开发简单,便于修改,数据库移植性好
- 由于直接使用SQL,MyBatis使用自由度较高方便调优
Hibernate框架搭建
部署JAR文件
Hibernate的官方网站http://hibernate.org 下载需要的jar文件;
推荐下载:hibernate-distribution-3.6.10.Final-dist.zip
Hibernate所需Jar文件
名称 | 说明 |
---|---|
antlr-2.7.6.jar | 语法分析器 |
commons-collections-3.1.jar | 各种集合类和工具类的封装 |
dom4j-1.6.1.jar | XML读写 |
javassist-3.12.0.GA.jar | 分析,编辑和创建Java字节码类库 |
jta-1.1.jar | Java事务Apl |
slf4j-api-1.6.1.jar | 日期输出 |
hibernate-jpa-2.0-api-1.0.1.Final.jar | 提供JPA(Java持久化APl)规范的支持; |
部署至Web项目 lib下…
创建Hibernate 核心配置文件 hibernate.cig.xml
Hibernate 配置文件主要用于配置数据库连接和 Hibernate运行时所需的各种特性。
用于配置数据库连接
运行时所需的各种特性
一般命名为 'hibernate.cfg.xml' (MyElicpse对于创建核心配置文件有自带的DTD文件..)
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<session-factory>
<!-- 加载数据库驱动 -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<!-- 数据库URL -->
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
<!-- 数据库用户 -->
<property name="connection.username">用户名</property>
<!-- 数据库用户密码 -->
<property name="connection.password">密码</property>
<!-- 每一个数据库都有其对应的方言(Dialect),以匹配其平台特性: MySQL Oracle 都遵循SQL语言,总有一些语法不一样 -->
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<!-- 程序运行时输出SQL语句:可以在控制台中看到对应执行的真实SQL如果实在不会写了的话可以来借鉴 -->
<property name="show_sql">true</property>
<!-- 程序运行输出格式化的SQL语句 -->
<property name="format_sql">true</property>
<!-- 可选,指定getCurrentSession(); 得到的Session由谁来管理 thread值由当前线程管理; -->
<property name="current_session_context_class">thread</property>
<!-- 引入所需的映射文件 -->
<mapping resource="com/zb/entity/映射文件.xml"/>
<mapping resource="..." />
</session-factory>
</hibernate-configuration>
<!--
这里使用的是Oracle
oracle.jdbc.driver.OracleDriver Oracle驱动;
jdbc:oracle:thin:@127.0.0.1:1521:全局数据库名 Oracle本地连接URl,orcl是全局数据库名;
current_session_context_class:
可以在多线程的应用环境中获得线程安全Session对象;
每个执行的线程首次调用 getCurrentSession();方法时,会为当前执行线程创建并保持一个线程;
当前线程在次嗲偶 getCurrentSession();会返回该线程当前的Session对象; (保证了每个执行线程都是字节都有的Session对象)
且,当关联的事务结束(提交/回滚),会自动关闭当前执行线程解绑;
-->
创建持久化类 和 映射文件
完成了Hibernate 的核心配置文件, 之后就是要准备 持久化类和映射文件 l
持久化类
就是业务需求中的 实体类;
注意:Hibernate 要求实体类必须有一个无参的构造函数,类实现 Serializable序列化接口;
映射文件
创建持久化类之后, 通过映射文件来告诉 Hibernate该类对应的是数据库这具体的表;
Hibernate 中, 映射文件通常与对应的持久化类同名已 .hbm.xml后缀
xxx.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="持久化类的全限定名" table="对应的数据库表名" >
<!-- 表示数据库与实体类的,主键列对应 -->
<id name="实体类属性名" type="java.lang.Integer" > <!-- 对应Java类型 -->
<column name="数据库主键列名"></column>
<!-- 主键增长的方式 assigned:用户自己填写-->
<generator class="assigned"></generator>
</id>
<property name="Java属性名" type="对应类型" >
<column name="对应数据库列名"></column>
</property>
<!-- 其它元素配置.. -->
</class>
</hibernate-mapping>
<!--
注意:
Java区分大小写,name="Java类名注意大小写" 其实体类存在对应的 get/set(); 可以通过鼠标悬浮Ctrl,验证是否成功!
Hibernate通过 get/set();访问器实现...
generator元素属性:
assigned: 主键由应用程序负责生成,无须hibernate参与,没有指定generator 默认值;
increment: 对应类型为 int short long的主键,已自动增长方式生成主键值 且持续递增每次+1;
identity: 使用数据库自带的主键生成策略来实现...
native: 由hibernate 根据底层数据库自行判断采用何种主键生成策略,即由使用的数据库生成主键的值;
sequence: 对于Oracle DB2 等支持序列的数据库,可以使用其属性;
<generator class="assigned">
<param name="sequence"> 序列名 </param>
</generator>
....还有一些不常用属性..
-->
持久化类 映射文件定义完成之后, 别忘了核心配置文件中 引入:
映射文件;
使用Hibernate 完成持久化操作:
使用Hibernate 操作数据库包括七个步骤:
-
读取并解析配置文件及映射文件
Configuration configuration = new Configuration().configure(“hibernate.cfg.xml”);
// configure() :如果核心配置文件名为hibernate.cfg.xml
可以省略。。。 -
依据配置文件 和映射文件信息, 创建SessionFactory对象;
SessionFactory sessionFactory = configuration.buildSessionFactory();
// configuration对象会根据当前数据库配置信息,构造除一个SessionFactory对象;
// SessionFactory一旦构造完成, configuration就不会在影响 SessionFactory 对象;
// 如果Hibernate 有改动,则需要根据改动后的 configuration 重新构建一个 SessionFactory 对象; -
打开Session
Session session = sessionFactory.openSession();
或
session session = sessionFactory.getCurrentSession();
// Session是Hibernate 持久化操作的基础,提供了众多持久化的操作 :
// save() delete() update() get() load()…等 -
开始一个事务
Transaction tx = session.beginTransaction();
-
数据库操作
… … 增删改查 … … -
结束提交事务
一般是处理异常,根据情况:
tx.commit(); 提交事务或 tx.rollback(); 回滚事务; -
关闭资源
session.close();
// 如果Session是通过 openSession(); 获取的则需要手动关闭资源…
// 如果通过getCurrentSession();获取的 且 核心配置文件中设置了: current_session_context_class 值thread;
// 则会在关联的事务结束后,自动的关闭资源,一般很少使用…
SessionFactory工厂实现获取Session
在项目开发过程中,通常会使用工具类来管理SessionFactory 和 Session的关系…
HibernateUtil.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
//静态属性;
private static SessionFactory factroy;
//静态代码块:类加载给工厂对象赋值;
//类只加载一次,创建的工厂也只有一个!!
static{
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
factroy = configuration.buildSessionFactory();
}
//获取Session
public Session openSession(){
return factroy.openSession();
}
//关闭资源
public void closeSessionn(Session session){
if(session!=null){
session.close();
}
}
}
Hibernate实现增删改查:
为了方便讲解举例这里带上实例代码:
前言
这里使用Oracle数据库来操作,使用 Scott用户 密码是ok;
用户下的 DEPT系统表
-- 建一个和DEPT 结构一样的表:DEPT2
create table dept2
as
select * from dept where 1=2;
select * from dept2
insert into dept2 values(1,'人事','RS');
insert into dept2 values(2,'研发','YF');
insert into dept2 values(3,'技术','JS');
搭建Hibernate框架:
这里没有使用三层…只有Dao 借鉴学习即可…
导入Jar
核心配置文件
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<session-factory>
<!-- 加载数据库驱动 -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<!-- 数据库URL -->
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
<!-- 数据库用户 -->
<property name="connection.username">scott</property>
<!-- 数据库用户密码 -->
<property name="connection.password">ok</property>
<!-- 每一个数据库都有其对应的方言(Dialect),以匹配其平台特性: MySQL Oracle 都遵循SQL语言,总有一些语法不一样 -->
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<!-- 程序运行时输出SQL语句 -->
<property name="show_sql">true</property>
<!-- 程序运行输出格式化的SQL语句 -->
<property name="format_sql">true</property>
<!-- 引入所需的映射文件 -->
<mapping resource="com/wsm/entity/Dept.hbm.xml"/>
</session-factory>
</hibernate-configuration>
数据持久化类 及其 核心配置文件;
Dept.java
数据持久化类
import java.io.Serializable;
//实体类:实现接口Serializable
//这并不是Hibernate所必须的,为了方便用于数据传输等用途时正确的执行序列化操作;
public class Dept implements Serializable {
//必须提供的无参构造
public Dept(){
}
//属性
private Integer deptno;
private String dname;
private String loc;
//get/set
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
//重新toString();
@Override
public String toString() {
return "Dept [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
}
}
Dept.hbm.xml
核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="com.wsm.entity.Dept" table="dept2">
<id name="deptno" type="java.lang.Integer">
<column name="DEPTNO"></column>
<!-- 主键增长的方式 assigned:用户自己填写-->
<generator class="assigned"></generator>
</id>
<property name="dname" type="string">
<column name="DNAME"></column>
</property>
<property name="loc" type="string">
<column name="loc"></column>
</property>
</class>
</hibernate-mapping>
Util工具类
HibernateUtil.java
可以借鉴上面…
增删改查开始…
这里的关键代码写在DeptDao.Java:
import org.hibernate.Session;
import com.wsm.entity.Dept;
import com.wsm.util.HibernateUtil;
public class DeptDao {
//创建hibernateutil 工具对象;
private HibernateUtil hibernateUtil = new HibernateUtil();
}
使用Hibernate实现主键查询
Hibernate提供了两种方法加载对象: get() 和 load()方法;
- Object get( Class clazz, Serializable id );
- Object load( Class clazz, Serializable id );
get();
DeptDao.Java
//根据主键当前对象 get
public Dept selget(Integer id){
//获取Session
Session session = hibernateUtil.openSession();
Dept dept = (Dept) session.get(Dept.class, id); //查询
//关闭资源
hibernateUtil.closeSessionn(session);
return dept;
}
使用Session 的get(); 方法根据主键查询数据时, 如果数据库中没有对应数据;
get(); 方法返回结果为 null;
load();
DeptDao.Java
//根据主键当前对象 load
public Dept selload(Integer id){
Session session = hibernateUtil.openSession();
Dept dept = (Dept) session.load(Dept.class, id);
//关闭资源
//hibernateUtil.closeSessionn(session); 注释了关闭资源...
return dept;
}
可以看到使用 load(); 方法和get() 几乎相同;
唯一不同: 注释了关闭资源… 因为load()方法访问数据库, 属于的是懒加载机制 ;
即: 用的时候才做查询…如果不用则不做…而提前关闭了资源. 无法完成数据库交互查询…所以不可以关闭资源…
且 如果数据表中不存在对应数据, 会抛出异常!!
使用Hibernate实现数据库 增删改;
增 save();
Test.java
// 原生新增:增一条Dept
public void save(){
Dept dept = new Dept();
dept.setDeptno(4);
dept.setDname("运维");
dept.setLoc("YW");
// 读取并解析配置文件及映射文件
Configuration configuration = new Configuration().configure(); // "hibernate.cfg.xml"
// 核心配置文件名为,可以不参数指定;
// 依据配置文件 和映射文件信息, 创建SessionFactory对象;
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 打开Session
Session session = sessionFactory.openSession();
// 开始一个事务
Transaction tx = session.beginTransaction();
try {
// 数据库操作: 新增save();
session.save(dept); // ALT+SHift+z 快速给选中行添加try-catch...
tx.commit();
System.out.println("新增成功"); // 提示新增成功;
} catch (HibernateException e) {
// 回滚事务;
tx.rollback();
}
// 关闭资源
session.close();
}
save(Object);
数传入 操作表对应的 实体类对象;
根据对象的属性值, 进行对应的新增…
删 delete();
DeptDao.java
//删除:参数要删除的数据; Hibernate是以面向对象方式实现的 数据持久化...
public void deleteDept(Integer id){
Session session = hibernateUtil.openSession();
Transaction tx = session.beginTransaction();
Dept dept = new Dept();
dept.setDeptno(id);
try {
session.delete(dept); //封装对象数据,要删除的id;
tx.commit(); //成功提交事务
System.out.println("删除成功!");
} catch (HibernateException e) {
tx.rollback(); //失败回滚;
System.out.println("删除失败!");
}
//关闭资源;
hibernateUtil.closeSessionn(session);
}
.delete(Object);
参数传入 操作表对应的 实体类对象;
给对象属性赋值, Hibernate底层自动生成SQL语句; 属性作为删除的条件…进行删除;
改(两种) update(Object) / Setxx(xx) ;
update(Object)
DeptDao.java
//session.update(Object);
//修改1 根据传入的dept来进行修改;
public void updateDept(Dept dept){
Session session = hibernateUtil.openSession();
Transaction tx = session.beginTransaction();
try {
session.update(dept);
tx.commit();
System.out.println("修改成功");
} catch (HibernateException e) {
tx.rollback();
System.out.println("修改失败");
}
hibernateUtil.closeSessionn(session);
}
session.update(Object);
注意: 传入参数(对应持久类的对象) ,其主键属性必须需要赋值, 不然执行不成功!!
Setxx(xx);
DeptDao.java
//修改2 使用Setxx() 进行修改
public void setDept(Integer id){
System.out.println("三态修改...");
Session session = hibernateUtil.openSession();
Transaction tx = session.beginTransaction();
Dept dept = (Dept)session.load(Dept.class,id);
//根据三态原则进行修改;
try {
dept.setDname("修改");
tx.commit();
System.out.println("修改成功");
} catch (Exception e) {
tx.rollback();
System.out.println("修改失败");
}
hibernateUtil.closeSessionn(session);
}
三态进行修改Setxx(xx)
使用该方法修改数据时, 首先要加载对象, 然后通过修改对象的属性。最后提交事务;
Hibernate 会生成并执行修改SQL语句; (Hibernate三态原则)
Hibernate中Java对象的三种状态(三态)
瞬时状态
瞬时状态又称临时状态:
Java对象与数据库中的数据, 没有任何的关联; (此时的Java对象状态为瞬时状态)
Session 对于瞬时状态的Java对象是一无所知的, 当Java对象不在被其它对象引用时, 被虚拟机回收~
持久状态
当Java对象与Session关联时,就处于持久状态(该状态下的对象, 同时对应着数据库中的一条记录)
处于持久状态的Java对象, Session会持续跟踪和管理它们, 如果对象的内部结构发生了任何改变;
Hibernate 会选择合适的时机(事务提交~), 将对象的变更与数据库实时同步~ 着就是Setxx(); 之所以可以完成修改的原因!!
游离状态
游离状态:又称托管状态, Session放弃或不足管理Java对象, 此时的对象处于了游离状态;
没有了Session的跟踪监视管理, 此时调用Setxx(); 就不会自动同步修改数据了…
三种状态之间的转换
瞬时——持久
执行Session的 save() saveOrUpdate() 等方法保存对象时候,该对象有瞬时状态转换为持久状态;
执行Session 的 get() load() 方法获取对象, 该对象就处于持久状态;
持久——瞬时
执行Session 的 delete() 方法持久状态的对象转换为瞬时状态
持久——游离
执行Session调用 evict() clear() close() 对象有原来的持久转换为游离状态;
游离——持久
执行Session 的update() saveOrupdate() 方法, 对象由游离状态转换为持久
游离——瞬时
执行Session的 delete() 对象由游离转换为瞬时…
脏检查 与 刷新缓存机制
脏检查
Hibernate 中, 数据前后发生变化的对象, 称为脏对象;
当一个 Java对象被Session管理时候, Hibernate会对对象进行检测保存;
以判断对象属性,是否发生变化, 这种判断称为脏检测
如果对象发生改变,Session会根据脏对象的值进行比较, 将最新数据存储到数据库中…
刷新缓存机制
Session中的对象属性发生改变时,Session并不会立即执行脏检查相关的SQL语句; 而是在特定的时间(刷新缓存时执行)
优点
当对象属性进行多次更改,而Hibernate不会每次都进行匹配修改 ,而是在最后一次执行一次SQL进行数据匹配;
提高应用程序的数据访问性能;
Session.flush() 和 事务提交可以立即执行脏检查进行数据校验!!
Session的其它方法
saveOrUpdate()
saveorUpdate(Objext) 同时包含了 save() 和 Update() 功能, 如果入参对象是瞬时状态就新增,游离状态就修改;
即: 如果数据库中存在对应的数据, 修改 | 新增;