一、搭建Hibernate环境
1、Hibernate框架简介
-
Hibernate是数据持久化工具,也是一个开放源代码的ORM解决方案。Hibernate内部封装了通过JDBC访问数据库的操作,向上层应用提供面向对象的数据访问API。
-
Hibernate是ORM解决方案 :基于ORM,Hibernate在对象模型和关系数据库的表之间建立了一座桥梁。通过Hibernate,程序员就不需要再使用sql语句操作数据库中的表,而是使用API直接操作JavaBean对象就可以实现数据的存储、查询、更改和删除等操作,显著降低了由于对象与关系数据库在数据表现方面的范例不匹配而导致的开发成本。
2、为什么选择Hibernate框架
(1)Hibernate优点:
-
Hibernate功能强大,是Java应用于关系数据库之间的桥梁,较之JDBC方式操作数据库,代码量大大减少,提高了持久化代码的开发速度,降低了维护成本。
-
Hibernate支持许多面向对象的特性,如组合、继承、多态等,使得开发人员不必在面向业务领域的对象模型和面向数据库的关系数据模型之间来回切换,方便开发人员进行领域驱动的面向对象的设计与开发。
-
可移植性好。系统不会绑定在某个特定的关系型数据库上,对于系统更换数据库,通常只需要修改Hibernate配置文件即可正常运行。
-
Hibernate框架开源免费,可以在需要时研究源代码,改写源代码,进行功能的定制,具有可扩展性。
(2)Hibernate缺点:
- 不适合以数据为中心大量使用存储过程的应用。
- 大规模的批量插入、修改和删除不适合使用Hibernate。
3、Hibernate与MyBatis的对比
Hibernate与MyBatis都属于ORM框架,为数据层提供持久化操作的支持。
区别如下:
-
(1)相对于MyBatis的" SQL-Mapping" 的ORM实现,Hibernate的ORM实现更加完善,提供了对象状态管理的功能。Hibernate对数据操作,针对的是Java对象,即使使用Hibernate的查询语言(HQL语句),其书写规则也是面向对象的。
-
(2)Hibernate与具体数据库的关联只需要在XML中配置即可,Hibernate开发者不需要关注SQL的生成与结果的映射,所有的HQL语句与具体使用的数据库无关,便于修改,可移植性好。而MyBatis直接使用sql语句,不同数据库之间可能会有差异,修改工作量大,可移植性差。
-
(3)由于直接使用sql语句,因此MyBatis的使用灵活性更高,而Hibernate对于关系模型设计不合理、不规范的系统则不适用。在不考虑缓存的情况下,MyBatis的执行效率也比Hibernate高一些。
4、搭建Hibernate环境
(1)下载jar文件
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事务API
- slf4j-api-1.6.1.jar 日志输出
- hibernate-jpa-2.0-api-1.0.0.Final.jar 提供对JPA(Java持久化API)规范的支持
(2)部署jar文件
在项目中引用下载好的hibernate3.jar、lib\required、lib\jpa目录下的jar文件及
Oracle数据库驱动jar文件。
(3)创建Hibernate配置文件 hibernate.cfg.xml
Hibernate配置文件主要用于配置数据库连接和Hibernate运行时所需的各种特性。
在工程的src目录下添加Hibernate配置文件(可在project\etc目录下找到示例文件),默认文件名为“hibernate.cfg.xml”。该文件需要配置数据库连接信息和Hibernate的参数。
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>
<!--数据库url-->
<property name="connection.url">
jdbc:oracle:thin@localhost:1521:orcl
</property>
<!--数据库用户-->
<property name="connection.username">scott</property>
<!--数据库用户密码-->
<property name="connection.password">123456</property>
<!--数据库JDBC驱动-->
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<!--每个数据库都有其对应的方言(Dialect)以匹配其平台特性-->
<property name="dialect">
org.hibernate.dialect.Oracle10gDialect
</property>
<!--指定当前session范围和上下文-->
<property name="current_session_context_class">
thread
</property>
<!--是否将运行期生成的sql输出到日志以供调试-->
<property name="show_sql">true</property>
<!--是否格式化sql-->
<property name="format_sql">true</property>
</session-factory>
</hibernate-configuration>
说明:
-
connection.url:表示数据库url。jdbc:oracle:thin@localhost:1521:orcl是Oracle数据库的URL。其中jdbc:oracle:thin@是固定写法,localhost是IP地址,1521是端口号,orcl是数据库实例名。
-
connection.username:表示数据库用户名
-
connection.password:表示数据库用户密码
-
connection.driver_class:表示数据库驱动。
oracle.jdbc.driver.OracleDriver是Oracle数据库的驱动类。 -
dialect:用于配置Hibernate使用的数据库类型。Hibernate支持几乎所有的主流数据库,包括Oracle、DB2、MS SQL Server和MySql等。org.hibernate.dialect.Oracle10gDialect指定当前数据库类型是Oracle 10g 及以上版本。
-
current_session_context_class:指定
org.hibernate.context.CurrentSessionContet.currentSession() 方法的Session由谁来跟踪管理。thread指定Session由当前执行的线程来跟踪管理。 -
show_sql:如果设置为true,则程序运行时在控制台输出sql语句。
-
format_sql:如果设置为true,则程序运行时在控制台输出格式化后的SQL语句。
注: 因为Hibernate的配置属性较多,可在hibernate-jpa-2.0-api-1.0.0.Final.jar的
documentation\manual\z-CN\pdf 目录中查看hibernate_reference.pdf的第3章3.4节了解可选的配置属性。
(4)创建持久化类和映射文件
持久化类是指其 实例状态需要被Hibernate持久化到数据库中的类。
在应用的设计中,持久化类通常对应需求中的业务实体。为了在将持久化类用于数据传输等用途时能够对其实例正确执行序列化操作,建议实现java.io.Serializable接口。
创建持久化类:Dept.java
package cn.demo.po;
import java.io.Serializable;
/**
* 部门表
*/
public class Dept implements Serializable {
/**
* 部门编号
*/
private Integer deptNo;
/**
* 部门名称
*/
private String dName;
/**
* 部门地区
*/
private String loc;
//省略getter/setter
}
注: Dept持久化类deptNo属性,用来唯一标识Dept类的每个实例。deptNo属性又称为id属性。在Hibernate中,这个ID属性被称为对象标识符,一个Dept实例和Dept表中的一条记录对应。
创建映射文件: 告诉“Hibernate”,持久化类Dept映射到数据库的哪个表,以及哪个属性对应到数据库表的哪个字段。
注: 在Hibernate中,映射文件通常与对应的持久化类同名,并以“.hbm.xml”作为后缀。
Dept.hbm.xml如下
<!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="cn.demo.po.Dept" table="DEPT">
<id name="deptNo" type="java.lang.Integer" column="DEPTNO">
<generator class="assigned"/>
</id>
<property name="dName" type="java.lang.String" column="DNAME"/>
<property name="loc" type="java.lang.String">
<column name="LOC"></column>
</property>
</class>
</hibernate-mapping>
说明:
-
class元素:定义一个持久化类的映射信息。常用属性如下:
name:表示持久化类的全限定名
table:表示持久化类对应的数据库表名
dynamic-update="true"属性:作用是只修改发生变化的属性。 -
id元素:表示持久化类的OID和表的主键的映射。常用属性如下:
name:表示持久化类属性的名称,和属性的访问器相匹配
type:表示持久化类属性的类型
column:表示持久化类属性对应的数据库表字段的名称,也可在子元素column中指定。 -
generator元素:id元素的子元素,用于指定主键的生成策略。常用属性及子元素如下:
class属性:用来指定具体主键生成策略
param元素:用来传递参数。 -
常用的主键生成策略如下:
-
property元素:定义持久化类中的属性和数据库表中的字段的对应关系。常用属性如下:
name:表示持久化类属性的名称,和属性的访问器相匹配。
type:表示持久化类属性的类型
column:表示持久化类属性对应的数据库表字段的名称,也可在子元素column中指定。 -
column元素: 用于指定其父元素代表的持久化类属性所对应的数据库表中的字段。常用属性如下:
name:表示字段的名称
length:表示字段的长度
not-null:设定是否不能为null,设置为true表示为不能为null
映射文件定义完毕,还需要在配置文件hibernate.cfg.xml中声明
<hibernate-configuration>
<session-factory>
<!--省略其他配置-->
<!--映射文件配置,注意文件名必须包含其相对于classpath的全路径-->
<mapping resource="cn/demo/dao/Dept.hbm.xml"/>
</session-factory>
</hibernate-configuration>
二、使用Hibernate API实现持久化操作
使用Hibernate操作数据库包括7个步骤:使用Hibernate操作数据库包括7个步骤:
- (1)读取并解析配置文件及映射文件
Configuration conf=new Configuration().configure();
根据默认位置的Hibernate配置文件中的信息,构建Configuration对象。
Configuration对象负责管理Hibernate的配置信息。
- (2)依据配置文件和映射文件中的信息,创建Sessionfactory对象
SessionFactory sf=conf.buildSessionFactory();
Configuration对象会根据当前的数据库配置信息,构造SessionFactory对象。SessionFactory对象一旦构造完毕,Configuration对象的任何变更将不会影响已经创建的SessionFactory对象。若Hibernate配置信息有改动,那么需要基于改动后的Configuration对象重新创建一个SessionFactory对象。
(3)打开Session
Session session=sf.getCurrentSession(); //或者使用sf.openSession();
SessionFactory对象负责创建Session对象。
Session是Hibernate持久化操作的基础。Session作为贯穿Hibernate的持久化管理器的核心,提供了众多持久化方法,如save()、delete()、update()、 get()、 load()等。
(4)开始一个事务
Transaction tx=session.beginTransaction();
(5)数据库操作
session.save(user); //保存操作
(6)结束事务
tx.commit(); //提交事务
或
tx.rollback(); //回滚事务
(7)如果是通过SessionFactory的openSession()方法获取的Session对象,则需关闭session。
session.close();
注: 若在Hibernate配置文件中将参数current_session_context_class设置为thread,并采用SessionFactory的getCurrentSession()方法获得Session对象,则不需要执行session.close()方法,因为通过这种方式获得的Session对象,会在关联的事务结束(提交或回滚)时自动关闭。
补充: 在项目开发过程中,通常使用工具类来管理SessionFactory 和Session,下面创建HibernateUtil.java。
/**
* 工具类:管理SessionFactory和Session
*/
public class HibernateUtil {
private static Configuration configuration;
private final static SessionFactory sessionFactory;
//初始化Configuration和SessionFactory
static{
try{
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}catch(HibernateException ex) {
throw new ExceptionInInitializerError(ex);
}
}
//获取session对象
public static Session currentSession(){
return sessionFactory.getCurrentSession();
}
}
说明:在此工具类中,采用SessionFactory的getCurrentSession()方法获取Session对象,结合Hibernate配置文件中的以下配置:
<property name="current_session_context_class">thread</property>
可以在多线程的应用环境中获得线程安全的Session对象,在多线程情况下共享Session是不安全的,通过以上配置,在每个执行的线程中首次调用getCurrentSession()方法时,会为该执行线程创建并保持一个Session对象。其后,该线程在执行中再次调用getCurrentSession()方法,只会返回和该线程绑定的那个Session对象,这就保证了每个执行线程都使用自己独立的Session对象。
1、根据主键查询
Hibernate提供了两种方法根据主键加载对象:get()和load()
- Object get(Class clazz,Serializable id);
- Object loas(Class clazz,Serializable id);
例:
public class DeptDao {
/**
* 根据id获取Dept对象:使用session.get()方式
* 此种方式若数据表中没有匹配的数据,则返回null
* @param id
* @return
*/
public Dept get(Serializable id){
//通过Session的get()方法根据OID加载指定对象
return (Dept) HibernateUtil.currentSession().get(Dept.class,id);
}
/**
* 根据id获取Dept对象:使用session.load()方式
* @param id
* @return
*/
public Dept load(Serializable id){
//通过Session的get()方法根据OID加载指定对象
return (Dept) HibernateUtil.currentSession().load(Dept.class,id);
}
}
get()方法与load()方法区别:
- 当使用Session的get()方法时,如果加载的数据不存在,则get()方法会返回null。
- 当使用load()方法,若加载的数据不存在,则会抛出异常。
业务层DeptBiz.java代码如下:
package cn.demo.service;
import cn.demo.dao.dept.DeptDao;
import cn.demo.po.Dept;
import cn.demo.utils.HibernateUtil;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Transaction;
import java.util.List;
public class DeptBiz {
private DeptDao deptDao=new DeptDao();
/**
* 根据id获取指定部门
* @param id
* @return
*/
public Dept findDeptById(Integer id){
Transaction tx=null;
Dept result=null;
try{
tx= HibernateUtil.currentSession().beginTransaction(); //开启事务
result=deptDao.get(id); //调用dao方法,根据OID加载指定Dept对象
//result=deptDao.load(id); //调用dao方法,根据OID加载指定Dept对象
//输出结果,与调用get()时不同,需在会话关闭前测试查询结果
System.out.println(result.getdName()+"----->deptName");
tx.commit();
}catch (HibernateException e){
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}
return result;
}
}
测试类
package cn.demo.test.dept;
import cn.demo.po.Dept;
import cn.demo.po.Emp;
import cn.demo.service.DeptBiz;
import org.junit.Test;
import java.util.List;
public class DeptTest {
/**
* 测试获取Dept对象
*/
@Test
public void test1(){
//1.加载数据操作
Dept dept=new DeptBiz().findDeptById(10);
//2.输出数据
System.out.println(dept.getdName());
}
}
运行结果
补充:为了简化编码,再定义一个基类BaseDao,对获取Session的方法进行封装,在此基础上,让所有的Dao类继承BaseDao。
public class BaseDao {
/**
* 获取Session对象
* @return
*/
public Session currentSession(){
return HibernateUtil.currentSession();
}
}
2、使用Hibernate实现CRUD
- demo1:使用Hibernate实现增加部门记录
DeptDao.java
public class DeptDao extends BaseDao{
/**
* 新增部门信息
* @param dept
*/
public void save(Dept dept){
currentSession().save(dept); //保存指定的Dept对象
}
}
DeptBiz.java
public class DeptBiz{
private DeptDao deptDao=new DeptDao();
/**
* 新增部门
* @param dept
*/
public void addNewDept(Dept dept){
Transaction tx=null;
try {
tx=deptDao.currentSession().beginTransaction(); //开启事务
deptDao.save(dept);
tx.commit();
}catch (HibernateException e){
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}
}
}
测试类
/**
* 测试新增
*/
@Test
public void Test2(){
Dept dept=new Dept();
dept.setDeptNo(11);
dept.setdName("质管部");
dept.setLoc("西区");
//保存新部门信息
new DeptBiz().addNewDept(dept);
}
执行结果:
- demo2:使用Hibernate实现部门的修改和删除
对于Hibernate这种ORM工具,操作都是针对对象的。要修改和删除数据,首先要获得数据,然后才能进行修改和删除操作。
DeptDao.java
public class DeptDao extends BaseDao{
/**
* 根据id获取Dept对象:使用session.load()方式
* 若没有获取到数据,则会报异常
* @param id
* @return
*/
public Dept load(Serializable id){
//通过Session的get()方法根据OID加载指定对象
return (Dept)currentSession().load(Dept.class,id);
}
}
DeptBiz.java
public class DeptBiz{
private DeptDao deptDao=new DeptDao();
/**
* 修改部门信息
* @param dept 修改后的部门信息
*/
public void updateDept(Dept dept){
Transaction tx=null;
try {
tx=deptDao.currentSession().beginTransaction(); //开启事务
//通过get()或load()方法加载要修改的部门对象
Dept deptToUpdate=deptDao.load(dept.getDeptNo());
//更新部门数据
deptToUpdate.setdName(dept.getdName()); //修改部门名称
deptToUpdate.setLoc(dept.getLoc()); //修改地区
tx.commit();
}catch (HibernateException e){
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}
}
}
测试类:
/**
* 更新部门信息
*/
@Test
public void test3(){
Dept dept=new Dept();
dept.setDeptNo(11);
dept.setdName("质管部");
dept.setLoc("东区");
//更新部门信息
new DeptBiz().updateDept(dept);
}
测试结果:
- demo3:实现删除部门
DeptDao.java
public class DeptDao extends BaseDao {
/**
* 删除部门
* @param dept
*/
public void delete(Dept dept){
currentSession().delete(dept); //删除指定的Dept对象
}
}
DeptBiz.java
public class DeptBiz {
private DeptDao deptDao=new DeptDao();
/**
* 删除部门
* @param id
*/
public void deleteDept(Integer id){
Transaction tx=null;
try {
tx=deptDao.currentSession().beginTransaction(); //开启事务
//通过get()或load()方法加载要修改的部门对象
Dept deptToDelete=deptDao.load(id);
deptDao.delete(deptToDelete); //删除部门数据
tx.commit();
}catch (HibernateException e){
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}
}
}
测试类
/**
* 测试删除部门
*/
@Test
public void test4(){
new DeptBiz().deleteDept(11);
}
运行结果:
三、Hibernate中Java对象的生命周期
1、Hibernate中持久化对象的生命周期
Hibernate框架通过Session来管理Java对象的状态,在持久化生命周期中,Java对象存在以下3种状态:
(1)瞬时状态 Transient
瞬时状态又称临时状态。如果Java对象与数据库中的数据没有任何的关联,即此Java对象在数据库中没有相关联的记录,此时Java对象的状态为瞬时状态。Session对瞬时状态的Java对象是一无所知的,当对象不再被其他对象引用时,它的所有数据也就丢失了,对象将会被Java虚拟机按照垃圾回收机制处理。
(2)持久状态 Persistent
当对象与Session关联,被Session管理时,它就处于持久状态。处于持久状态的对象拥有数据库标识(数据库中的主键值)。对象在与Session发生关联的情况分为2种:第一种情况,通过Session的查询接口、get()或load()方法从数据库中加载对象时,加载的对象是与数据库表中的一条记录关联的,此时对象与加载它的Session发生关联。第二种情况,对瞬时状态的对象调用Session的save()、saveOrUpdate()等方法时,在保存对象数据的同时,Java对象也会与Session发生关联。对于处于持久状态的对象,Session会持续跟踪和管理他们,如果对象的内部状态发生了任何变更,Hibernate会选择合适的时机(如事务提交时)将变更同步到数据库中。
(3)游离状态 Detached
游离状态又称脱管状态。处于持久状态的对象,脱离与其关联的Session管理后,就处于游离状态。处于游离状态的对象,Hibernate无法保证对象所包含的数据与数据库中的记录一致,因为Hibernate已经无法感知对该对象的任何操作。Session提供了update()、saveOrUpdate()等方法,将处于游离状态的对象的数据以更新的方式同步到数据库中,并将该对象与当前的Session关联。这时,对象的状态就从游离状态重新转换为持久状态。
2、使用Hibernate API转换对象的状态
(1)瞬时状态转为持久状态
创建一个部门对象,此时该对象与数据库中的数据没有任何关联,所以处于瞬时状态,当调用Session的save()、saveOrUpdate()等方法保存对象后,该对象即由瞬时状态转换为持久状态。
Dept dept=new Dept();
//赋值
dept.setDeptNo(1);
dept.setDName("财务部");
dept.setLoc("china");
使用Session的get()、 load() 方法获取对象,该对象的状态是持久状态。
(2)持久状态转为瞬时状态
执行Session的delete()方法后,对象由原来的持久状态变为瞬时状态,因为此时该对象没有与任何的数据库数据关联。
(3)持久状态转游离状态
执行Session的evict()、clear()或close()方法,对象由原来的持久状态转为游离状态。
- Session.evict():会把指定的缓冲对象进行清除。
- Session.clear():把缓冲区内的全部对象清除,但不包括操作中的对象。
(4)游离状态转持久状态
执行Session的update()或saveOrUpdate()方法后,对象由游离状态转为持久状态,再次与当前Session相关联。
例:
//根据部门编号获取部门对象
Dept dept=deptDao.load(dept.getDeptNo);
//对该部门对象进行更新操作
dept.setDName("财务部02");
dept.setLoc("China");
(5)游离状态转瞬时状态
执行Session的delete()方法,对象由游离状态转为瞬时状态。
注: 处于瞬时状态或游离状态的对象不再被其他对象引用时,会被Java虚拟机按照垃圾回收机制处理。
四、Hibernate脏检查及如何刷新缓存
1、什么是脏检查
在Hibernate中,数据前后发生变化的对象,称为脏对象。
例:
tx=session.beginTransaction();
//获取部门对象,dept对象处于持久状态
Dept dept=(Dept)session.load(Dept.class,10);
//修改后,部门信息和之前不同,此时dept对象称为所谓的“脏对象"
dept.setDName("质管部");
//提交事务
tx.commit();
说明:
以上代码中dept对象处于持久状态,当dept对象被加入Session缓存中时,Session会为dept对象的值类型的属性复制一份快照。操作中,dname属性发生改变,dept对象即成为脏对象。在事务提交时,Hibernate会对Session中持久状态的对象进行检测,即比较dept对象的当前属性与它的快照,以判断dept对象的属性是否发生了变化,这种判断成为脏检查。如果对象发生了改变,则Session会根据脏对象的最新属性值来执行相关的sql语句,将变化更新到数据库,以确保内存中的对象数据与数据库中的数据一致。
2、什么是刷新缓存
Session是Hibernate向应用程序提供的持久化操纵的主要接口,它提供了基本的保存、更新、删除和加载Java对象的方法。Session具有一个缓存,可以管理和跟踪所有持久化对象。在某些时间点,Session会根据缓存中对象的变化来执行相关sql语句,将对象发生的变化同步到数据库中,换句话就是将数据库同步为与Session缓存一致,这一过程称为刷新缓存。
3、Session如何刷新缓存
当Session缓存中对象的属性发生变化时,Session并不会立即执行脏检查和执行相关的sql语句,而是在特定的时间点,即刷新缓存时才执行。这使得Session能够把多次变化合并为一条或者一批sql语句,减少了访问数据库的次数,从而提高了应用程序的数据访问性能。在默认情况下,Session会在以下时间点刷新缓存:
-
(1)应用程序显式调用Session的flush()方法时。
Session的flush()方法进行刷新缓存的操作,会触发脏检查,视情况执行相关的sql语句。
-
(2)应用程序调用Transaction的commit()方法时。
commit()方法会先调用Session的刷新缓存方法flush(),然后向数据库提交事务。在提交事务时执行刷新缓存的动作,可以减少访问数据库的频率,尽可能缩短当前事务对数据库中相关资源的锁定时间。
五、使用Hibernate API 更新数据
Hibernate中的Session提供了多种更新数据的方法,如Update()、saveOrUpdate()、merge()方法。
-
(1)update()方法
用于将游离状态的对象恢复为持久状态,同时进行数据库更新操作。
当参数对象的OID为null时会报异常。 -
(2)saveOrrUpdate()方法
同时包含了save()与update()方法的功能,如果传入参数是瞬时状态的对象,就调用save();如果传入参数是游离状态的对象,则调用update()方法。 -
(3)merge()方法
能够把作为参数传入的游离状态对象的属性复制到一个拥有相同的OID的持久状态对象中,通过对持久状态对象的脏检查实现更新操作,并返回该持久状态对象;如果无法从Session缓存或数据库中加载到相应的持久状态对象,即传入的是瞬时对象,则创建其副本执行插入操作,并返回这一新的持久状态对象。无论何种情况,传入对象的状态都不受影响。
demo4:演示使用merge()方法进行修改操作
Dept.hbm.xml文件
<!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="cn.bdqn.po.Dept" table="DEPT" schema="scott" dynamic-update="true">
<id name="deptNo" type="java.lang.Integer" column="DEPTNO">
<!--为了避免主键生成器assigned造成的干扰,把主键生成器 替换为increment-->
<generator class="increment"/>
</id>
<property name="dName" type="java.lang.String" column="DNAME"/>
<property name="loc" type="java.lang.String">
<column name="LOC"></column>
</property>
</class>
</hibernate-mapping>
DeptDao.java
/***
* 使用Hibernate API merge()方法实现更新操作
* @param dept
* @return
*/
public Dept merge(Dept dept){
return (Dept)currentSession().merge(dept);
}
DeptBiz.java
/**
* 调用merge()修改部门信息
* @param dept
* @return
*/
public Dept mergeDept(Dept dept){
Transaction tx=null;
Dept persistentDept=null; //持久化Dept对象
try{
tx=deptDao.currentSession().beginTransaction(); //开启事务
persistentDept=deptDao.merge(dept);
tx.commit();
}catch (HibernateException e){
e.printStackTrace();
if(tx!=null){
tx.rollback();
}
}
return persistentDept;
}
测试类:
/**
* 调用merge()方法进行更新操作
*/
@Test
public void test5(){
Dept dept=new Dept();
//dept.setDeptNo(11); //游离状态,去调本行代码则为临时状态
dept.setdName("开发部1");
dept.setLoc("西区");
//合并游离状态dept的数据或者保存临时状态的dept的副本
new DeptBiz().mergeDept(dept);
}
小结:如果当前Session缓存中没有包含具有相同的OID的持久化对象,可以使用update()或saveOrUpdate()方法;若想随时合并对象的修改而不考虑Session缓存中对象的状态,可以使用merge()方法。
关注一下吧~【Pretty Kathy】