首页 > WORK > Hibernate数据访问层开发简介

Hibernate数据访问层开发简介

版权声明:本文可以任意转载,转载时请务必以超链接形式标明文章原始出处作者署名本版权声明

1. 环境准备

1.1 下载开发工具

下载Jdk1.4.2、Eclipse with WTP3.2、hibernate-synchronizer-3.1.1插件、Tomcat5.0。

1.2 开发环境准备

下载下来后,本机要做的是先配置JAVA的环境变量,参考:JDK1.4安装与环境配置完全图解(Windows版)

1.3 Hibernate插件的配置

解压hibernate-synchronizer-3.1.1插件,将其中的plugins目录和features目录copy到Eclipse的这两个目录中直接覆盖,完成该插件的安装。

也可以采用links方式安装,参考:第一个Eclipse程序完全图解

插件安装完成后,可在Eclipse项目属性中看见“Hibernate Synchronizer”这项,需要在其中进行配置,包括PO和DAO的生成,注意其中的Package选项,表示生成文件的路径,不要选错。

synchronizer.jpg

1.4 Tomcat的使用

Tomcat是JSP/Servlet容器,RobConsole项目在开发模式下是运行在其中的,Tomcat的优势在于轻便,直接解压即可使用。

标注:RobConsole项目在开发模式下运行于Tomcat中,生产模式下运行于WebLogic中。

tomcat.jpg

按照上图在Eclipse中进行Tomcat开发环境的注册,这样就可以在Eclipse中启停它了。

标注:在Eclipse中加入View:Servers,可以观察Tomcat信息。

1.5 从CVS中取得RobConsole库

切换到CVS Repositories视图,从192.1.1.163:/var/cvsroot检出RobConsole库,

标注:采用pserver方式连接;用户名/密码:rob/rob

全部的开发工作都在该库中进行,开发所需要的包如Struts、Spring、Hibernate等都在WEB-INF/lib目录下。

2. 开发流程

2.1 生成数据库表

简单起见,下面仅以一张表next_id为例进行说明:

建表语句:

drop table if exists next_id;

create table next_id
(id_cd char(2) not null default ‘US’,
sub_key_cd char(20) not null,
id_desc_tx char(20) not null,
id_len_qt int(2) default ‘15′ not null,
next_id char(20) default ‘0000000000′ not null,
last_upd_opr_id char(10) not null,
last_upd_txn_id char(10) not null,
last_upd_ts date not null
);

create unique index UK_IC on next_id(id_cd);

2.2 生成hbm.xml文件

通过hibernate-synchronizer插件新建Hibernate Mapping File,在右键弹出的hibernate-synchronizer选项卡中输入:

Driver:输入oracle.jdbc.driver.OracleDriver
Database URL:输入数据库地址
Username:输入用户名
Password:输入密码
Tables:选择需要映射的表,这里可以加入过滤器
Package:输入po文件存放的路径

生成的NextID.hbm.xml文件内容为:
<?xml version=”1.0″?>
<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD//EN”
“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd” >
<hibernate-mapping package=”com.robertbao.po”>
//这里是进行表映射
<class name=”NextId” table=”next_id”>
//这里是进行主键映射
<id name=”IdCd” type=”string” column=”id_cd”>
<generator class=”assigned” />
</id>
//这里是进行属性映射
<property name=”SubKeyCd” column=”sub_key_cd” type=”string”
not-null=”true” length=”20″ />
<property name=”IdDescTx” column=”id_desc_tx” type=”string”
not-null=”true” length=”20″ />
<property name=”IdLenQt” column=”id_len_qt” type=”integer”
not-null=”true” length=”2″ />
<property name=”NextId” column=”next_id” type=”string”
not-null=”true” length=”20″ />
<property name=”LastUpdOprId” column=”last_upd_opr_id”
type=”string” not-null=”true” length=”10″ />
<property name=”LastUpdTxnId” column=”last_upd_txn_id”
type=”string” not-null=”true” length=”10″ />
<property name=”LastUpdTs” column=”last_upd_ts” type=”date”
not-null=”true” length=”10″ />
</class>
//可在其中通过SQL语句定义查询,该部分为可选,视开发需求而定
<query name=”NextIdIC_SKC”>
<![CDATA[
from NextId as nextid where nextid.IdCd = :IdCd and nextid.SubKeyCd = :SubKeyCd ]]>
</query>
</hibernate-mapping>

标注:

1、单主键可通过工具自动生成,但复合主键的情况需要手工修改代码;

2、该插件的当前版本有bug,有可能生成的hbm缺少一些项,PO缺少一些初始化的定义,有可能需要手工查错。

2.3 生成PO和DAO

通过Hibernate synchronizer工具进行O/R Mapping映射,选中hbm.xml文件,右键点击”Synchronize Files”进行代码生成。

hbm.jpg

生成数据库表对应的PO,PO与数据库表一一对应:

package com.robertbao.po;

import com.robertbao.po.base.BaseNextId;

public class NextId extends BaseNextId {
private static final long serialVersionUID = 1L;
/*[CONSTRUCTOR MARKER BEGIN]*/
public NextId () {
super();
}
/**
* Constructor for primary key
*/
public NextId (java.lang.String idCd) {
super(idCd);
}
/**
* Constructor for required fields
*/
public NextId (
java.lang.String idCd,
java.lang.String subKeyCd,
java.lang.String idDescTx,
java.lang.Integer idLenQt,
java.lang.String nextId,
java.lang.String lastUpdOprId,
java.lang.String lastUpdTxnId,
java.util.Date lastUpdTs) {
super (
idCd,
subKeyCd,
idDescTx,
idLenQt,
nextId,
lastUpdOprId,
lastUpdTxnId,
lastUpdTs);
}
/*[CONSTRUCTOR MARKER END]*/
}

并且自动生成对应的DAO:

package com.robertbao.dao;

import com.robertbao.dao.base.BaseNextIdDAO;

public class NextIdDAO extends BaseNextIdDAO implements INextIdDAO {

/**
* Default constructor. Can be used in place of getInstance()
*/
public NextIdDAO () {}
}

在NextIdDAO的基类BaseNextIdDAO和_BaseRootDAO中,基本的CRUD方法已经建立,可以在BO单元中写交易时直接调用。

其中的主要方法包括:

//通过HQL语句进行查询
public List find(String query) {
return getHibernateTemplate().find(query);
}
//通过hbm.xml中的语句名进行查询
public List findByNamedQuery(String name) {
return getHibernateTemplate().findByNamedQuery(name);
}
//保存对象到数据库
protected Serializable save(Object obj) {
return getHibernateTemplate().save(obj);
}
//删除数据库中的记录
protected void delete(Object obj) {
getHibernateTemplate().delete(obj);
}

2.4 生成BO

在DAO外面再封装一层BO,可按不同的交易需求进行使用。

按照面向接口编程的思想,把BO分为接口和实现两层:

接口层NextIdBO:

package com.robertbao.bo;

import java.util.List;
import com.robertbao.exception.RobException;
import com.robertbao.po.NextId;

public interface NextIdBO {
public abstract NextId getNextId(String idCd) throws RobException;
public abstract List getNextId() throws RobException;
public abstract List getNextIdByIC_SKC(String idCd , String subKeyCd)
throws RobException;
public abstract void addNextId(NextId nextId) throws RobException;
public abstract void updateNextId(NextId nextId) throws RobException;
public abstract void deleteNextId(NextId nextId) throws RobException;
public abstract void deleteNextId(String id) throws RobException;
}

实现层NextIdBOImpl:

package com.robertbao.bo.impl;

import java.util.HashMap;
import java.util.List;
import com.robertbao.bo.NextIdBO;
import com.robertbao.common.err.Module;
import com.robertbao.common.err.Rescode;
import com.robertbao.dao.INextIdDAO;
import com.robertbao.dao.ITxnLogDAO;
import com.robertbao.exception.RobException;
import com.robertbao.po.NextId;
import com.robertbao.po.TxnLog;

public class NextIdBOImpl implements NextIdBO {
private INextIdDAO nextIdDAO;
private ITxnLogDAO txnLogDAO;
public void setTxnLogDAO(ITxnLogDAO txnLogDAO) {
this.txnLogDAO = txnLogDAO;
}
public NextIdBOImpl() {
super();
}
public void setNextIdDAO(INextIdDAO nextIdDAO) {
this.nextIdDAO = nextIdDAO;
}
public void addNextId(NextId nextId) throws RobException{
try {
nextIdDAO.save(nextId);
} catch (Exception ex) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“Nextid save error: nextId=” + nextId, ex);
}
}
public void deleteNextId(NextId nextId) throws RobException{
try {
nextIdDAO.delete(nextId);
} catch (Exception ex) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“Nextid delete error: nextId=” + nextId, ex);
}
}
public NextId getNextId(String idCd) throws RobException{
return nextIdDAO.get(idCd);
}
public List getNextId() throws RobException{
return nextIdDAO.findAll();
}
public List getNextIdByIC_SKC(String idCd, String subKeyCd)
throws RobException{
HashMap map = new HashMap();
map.put(”IdCd”, idCd);
map.put(”SubKeyCd”, subKeyCd);
List result = nextIdDAO.findByNamedQuery(”NextIdIC_SKC”, map);
if (result.size() == 0) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“GetnextId error: idCd=” + idCd + “, subKeyCd=” + subKeyCd);
}
return result;
}
public void updateNextId(NextId nextId) throws RobException{
try {
nextIdDAO.update(nextId);
} catch (Exception ex) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“Nextid update error: nextId=” + nextId, ex);
}
}
public void deleteNextId(String id) throws RobException{
try {
nextIdDAO.delete(id);
} catch (Exception ex) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“Nextid delete error: id=” + id, ex);
}
}
public void saveTxnLog(NextId nextId, TxnLog txnLog) throws RobException{
try {
nextIdDAO.save(nextId);
txnLogDAO.save(txnLog);
} catch (Exception ex) {
throw new RobException(Module.BO_MODULE, Rescode.FAIL,
“saveTxnLog error: nextId=” + nextId + “, txnLog=”
+ txnLog, ex);
}
}
}

其中:
getNextId(String idCd)通过主键查询记录;
getNextId()获得所有记录;
getNextIdByIC_SKC(String idCd , String subKeyCd)通过idCd和subKeyCd进行查询;
addNextId(NextId nextId)增添一条记录;
updateNextId(NextId nextId)更新一条记录;
deleteNextId(NextId nextId)通过对象删除一条记录;
deleteNextId(String id)通过主键删除一条记录;
saveTxnLog(NextId nextId, TxnLog txnLog)保存交易流水;

标注:开发的时候,应该按需在BO中添加具体的交易,可以调用DAO中已经定义的方法,BO中的方法已经全部绑定Spring的事务管理功能。

2.5 注册Bean

在Spring配置文件中注册生成的DAO和BO,按照AOP的思想用切面来声明事务管理。

在项目下的WEB-INF/spring/db目录中的applicationContext-hibernate.xml文件中进行配置:

<?xml version=”1.0″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>
<beans>
<bean id=”dataSource”
class=”org.apache.commons.dbcp.BasicDataSource”
destroy-method=”close”>
<property name=”driverClassName”>
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name=”url”>
<value>jdbc:oracle:thin://192.1.1.163:1521/robconsole</value>
</property>
<property name=”username”>
<value>rob</value>
</property>
<property name=”password”>
<value>rob</value>
</property>
</bean>

<bean id=”sessionFactory”
class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>
<property name=”dataSource”>
<ref local=”dataSource” />
</property>
<property name=”hibernateProperties”>
<props>
<prop key=”hibernate.dialect”>
org.hibernate.dialect.Oracle9Dialect
</prop>
<prop key=”hibernate.show_sql”>true</prop>
<prop key=”hibernate.query.factory_class”>
org.hibernate.hql.classic.ClassicQueryTranslatorFactory
</prop>
</props>
</property>

<property name=”mappingResources”>
<list>
//在这里添加你需要使用的hbm.xml文件
<value>NextId.hbm.xml</value>
</list>
</property>
</bean>

<bean id=”HibernateInterceptor”
class=”org.springframework.orm.hibernate3.HibernateInterceptor”>
<property name=”sessionFactory”>
<ref bean=”sessionFactory” />
</property>
</bean>

//添加你的DAO,并统一以”原DAO名+Target”命名
<!–DAO TARGET–>
<bean id=”NextIdDAOTarget” class=”com.robertbao.dao.NextIdDAO”>
<property name=”sessionFactory”>
<ref bean=”sessionFactory” />
</property>
</bean>

//定义新的DAO,将HibernateInterceptor织入NextIdDAOTarget
<!–DAO–>
<bean id=”NextIdDAO”
class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>com.robertbao.dao.INextIdDAO</value>
</property>
<property name=”interceptorNames”>
<list>
<value>HibernateInterceptor</value>
<value>NextIdDAOTarget</value>
</list>
</property>
</bean>

<!–Transaction–>
<bean id=”TransactionManager”
class=”org.springframework.orm.hibernate3.HibernateTransactionManager”>
<property name=”sessionFactory”>
<ref bean=”sessionFactory” />
</property>
</bean>

<bean id=”TransactionInterceptor”
class=”org.springframework.transaction.interceptor.TransactionInterceptor”>
<property name=”transactionManager”>
<ref bean=”TransactionManager” />
</property>
<property name=”transactionAttributeSource”>
<value>
//按此种形式添加事务管理的方式
com.robertbao.bo.NextIdBO.*=PROPAGATION_REQUIRED,-Exception
</value>
</property>
</bean>

//添加你的BO,并统一以”原BO名+Target”命名
<!–BO TARGET–>
<bean id=”NextIdBOTarget” class=”com.robertbao.bo.impl.NextIdBOImpl”>
<property name=”nextIdDAO”>
<ref bean=”NextIdDAO” />
</property>
</bean>

//定义新的BO,将TransactionInterceptor织入NextIdBOTarget
<!–BO–>
<bean id=”NextIdBO”
class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>com.robertbao.bo.NextIdBO</value>
</property>
<property name=”interceptorNames”>
<list>
<value>TransactionInterceptor</value>
<value>NextIdBOTarget</value>
</list>
</property>
</bean>

</beans>

在配置文件中将原有的BO实现NextIdBOImpl命名为NextIdBOTarget,并且与Transaction Interceptor共同组装成新的NextIdBO,这样就屏蔽了客户对BO事务管理的了解,客户调用NextIdBO中的方法进行数据库的操作时,实际上BO已经具有Spring提供的事务功能,可以进行数据库的提交或回滚了。

3. 名词解释

PO:persistant object 持久对象,可以看成是与数据库中的表相映射的Java对象。最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合。PO中不应该包含任何对数据库的操作。

VO:value object值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不对应,这根据业务的需要。

DAO:data access object 数据访问对象,此对象用于访问数据库。通常和PO结合使用,DAO中包含了各种数据库的操作方法。通过它的方法,结合PO对数据库进行相关的操作。

BO:business object 业务对象,封装业务逻辑的Java对象,通过调用DAO方法,结合PO,VO进行业务操作。

POJO:plain ordinary java object 简单无规则Java对象,它应该是一个包含行为、属性的传统Java对象。

分类: WORK 标签: ,
  1. 赵磊
    2007年1月9日10:06 | #1

    这个hibernate的同步插件不用还不行,手工写PO累死

  2. 李方非
    2007年1月9日11:05 | #2

    hibernate-synchronizer插件的最新版本是3.1.9,不知能不能少点bug,但是这个插件看起来已经很久没更新了

  3. robertbao
    2007年1月9日12:56 | #3

    >>赵磊:PO、DAO这些累活还是要让工具干,我们可以更高一层地考虑业务逻辑。
    >>李方非:我这里用3.1.1版本,是因为考虑到和Jdk1.4的配合。希望它的最新版已经消除了这些bug。

  4. 2007年1月17日01:58 | #4

    这个工具不怎样的。生成好的Model层对象及其混乱,而且DAO是“圆环套圆环”,改起来太痛苦了。

  5. cskys
    2007年2月25日15:30 | #5

    这个插件最大的问题是不支持“视图”。