Hibernate Hibernate Reference Manual

OpenDoc Series
Hibernate 开发指南
V1.0
作者:夏昕 xiaxin(at)gmail.com
Hibernate Developers Guide Version 1.0
文档说明
参与人员:
作者 联络 夏昕 xiaxin(at)gmail.com
(at) email @ 符号
发布记录
版本 日期 作者 说明
0.9 2004.5.1 夏昕 第一版
1.0 2004.9.1 夏昕 错误修订 增加 Hibernate in Spring
OpenDoc 版权说明
本文档版权归原作者所有。 在免费、且无任何附加条件的前提下,可在网络媒体中自由传播。
如需部分或者全文引用,请事先征求作者意见。
如果本文对您有些许帮助,表达谢意的最好方式,是将您发现的问题和文档改进意见及时反馈 作者。当然,倘若有时能力,能为技术群体无偿贡献自己的所学为最好的馈。
另外,笔者近来试图就日本、印度式进行一些调研。如果诸位以赠阅日本、印度过程中的需求、设计文档以供研究感激不尽!
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate 开发指南
本文是由2003 年底个咨询项目中,为客户做持久层设计培训案整理而来。
中的内容涉Hibernate 的使用,以及一部分笔者实际咨询项目中的 经验积累一方部分是笔者在 Hibernate 的官方论坛与众多 技术专家交流
既来于斯于斯希望有所用。
本文并非试图替代 Hibernate Reference,,Hibernate Reference编写的是为开发者提更简便的条索引,而本文标则在于为开人员入门掌握 Hibernate 的途径
本文需结合 Hibernate Reference 使用。
笔者好友曹晓钢义务组织了 Hibernate 文档的汉化工作,在此对其辛勤劳作致敬。 中文版 Hibernate Reference 将被包含在 Hibernate 下个官方 Release 中,目前可 通过 http://www.redsaga.com 获取中文版 Hibernate Reference 的最新版本。
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate 开发指南 .......................................................................................................3
准备工作 ..........................................................................................................5
构建 Hibernate 基础代码 ...............................................................................5
由数据库产生基础代码...........................................................................6
Hibernate 配置 ..............................................................................................17
第一段代码 ....................................................................................................19
Hibernate 基础语义 ......................................................................................21
Configuration ........................................................................................21
SessionFactory.......................................................................................22
Session....................................................................................................22
Hibernate 高级特性 ......................................................................................................24
XDoclet Hibernate 映射...........................................................................24
数据检索 ........................................................................................................33
Criteria Query...............................................................................33
Criteria 查询表达式 ................................................................33
Criteria 高级特性 ....................................................................35
限定返回的记录范围.............................................................35
查询结果进行排序.............................................................35
Hibernate Query Language (HQL) .........................................36
数据关联 ........................................................................................................37
一对一关联.............................................................................37
一对多关联.............................................................................39
Ø 单向一对多关系......................................................39
Ø 双向一对多关系......................................................44
多关联.............................................................................49
数据访问 ........................................................................................................56
PO VO...............................................................................................56
关于 unsaved-value ...............................................................................59
Inverse Cascade.........................................................................61
延迟加载(Lazy Loading............................................................61
管理 ........................................................................................................65
JDBC 管理.........................................................................66
JTA 管理 ...........................................................................67
locking.........................................................................................70
悲观锁(Pessimistic Locking.......................................70
乐观锁(Optimistic Locking..........................................71
Hibernate 分页..........................................................................................75
Cache 管理....................................................................................................77
Session 管理...............................................................................................81
Hibernate in Spring...........................................................................................86
编后赘言 ........................................................................................................................92
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate 初识
Quick Start 教
准备工作
1载 Ant 解压缩(如 C:\ant\其 bin 目录( 如 c:\ant\bin)添到系统
PATH 中。
2载 HibernateHibernate-Extension 和 Middlegen-Hibernate 的最版本。 http://prdownloads.sourceforge.net/hibernate/
构建 Hibernate 基础代码
Hibernate 基础代码包括
1 POJO POJO Hibernate 语义数据库表所对Domain Object这里POJO
是所谓Plain Ordinary Java Object,字是无普通 Java 对象的可以理解为个不包含逻辑代码的值对象(Value Object 简称 VO)
个典型POJO
public class TUser implements Serializable {
private String name;
public User(String name) { this.name = name; }
/** default constructor */ public User() { }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; } }
2Hibernate 映射文件 Hibernate 质上是一种“象-关系型数据映射”( O bject Relational
Mapping 简称 ORM。前面POJO 这里体现的ORM Object 语义映射(Mapping文件是将对象(Object)与关系型数据(Relational)相关
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
纽带,在 Hibernate 中,映射文件通常.hbm.xml后缀
构建 Hibernate 基础代码通常途径
1手工编写
2直接从数据库导出结构并生成的 ORM 文件和 Java 代码
实际开发中最用的方式,是这里所推荐的方式。 直接从标数据库导出数据结构,最小化了手工编码调整的可,从
大程度保证了 ORM 文件和 Java 代码与实际数据库结构相
3现有的 Java 代码生成映射文件,将 Java 代码数据库绑定
预先编写好的 POJO 生成映射文件,这种方式在实际开发中使用,特别结合xdoclet 灵活在问题与实际数据库结构
现的同步的障碍,由手工调整代码,往往调整过程中由手工操作的 疏漏后生成配置文件错误,这点发中特别注意。 结合 xdoclet,由 POJO 生成映射文件的技术我们将在“高级特性章节中进探讨
由数据库产生基础代码
Hibernate 方提MiddleGen for Hibernate Hibernate_Extension ,我
便现有数据库导出数据库结构生成 ORM POJO
1) 先,将 Middlegen-Hibernate 包解压缩( 解压缩到 C:\Middlegen\
2) 配置标数据库
MiddleGen 下的\config\database 录,我们实际用的数据库
配置文件。如这里我们用的是 mysql 数据库,对mysql.xml 文件。
<property name="database.script.file"
value="${src.dir}/sql/${name}-mysql.sql"/>
<property name="database.driver.file"
value="${lib.dir}/mysql.jar"/>
<property name="database.driver.classpath"
value="${database.driver.file}"/>
<property name="database.driver"
value="org.gjt.mm.mysql.Driver"/>
<property name="database.url"
value="jdbc:mysql://localhost/sample"/>
<property name="database.userid"
value="user"/>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
<property name="database.password"
value="mypass"/>
<property name="database.schema"
value=""/>
<property name="database.catalog"
value=""/>
<property name="jboss.datasource.mapping"
value="mySQL"/>
中下划线的部分是我们进行配置的内容,分数据 url 以数据库
3) 修改 Build.xml
修改 MiddleGen 下的 build.xml 文件,文件是 Middlegen-Hibernate 的 Ant 构建配置。Middlegen-Hibernate 将build.xml 文件中的数生成数据库映射 文件。可配置的项目包括
a) 标数据库配置文件地址
查找!ENTITY
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/hsqldb.xml">
]>
默认情况下,MiddleGen 用的是 hsqldb.xml,将修改我们所用的数据配置文件(mysql.xml)
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/mysql.xml">
]>
b) Application name
查找
<property name="name" value="airline"/>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
aireline”是 MiddleGen 始配置中默认 Application Name,将 修改我们希望,如HibernateSample”:
<property name="name" value="HibernateSample"/>
c)
查找字“name="build.gen-src.dir"
<property name="build.gen-src.dir"
value="${build.dir}/gen-src"/>
修改 value="${build.dir}/gen-src"使其指向我们所期输出
这里我们修改
<property name="build.gen-src.dir"
value="C:\sample"/>
d) 应代码的 Package name
查找字“destination
<hibernate
destination="${build.gen-src.dir}" package="${name}.hibernate" genXDocletTags="false" genIntergratedCompositeKeys="false" javaTypeMapper=
"middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
看到,hibernate 节点 package 属性默认实际是由前 Application Name ${name}.hibernate我们的需
<hibernate
destination="${build.gen-src.dir}" package="org.hibernate.sample" genXDocletTags="true" genIntergratedCompositeKeys="false" javaTypeMapper=
"middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
这里有一属性 genXDocletTags,如果为 true则生成代码包含
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
xdoclet tag这为以过程xdoclet 进行映射调整帮助。Hibernate xdoclet 使用,请高级特性中的相关内容
意,如果使用的数据库SQLServer,需build.xml 中如下部分划 线部分删除Middlegen 会报表的错误。
<middlegen
appname="${name}"
prefsdir="${src.dir}"
gui="${gui}"
databaseurl="${database.url}"
initialContextFactory="${java.naming.factory.initial}"
providerURL="${java.naming.provider.url}"
datasourceJNDIName="${datasource.jndi.name}"
driver="${database.driver}"
username="${database.userid}"
password="${database.password}"
schema="${database.schema}"
catalog="${database.catalog}"
>
至此,MiddleGen 配置完毕,在 MiddleGen ant
MiddleGen
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
① ② ④ ⑤
看到,数据库中的表结构导入到 MiddleGen 的中,选定数据库
中的表元素我们即调整数据库表的属性
1 Domain Class Name
POJO 类名
2 Key Generator
主键产
说明:
1) Assigned
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
主键序负生成,无需 Hibernate
2) hilo
hi/lo 算法现的主键生成机制,需要数据库表保生成历史状态
3) seqhilo
hilo 类似hi/lo 算法现的主键生成机制主键历史 状态Sequence中,适Sequence 数据库,如 Oracle
4) increment
主键数值递增。此方式的机制变量存着当前的最大值,每次需生成主键的时1 主键
这种方式可的问题是:如果前有多个实例访个数据那么个实维护主键状态能生成
主键而造主键重复异。因,如果数据库多个实 例访问,方式必须避使用。
5) identity
数据库提主键生成机制。如 DB2、SQL ServerMySQL 中的主键生成机制
6) sequence
数据库sequence 机制生成主键。如 Oralce 中的 Sequence
7) native
Hibernate 据底层数据库自行判断identityhilosequence中一作为主键生成方式。
8) uuid.hex
Hibernate 基于 128 算法生成 16 数值(编码后32 符串作为主键
9) uuid.string
uuid.hex 生成主键编码(16)。在 数据库中可现问题(如 PostgreSQL)
10) foreign
使部表的主键
利用 uuid.hex 方式生成主键将提最好的数据库平台适
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
另外用的数据库,如 OracleDB2SQLServerMySql 用的主键生成机制Auto-Increase 或者 Sequence我们可以在 据库提供主键生成机制generator-class=native 主键生成方式。
不过意的是,一些数据库提供的主键生成机制效率未必insert 数据时可能之间互锁
数据库主键生成机制往往在一个内部表中主键如对自增主键部表中就维护着当前的最和递增量
每次插入数据读取这大值然后记录主键再把的最值更新回内部表中,这,一 Insert 作可能导数据作,伴随数据的加锁解锁作,这
影响
,对Insert 求较系统推荐采uuid.hex 主键生成 机制
3 如果需要采定制主键产生算法此处配置主键生成主键生成器必
net.sf.hibernate.id.IdentifierGenerator 接口
4 Schema Name
数据库 Schema Name
5 Persister
持久实现类类名。如果系统中还需Hibernate 外的持久层实机制,如存储过程得标数据集,LDAP 中获取数据
我们的 POJO
6 Enable proxies
使延迟载[Lazy Loading]
7 Dynamic Update
如果选定则生成 Update SQL 时不包含变动属性在一程度SQL 执行效能
8 Mutable
默认选定状态(可)。如果希望应用序对此类数据录进修改(如对数据库),可将取消选定状态
此类的 Delete Update 失效
9 Implement the Lifecyle interface
Lifecyle 。Lifecyle 数据过程中的控制机制
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
过实Lifecyle 接口我们数据库作中加回调Call Back 机制,如在数据库前,后触指定操作。
10 Implement the Validatable interface
Validatable 接口过实Validatable 接口我们数据被到数据库前对行验
得注意的是,过实Lifecyle 我们同数据数据合的是,Validatable 中定validate 能会
调用次,设计中免在 Validatable 口的 validate 现中业务逻辑的
Class ,在 MiddleGen 中,我们也以设属性。在
MiddleGen 选定下方
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
这里我们以设属性中:
1 Hibernate mapping specialty
映射
Key 主键 Property 属性 Version :用于实optimistic locking高级特性章节
optimistic locking 描述
2 Java property name
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
的 Java 属性名
3 Java Type
的 Java 数据
4 Column updateable
生成 Update SQL 时是包含
5 Column insertable
生成 Insert SQL 时是包含
击窗部的 Generate MiddleGen 我们生成这数据库表所对
Hibernate 映射文件。在 MiddleGen 下的\build\gen-src\net\hibernate\sample 中, 我们看到.hbm.xml 后缀多个映射文件,映射文件
据库的一表。
映射文件我们还要根据这些文件生成POJO
POJO 生成工作可过 Hibernate Extension Hibernate Extension
tools\bin 包含
1 hbm2java.bat
据映射文件生成POJO。MiddleGen 我们已经得映射文件, 下一hbm2java.bat 生成POJO。
2 class2hbm.bat
据 POJO class 生成映射文件,具很这里就不详细介绍
3ddl2hbm.bat
数据库导出库表结构,并生成映射文件POJO。能与 MiddleGen但由于目前实际废弃,再维护),提,所 我们还MiddleGen 生成映射文件,后由 hbm2java
据映射文件生成 POJO 的方式。
使上工我们要配置一些开 tools\bin\setenv.bat 文件,修改
中的 JDBC_DRIVER 和 HIBERNATE_HOME 环境变量使其指向我们的实际 JDBC Driver 文件和 Hibernate 所在,如
set JDBC_DRIVER=c:\mysql\mysql.jar set HIBERNATE_HOME=c:\hibernate
一下环境变量 CP 中的个项目中是实际在,特别是%CORELIB%下的 jar
文件,些版本的发中,默认配置中的文件与实际的文件有所出入(如
%CORELIB%\commons-logging.jar, Hibernate 中,可能实际的文件
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
commons-logging-1.0.3.jar,诸此类
使hbm2javaMiddleGen 生成映射文件生成 Java 代码
开 Command Window,在 tools\bin
hbm2java c:\sample\org\hibernate\sample\*.xml --output=c:\sample\
生成的 POJO生成的 POJO 我们指定c:\sample
我们已过 MiddleGen Hibernate 基础代码作。配置 MiddleGen 是一件轻松的事,对于 Eclipse 的用户而 Hibernate Plugin些 Plugin 我们轻松成上作,体的使用方式 见附
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate 配置
前面已经得映射文件和 POJO,为使 Hibernate 能真正起来我们还配置文件。
Hibernate xml 式的配置文件,及传统properties 文件配置方式,不过 里建xml 型配置文件。xml 配置文件提了更易读结构配置能力,可 以 直映射文件加配置properties 文件中则无配置必须通代码中的 Hard Coding
载相应映射文件。下如果特别说明,都指的是xml 式文件的配置方式。
配置文件名默认hibernate.cfg.xml”( 或者 hibernate.propertiesHibernate 初始化 CLASSPATH 寻找件,读取中的配置信息数据库
配置文件CLASSPATH 中,对Web 配置文件放置在在
\WEB-INF\classes 录下。
典型hibernate.cfg.xml 配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0. dtd">
<hibernate-configuration> <!- SessionFactory 配置 -->
<session-factory> <!- 数据库URL -->
< property name="hibernate.connection.url"> jdbc:mysql://localhost/sample </property>
<!- 数据库JDBC --> < property name="hibernate.connection.driver_class"> org.gjt.mm.mysql.Driver </property>
<!- 数据库名 --> < property name="hibernate.connection.username"> User </property>
<!- 数据库码 --> < property name="hibernate.connection.password">
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Mypass </property>
<!--dialect 数据库的Dialet平台特性 --> <property name="dialect"> net.sf.hibernate.dialect.MySQLDialect </property>
<!- 生成SQL 出到以供调试 --> <property name="hibernate.show_sql"> True </property>
<!- 使数据库 --> < property name="hibernate.use_outer_join"> True </property>
<!- 这里我们使用JDBC Transaction --> <property name="hibernate.transaction.factory_class"> net.sf.hibernate.transaction.JDBCTransactionFactory </property>
<!映射文件配置配置文件必须包含的全径 --> <mapping resource="net/xiaxin/xdoclet/TUser.hbm.xml"/> <mapping resource="net/xiaxin/xdoclet/TGroup.hbm.xml"/>
</session-factory> </hibernate-configuration>
典型的 hibernate.properties 配置文件如下:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class org.gjt.mm.mysql.Driver
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql:///sample
hibernate.connection.username user
hibernate.connection.password mypass
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
第一段代码
我们已Hiberante 的基础代码,现在先简单代码入手
Hibernate 所提
代码是一JUnit TestCase,TUser 对读取考虑者可
没有 JUnit 的使经验代码中加一些 JUnit 相关释。
public class HibernateTest extends TestCase {
Session session = null;
/** * JUnitsetUpTestCase始化的时 * 始化资源 * 中,用始化Hibernate Session
*/ protected void setUp(){ try {
/** * hibernate.properties配置文件的始化代码
* Configuration config = new Configuration(); * config.addClass(TUser.class); */
//hibernate.cfg.xml配置文件 //始化Configuration时的 // 1.Configuration始化方式 // 2.xml文件中了Mapping文件,无需再Hard Coding导入 // POJO文件的 Configuration config = new Configuration().configure();
SessionFactory sessionFactory =
config.buildSessionFactory();
session = sessionFactory.openSession();
} catch (HibernateException e) { e.printStackTrace(); } }
/**
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
* setUpJUnit TestCase完毕时,用tearDown * 资源释放 * 中,用在setUpHibernate Session */ protected void tearDown(){ try { session.close(); } catch (HibernateException e) { e.printStackTrace(); } }
/** * 持久Insert)
* * JUnit中,test的方,将被JUnit * 试计
*/ public void testInsert(){
try { TUser user = new TUser(); user.setName("Emma");
session.save(user); session.flush(); } catch (HibernateException e) { e.printStackTrace(); Assert.fail(e.getMessage()); } }
/** * 读取Select
* 保证运数据库name=Erica
*/ public void testSelect(){ String hql= " from TUser where name='Erica'";
try { List userList = session.find(hql); TUser user =(TUser)userList.get(0); Assert.assertEquals(user.getName(),"Erica");
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
} catch (HibernateException e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } }
IDE,如 EclipseIntellij IDEA JBuilder 置了 JUnit 。下Eclipse
代码的结果(在 Run 单中Run as -> JUnit Test ):
现在我们已简单的 TUser 例的存和读取。可 看到,序中
代码现了 Java 数据库数据的同步Hibernate 的有轻松象到关系型数据库映射
对传JDBC 数据访问式,样的现无向对思想同时大大
高了效率
代码中引个 Hibernate 基础语义
1Configuration 2SessionFactory 3Session
我们概念探讨
Hibernate 基础语义
Configuration
Configuration 类负责Hibernate 配置信息Hibernate 时需 获取一些底层实现的信息键属性包括
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
1. 数据库 URL 2. 数据库 3数据库 4数据库 JDBC 5. 数据库 dialect,用特定数据库包含特定数据库特性
现,如 Hibernate 数据型到特定数据库数据映射
使Hibernate 必须先提基础信息始化作,为
些属性hibernate 配置文件hibernate.cfg.xml hibernate.properties中加以设见前Hibernate 配置中的示例配置文件内容
我们用:
Configuration config = new Configuration().configure();
时,Hibernate 自动前的 CLASSPATH 搜寻 hibernate.cfg.xml 文件其读中作作的基础配置Configuration 般只有在获取 SessionFactory
时需及,获取 SessionFactory 后,由配置信息Hibernate 维护绑定SessionFactory 上,此一情况无需操作。
我们也指定配置文件,如果希望使用默认的 hibernate.cfg.xml 文件作配 置文件的
File file = new File("c:\\sample\\myhibernate.xml"); Configuration config = new Configuration().configure(file);
SessionFactory
SessionFactory Session 我们Configuation 构建 SessionFactory
Configuration config = new Configuration().configure(); SessionFactory sessionFactory = config.buildSessionFactory();
Configuration config 会根前的配置信息造 SessionFactory SessionFactory 完毕赋予特定配置信息是说,config 的任
影响SessionFactory 实sessionFactory。如果需 使config 实SessionFactory,需config 新构建一个 SessionFactory
Session
Session 持久层作的基础当于 JDBC 中的 Connection Session SessionFactory 构建
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
我们以调用 Session 所提的 savefind、flush 持久层作:
Find:
String hql= " from TUser where name='Erica'"; List userList = session.find(hql);
Save:
TUser user = new TUser(); user.setName("Emma"); session.save(user); session.flush();
Session.flush方法数据库同步这里强制Hibernateuser
即同步到数据库中。如果在事务中flush方法,在事务提的时候,
hibernateflush另外当Session时,也会动执行flush
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate 高级特性
XDoclet Hibernate 映射
POJO 融合 XDoclet 的映射文件自生成机制,提了除手编码和由数据库导出
基础代码的第三种
结合 XDoclet Hibernate 中的数据映射进行介绍
实际开发中,往往使MiddleGen hbm2java 生成带XDoclet tag POJO
MiddleGen build.xml中的 genXDocletTags项决定了映射文件中生成XDoclet TagHibernate Quick Start章节MiddleGen 的说明后通修改 POJO 中的 XDoclet
tag 映射关系调整
XDoclet 广泛用在 EJB 发中,在 版本包含个为 Hibernate
子类库 Hibernate Doclet包含生成 Hibernate 映射文件所需的 ant 构建持以 java doc tag
XDoclet 本原是,在 Java 代码特定的 JavaDoc tag而为其特定
的附加语义后通XDoclet 具对代码JavaDoc Tag 进析,自生成代码配置文件,XDoclet。
Hibernate-Doclet 中,过引Hibernate 相关的 JavaDoc tag,我们就可以由代码生成
Hibernate 映射文件。
是一代码Hibernate-Doclet 的使用方式:
/**
* @hibernate.class * table="TUser" */
public class TUser implements Serializable {
…… /** * @hibernate.property * column="name" * length="50" * not-null="true"
*
* @return String */ public String getName() { return this.name;
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
}
……
}
上是使Hibernate-Doclet 描述 POJOTUser)及TUser映射关系 的一
中用到hibernate doclet tag@hibernate.class @hibernate.propertytag 描述POJO 所对应的数据库信息其字信息 Hibernate Doclet 会根据这信息生成映射文件:
<hibernate-mapping>
<class name="net.xiaxin.xdoclet.TUser" table="TUser"
>
<property
name="name" type="java.lang.String" column="name" not-null="true" length="50"
>
</class> </hibernate-mapping>
我们维护 Java 代码无需再手动编写体的映射文件完成 Hibernate 基础代码
Hibernate-Doclet 众多Tag然不是件轻松的事,好在前的主流 IDE Live Template 支持我们需进行一些配置作,就以实Hibernate-Doclet Tag
的自手工编写过程中可能出现的问题。
中提了主IDE,包括 JBuilder,Intellij IDEA,Eclipse 的 Hibernate-Doclet 南。
我们Hibernate Doclet 用的 Tag 进探讨Tag 的详细,请
XDoclet http://xdoclet.sourceforge.net/xdoclet/tags/hibernate-tags.html Hibernate Referencehttp://www.hibernate.org
用 Hibernate-Doclet Tag 介绍
1. Class 层面
1) @hibernate.class
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
描述 POJO 数据库映射关系指定相关
参数 描述 类型 必须
table
dynamic-update
dynamic-insert
Proxy
discriminator-value where
的表名 默认类名
生成 Update SQL 时,包含变动
默认: false 生成 Insert SQL 时,包含非(null)
默认false
默认 子类,用于多态支
数据选条件,如果库表中特定数据的时,可 此选项设
条件。
如用表中所有用数据,
我们系统可指
where=location=Shanghai"
Text N
Bool N
Bool N
Text N
Text N Text N
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
典型场景
/**
* @hibernate.class * table="TUser" (1) * dynamic-update="true" (2) * dynamic-insert="true" (3)
* proxy=”” (4) * discriminator-value=1 (5) */
public class TUser implements Serializable { ……
}
: 1 table 指定了TUser应数据库TUser
2 dynamic-update 生成 Update SQL 包括前发
高 DB Update
3 Dynamic-insert 生成 Insert SQL 包括
高 DB Insert
4 Proxy ,表明不使Proxy的作用是Lazy
Loading 见下Lazy Loading 的有内容
5 discriminator-value 设为”1”
discriminator-value 的是对。请见下 @hibernate.discriminator 的说明。
2) @hibernate.discriminator
@hibernate.discriminator别器供多态支
参数 描述 类型 必须
column
type length
各子类段名 默认类名
Hibernate 类型段长
如:
TUser应数据库TUserUserSysAdmin
SysOperator
TUser表中, user_type分用
September 2, 2004 So many open source projects. Why not Open your Documents?
text Y
Bool N Bool N
Hibernate Developers Guide Version 1.0
Hibernate根据user_typeClass类型( user_type==1
映射到SysAdminuser_type==2 则映射到SysOperator类)我们
映射文件中进配置Hibernate-Doclet中,对 @hibernate.discriminator @hibernate.class @hibernate.subclass
discriminator-value属性
典型场景
/**
* * @hibernate.class * table="TUser" * dynamic-update="true" * dynamic-insert="true"
*
* @hibernate.discriminator column="user_type" type="integer" */
public class TUser implements Serializable { ……
}
根类 TUser 中,@hibernate.discriminator 指定了"user_type"
/**
* @hibernate.subclass * discriminator-value="1"
*/
public class SysAdmin extends TUser {
…… }
/**
* @hibernate.subclass * discriminator-value="2" */
public class SysOperator extends TUser {
……
}
SysAdmin SysOperator 均继承TUser,其 discriminator-value 别设
"1""2"Hibernate 读取 t_user 数据时,会根据其 user_type 进行
判断,如果是 1 则映射到 SysAdmin ,如果是 2 映射到 SysOperator
中,描述 SysAdmin SysOperator 时,我们引入Tag
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
@hibernate.subclass,@hibernate.subclass @hibernate.class
同之@hibernate.subclass 描述的是一个子类实际Tag去名不同区别
2. Method 层面
1) @hibernate.id
描述 POJO 数据库主键之映射关系
参数 描述 类型 必须
column
type
length unsaved-value
generator-class
主键名 默认类名
Hibernate 使用对象型数据
,如 int 对应 Integer 这里id 设为[int]免对
思路实际意义的,
使这里基本型,Hibernate
使用对象型数据对
返回数据的时候再转换为
段长度 否已经
“数据访章节相关讨 主键产方式Hibernate Quick
Start MiddleGen 相关说明 中的任意一
Text N
Text N
Text N Text N
Text Y
assigned hilo seqhilo increment identity sequence native uuid.hex uuid.string foreign
2) @hibernate.property
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
描述 POJO 属性数据库映射关系
参数 描述 类型 必须
column
type length not-null unique insert
update
数据库段名 默认类名
型 字段长重复值)
Insert 作时是包含数据 默认true
Update 作时是否包含数据 默认true
典型场景
/** * @hibernate.property * column="name" * length="50" * not-null="true" * * @return String */
public String getName() {
return this.name; }
Text N
Text N Text N Bool N Bool N Bool N
Bool N
注意:在编写代码的时候请,对将POJOgetter/setter法设定public如果 设定privateHibernate将无法性的进行优化,只能转而采用传统机制 进行操作,大量的性销(1.4前的Sun JDK版本以及IBM JDK中,所带来系统相当观)
包含XDoclet Tag代码必须由xdoclet理以生成映射文件, xdoclet理模ant,下是一简单hibernate xdocletant 构建实际使用时需要根实际情况CLASSPATH行调整
<?xml version="1.0"?>
<project name="Hibernate" default="hibernate" basedir=".">
<property name="xdoclet.lib.home"
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
value="C:\xdoclet-1.2.1\lib"/>
<target name="hibernate" depends="" description="Generates Hibernate class descriptor files.">
<taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask">
<classpath> <fileset dir="${xdoclet.lib.home}"> <include name="*.jar"/> </fileset> </classpath>
</taskdef>
<hibernatedoclet destdir="./src/" excludedtags="@version,@author,@todo" force="true" verbose="true" mergedir=".">
<fileset dir="./src/"> <include name="**/hibernate/sample/*.java"/> </fileset>
<hibernate version="2.0"/>
</hibernatedoclet> </target>
</project>
除了我们介绍Hibernate Doclet Tag有:
Class层面
@hibernate.cache
@hibernate.jcs-cache @hibernate.joined-subclass @hibernate.joined-subclass-key @hibernate.query
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Method层面
@hibernate.array @hibernate.bag @hibernate.collection-cache @hibernate.collection-composite-element @hibernate.collection-element @hibernate.collection-index @hibernate.collection-jcs-cache @hibernate.collection-key @hibernate.collection-key-column @hibernate.collection-many-to-many @hibernate.collection-one-to-many @hibernate.column @hibernate.component @hibernate.generator-param
@hibernate.index-many-to-many @hibernate.list @hibernate.many-to-one @hibernate.map @hibernate.one-to-one @hibernate.primitive-array @hibernate.set @hibernate.timestamp @hibernate.version
体的Tag描述XDoclet方网Tag说明1。下 的 Hibernate高级特性 中,我们也到这些Tag实际使用。
1
http://xdoclet.sourceforge.net/xdoclet/tags/hibernate-tags.html
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
数据检索
数据询与索是 Hibernate 中的一相对ORM 实现言,Hibernate
了灵活样的机制。包括:
1. Criteria Query
2. Hibernate Query Language (HQL)
3. SQL
Criteria Query
Criteria Query 过面对象设计,将数据条件封装简单
Criteria Query 以看作是传SQL 的对,如:
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("name","Erica"));
criteria.add(Expression.eq("sex",new Integer(1)));
这里的 criteria 实际是 SQL Select * from t_user where
name=Erica and sex=1封装我们开 Hibernate show_sql 观察 Hibernate 生成SQL
Hibernate 会根Criteria 指定条件代码
criteria.add 加的表达式)生成相应SQL
这种方式的特点较符Java 程编码习惯清晰的可
ORM 实现中提供了类机制Apache OJB
Hibernate 者,特别是对 SQL 解有言,Criteria Query
上手的途径,相对 HQLCriteria Query 于理解的段,IDE 的 Coding Assist 机制Criteria 的使
Criteria 查询表达式
Criteria 是一询容体的条件需Criteria.addCriteria 中。
如前Expression 对 描述了查条件。SQL 法 , Expression 机制,包括
描述
Expression.eq
Expression.allEq
Expression.gt
SQLfield = value表达式。 Expression.eq("name","Erica")
Map 对象中包含多个属性-值 应关系。相当于多个 Expression.eq关系加。
对应 SQL 中的 field > value 表达式
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Expression.ge Expression.lt Expression.le
Expression.between
Expression.like Expression.in Expression.eqProperty
应 SQL 中的 field >= value 表达式 对应 SQL 中的 field < value 表达式 应 SQL 中的 field <= value 表达式 对应 SQL 中的 between 表达式
如下的表达式表age位于 1350 间内
Expression.between("age",new Integer(13),new Integer(50));
应 SQL 中的 field like value 表达式 对应 SQL 中的 field in …” 表达式 属性之间的,对 应 SQL 中的“field
= field”。 如:
Expression.eqProperty(
"TUser.groupID", "TGroup.id"
Expression.gtProperty
Expression.geProperty
Expression.ltProperty
Expression.leProperty
Expression.and
); 属性之,对 应 SQL 中的“field
> field 属性之,对 应 SQL 中的“field
>= field 属性之,对 应 SQL 中的“field
< field 属性之,对 应 SQL 中的“field
<= field and 关系
如:
Expression.and(
Expression.eq("name","Erica"), Expression.eq(
"sex",
new Integer(1)
)
);
Expression.or
or 关系 如:
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Expression.or(
Expression.eq("name","Erica"), Expression.eq("name","Emma")
);
Expression.sql
Expression 各方中的属性名参数(如 Express.eq 中的第一数),这里属性名POJO 中对实际属性名),非库表中的
充,本方SQL 法的支持。 直接通SQL 定查 条件。
代码所有Erica始的录:
Expression.sql(
lower({alias}.name) like lower(?), "Erica%",
Hibernate.STRING
);
中的{alias}”将由 Hibernate 使联的 POJO 别名换。
Criteria 高级特性
限定返回的记录范围
criteria. setFirstResult/setMaxResults 方范围:
查询结果进行排序
//所有groupId=2 //照姓名(序)groupId
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("groupId",new Integer(2)));
criteria.addOrder(Order.asc("name"));
Criteria criteria = session.createCriteria(TUser.class);
//定查索结果中,第一的20
criteria.setFirstResult(100);
criteria.setMaxResults(20);
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
criteria.addOrder(Order.desc("groupId"));
Criteria 封装式,不过于 Hibernate 过程中将
中在 HQL 语言上Criteria 的能实现(这OJBCriteria ,在实际开发中,Hibernate 推荐的查封装模式:HQL
Hibernate Query Language (HQL)
Criteria 象编程模式的封装式。不过HQL(Hibernate
Query Language,在中,HQL 推荐
式。
Criteria,HQL 提更接近传SQL 句的法,也提更全特性
简单的一
String hql = "from org.hibernate.sample.TUser"; Query query = session.createQuery(hql); List userList = query.list();
面的代码TUser 的所有对
如果我们Erica”的用SQL,我们可SQL 句加
String hql =
"from org.hibernate.sample.TUser as user where user.name='Erica'";
Query query = session.createQuery(hql);
List userList = query.list();
中我们aswhereas 子类名别名where
指定了条件。
HQL
子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。
于 HQLHibernate 的说明和示例 Hibernate Chapter 11
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
数据关联
一对一关联
配置:
Hibernate 中的一对一联由one-to-one节点定义。
我们的权限管系统示例中,个用户于一个用户组。如用Erica System Admin组,发,是一典型(单一对 一关系
我们系统中反为 TUser TGroup one-to-one 关系中 TUser 方,TGroup 是被动方。
one-to-one 关系简单需在方加这里我们
TUser 对获取其对TGroup 对TUser 对方,现一 对一关系我们TUser 对映射文件 TUser.hbm.xml 中加one-to-one
,对 TGroup 一对一联:
<hibernate-mapping>
<class
name="org.hibernate.sample.TUser"
table="t_user"
dynamic-update="true"
dynamic-insert="true"
>
……
<one-to-one
name="group"
class="org.hibernate.sample.TGroup"
cascade="none"
outer-join="auto"
constrained="false"
/>
……
</class>
</hibernate-mapping>
如果XDocletTag 如下:
/**
* @hibernate.class
* table="t_user"
* dynamic-update="true"
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
* dynamic-insert="true"
*
*/
public class TUser implements Serializable {
……
private TGroup group;
/**
* @hibernate.one-to-one
* name="group"
* cascade="none"
* class="org.hibernate.sample.TGroup"
* outer-join="auto"
* @return
*/
public TGroup getGroup() {
return group;
}
……
}
one-to-one 节点属性
描述 类型 必须
name class
cascade
映射属性
标映射类设为包含 Package name 的全
(cascade)关系
all : 所有情况作。 none:所有情况作。 save-update:save-update
作。 delete:在 delete 时进作。
联(cascade)Hibernate 映射关
中是非常概念的是
行操作时,联对象(被动 否同步作。如对主
save-update delete 时,是 否同
时对联对象(被动
Text N Text N
Text N
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
save-update delete
这里TUser更新或者删除 时,联的TGroup被修
改或者删除,此,这里级联关系
none
constrained
outer-join
property-ref
约束
表明表的主键上在一个外
foreign key约束。这
关系到 save、delete 等方
使接。
true使outer-join false不使outer-join auto(默认) :如果联对
Proxy 机制使outer-join.
中用于与类相关联的属性名
默认为关主键属性名
这里我们主键达成一对一的关联,所 默认可。如果一对一的关 非建主键之,则此参数指定
属性
Bool N
Text N
Text N
access
一对多关联
一对关系系统现中也很见。典型例子父亲关系在我现在的示例中,TUser多个地址(TAddress),如一
地址地址多个地址属性,在系统中,应为一对”关联。
一对多关系一对关系一对多关系
一对关系需在方进配置一对关系
配置
Ø 单向一对多关系
属性值的读取方式。
field property默认 ClassName
Text N
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
配置:
(TUser
TUser.hbm.xml:
<hibernate-mapping>
<class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true"
>
…… <set name="addresses" table="t_address" lazy="false" inverse="false" cascade="all" sort="unsorted"
order-by="zipcode asc"
> <key column="user_id" > </key>
<one-to-many class="org.hibernate.sample.TAddress" /> </set> …… </class>
</hibernate-mapping>
XDoclet Tag 如下:
/** * @hibernate.collection-one-to-many
* class="org.hibernate.sample.TAddress"
* * @hibernate.collection-key column="user_id" * * @hibernate.set
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
* name="addresses" * table="t_address" * inverse="false" * cascade="all" * lazy="false"
* sort=unsorted * order-by="zipcode asc"
* */ public Set getAddresses() { return addresses; }
被动(TaddressHibernate 责读取指定
Collection 属性中。
one-to-many 关系我们java.util.Set 或者
net.sf.hibernate.collection.BagCollection,表现在 XML 映射文件
也就<set></set><bag></bag>节点关于 Hibernate Collection现,请Hibernate Reference.
one-to-many 节点有以属性
描述 类型 必须
name table lazy
inverse
cascade
映射属性
标关联数据库表。 否采用延迟
延迟加,请相关章节。
联中的被动方一
inverse=false 的一方(主控)负责 维护关联关系
默认 false cascade)关系
all : 所有情况作。 none:所有情况作。 save-update:save-update
作。
Text Y Text Y Text N
Bool N
Text N
delete:在 delete 时进作。
sort
序类
Text N
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
unsorted 默认 natural :自与 order-by
使 comparatorClass 个实
java.util.Comparator 算法
order-by
where
outer-join
指定方式。 (JDK1.4 以上版本有效) 应 SQL 中的 order by
与 sort 的 natural模式使 用。
数据选条件,如果库表中特定数据的时,可 此选项设
条件。 是使接。
true使outer-join false不使outer-join auto(默认) :如果联对
Proxy 机制使outer-join.
batch-size 采用延迟加特性Lazy Loading
次读入的数据数量。
处未延迟机制此此属性忽
Text N
Text N
Text N
Int N
access
一对多关系简单在一问题。由联,
了保持关系我们方对被动方进更新。且如果联方的
NOT NULLHibernate或者更新关关系时, 束违
我们有的用“Erica”添加一地址
Transaction tx = session.beginTransaction();
TAddress addr = new TAddress();
属性值的读取方式。
field property默认 ClassName
September 2, 2004 So many open source projects. Why not Open your Documents?
Text N
Hibernate Developers Guide Version 1.0
addr.setTel("1123"); addr.setZipcode("233123"); addr.setAddress("Hongkong");
user.getAddresses().add(addr);
session.save(user);//更新
tx.commit();
了完成这作,HibernateSQL成新t_address
:
1. save(user)时:
insert into t_address (user_id, address, zipcode, tel) values (null, "Hongkong", "233123", "1123")
2. tx.commit()
update t_address set user_id=1, address="Hongkong", zipcode="233123", tel="1123" where id=2
第一条SQL用入新的地址录。 条SQL用更新t_address,将 user_id为其联的user对的id值。
问题这里数据库中,我们t_address.user_idNOT NULL
Hibernate第一条语t_address时,试图user_id设为null是引发约束违例异常
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: org.hibernate.sample.TAddress.userId
联方关系TUser,而联的addr
知道自己与哪个TUser象相关联,也就是说,addr并不知道user_id
设为什么数值
,在保存addr时,先在段插,再TUser 将自id赋予字段addr.user_idaddr属性生变,在事务提时,hibernate发现一改变,并通update sql变动
到数据库
第一中,数据库的非段插值,致了约束违例。
既然TUser对象方,就不能好下TAddress对象Insert呢?莫妙?Hadont ask me ,go to ask
Hibernate TeamJ
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
我们设计的时过一些行调整避免约束违例,如将设为允许NULL值、直接采用数值型字(有的时调整不可 情况下我们必须针对现有数据库结构行开,或者关联属性
任意值(使这里通手工置了的user_id有意 hibernate动再用一条Update更新)
至我们被动方的关映射文件中除(如将user_id字 射从TAddress.hbm.xml除)。这Hibernate生成第一条insert的时 就不会包含这(数据库使默认填充,如:之后update语会根方的one-to-many映射配置中的关联字更新被动内容。在
这里中,如果将user_idTAddress.hbm.xml文件中 Hibernate数据生成SQL:
1. insert into t_address (address, zipcode, tel) values
('Hongkong', '233123', '1123')
2. update t_address set user_id=1 where id=7
生成第一条insert时,包含user_id数据库使值(如果有的填充因此引发约束违。之,根一条
id,update句对user_id段进更新。
是,纵使些权之计,由于Hibernate实机制中,SQL数据作,insert性能开效率较
系统承受
情况我们,如果addr知道如何获取user_id字段内容 那么执insert的时候直接数据可。约束违的可
还节省一条Update语句高了性
一对关系则解问题。它除了免约束违和提高性的好
外,来另外一点,由联,我们双方中任意一 方,访联的一方(如可TAddress对象直接访问关联的TUser对象), 丰富灵活的控制
Ø 双向一对多关系
向一对关系实际“单一对关系”对一关系”合。 是说我们必须配置一对关系基础上,在被控配置对一关系与其
配置:
我们已经大致完向方一对关系配置我们需在基础上做修 改,t_address)的相关属性进配置即可:
TUser.hbm.xml:
<hibernate-mapping>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
<class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true"
>
……
<set name="addresses" table="t_address" lazy="false" inverse="true" cascade="all" sort="unsorted" order-by="zipcode asc" >
<key column="user_id" > </key>
<one-to-many class="org.hibernate.sample.TAddress" /> </set> </class>
</hibernate-mapping>
这里与面不inverse被设为trueTUser 不方,是将关系维护作交给联对org.hibernate.sample.TAddress
。这TAddress 对象持久过程中,动获取其关联的 TUser iduser_idinsert 全部作。
one-to-many 关系中,将 many 一方设为动方inverse=false将有助
的改,如果胡锦涛
民知道胡锦涛,可就不需那么J
xdoclet tag 如下:
public class TUser implements Serializable {
…… private Set addresses = new HashSet();
……
/**
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
* @hibernate.collection-one-to-many * class="org.hibernate.sample.TAddress" * * @hibernate.collection-key column="user_id" * * @hibernate.set * name="addresses" * table="t_address" * inverse="true" * lazy="false"
* cascade=all
* sort="unsorted" * order-by="zipcode asc" */ public Set getAddresses() { return addresses; } …… }
TAddress.hbm.xml:
<hibernate-mapping>
<class name="org.hibernate.sample.TAddress" table="t_address" dynamic-update="false" dynamic-insert="false"
>
……
<many-to-one name="user"
class="org.hibernate.sample.TUser" cascade="none" outer-join="auto" update="true" insert="true" access="property" column="user_id" not-null="true" /> </class>
</hibernate-mapping>
TAddress 中新一个 TUser field user为其添加
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
getter/setter 删除原有user_id 性及其映射配置,否则运期会报重复映射错误Repeated column in mapping
Xdoclet tag:
public class TAddress implements Serializable {
…… private TUser user; …… /** * @hibernate.many-to-one * name="user" * column="user_id" * not-null="true" * */ public TUser getUser() { return this.user; } …… }
看上那段代码
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list();
TUser user =(TUser)userList.get(0);
Transaction tx = session.beginTransaction();
TAddress addr = new TAddress(); addr.setTel("1123"); addr.setZipcode("233123"); addr.setAddress("Hongkong");
user.getAddresses().add(addr);
session.save(user);//更新
tx.commit();
代码凄凉约束违
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
我们已配置了 TAddress many-to-one 关系么效……
不过提到inverse 属性这里我们TUser inverse 设为true”即指定由对方维护关关系,在这里是由 TAddress 维护关系
TUser 既然不再维护关系,那么 TAddress user_id 属性然不 必须TAddress 维护 user_id
……
TAddress addr = new TAddress();
addr.setTel("1123"); addr.setZipcode("233123"); addr.setAddress("Hongkong");
addr.setUser(user);//联的TUser
user.getAddresses().add(addr);
session.save(user);//更新
……
观察 Hibernate 行过程用的 SQL
insert into t_address (user_id, address, zipcode, tel) values (1, 'Hongkong', '233123', '1123')
我们所期的,条 Insert 行来
many-to-one 节点属性
描述 类型 必须
name column class
cascade
update
映射属性
类名 默认映射属性属类
cascade)关系
all : 所有情况作。 none:所有情况作。 save-update:save-update
作。 delete:在 delete 时进作。
行 Update
September 2, 2004 So many open source projects. Why not Open your Documents?
Text Y Text N Text N
Text N
Bool N
Hibernate Developers Guide Version 1.0
默认:true
insert
outer-join
property-ref
access
Insert 操 默认true
使 true使outer-join false不使outer-join auto(默认) :如果联对
Proxy 机制使outer-join.
于与主相关联的属性 默认主键属性名
这里我们过主键联,所 以采 可。如果并非建在主键之
此参指定属性 属性读取方式。
field property默认
Bool N
Text N
Text N
Text N
ClassName
关系差别
多关联
Hibernate 关联关系多对关联,多对关联一对一 联和一对多对多关联需另外一映射表用映射信息。
于多对多关联的能不(由于引中间表,一次读取操作需要反
,因设计该避使用。时,在对关系中,情况采取 延迟载(Lazy Loading 章节)机制来避免无能开
在一限管系统中,一常见的的映射关系就是 Group Role,Role Privilege 映射。
Ø Group ”(业务
Ø Role ”(“出”)
Ø Privilege 特定资源访问权修改
表”)
这里我们Group Role 映射例:
Ø Group 包含多个 Role,如个“业务管”“出
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Ø Role 于不Group
配置:
我们中,TRole TPrivilege 应数据库中的 t_role t_privilege 表。
TGroup.hbm.xml 于多联的配置
<hibernate-mapping>
<class name="org.hibernate.sample.TGroup" table="t_group" dynamic-update="false" dynamic-insert="false"
>
……
<set name="roles" table="t_group_role" lazy="false" inverse="false" cascade="save-update" >
<key column="group_id"
> </key>
<many-to-many class="org.hibernate.sample.TRole" column="role_id" /> </set>
</class>
</hibernate-mapping>
① 这为 t_group 和 t_role 之间的映射
般情况下,cascade 应该置为save-update,对于多逻辑
而言很少出现删除一方需要删除所有关联数据的情况删除
Group,一般不会删除其中包含的 Role(这Role 被其 Group 所引用)之删除 Role 般也不会删除关联所有 Group
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
映射表中对于 t_group 表记录的标识字段。
映射中对于 t_role 表记录的段。
xdoclet tag 如下:
public class TGroup implements Serializable {
…… private Set roles = new HashSet(); /** * @hibernate.set * name="roles" * table="t_group_role" * lazy="false" * inverse="false" * cascade="save-update" * sort=unsorted
*
* @hibernate.collection-key * column="group_id" * * @hibernate.collection-many-to-many * class="org.hibernate.sample.TRole" * column="role_id" * */ public Set getRoles() { return roles; } …… }
TRole.hbm.xml 于多联的配置
<hibernate-mapping>
<class name="org.hibernate.sample.TRole" table="t_role" dynamic-update="false" dynamic-insert="false"
>
……
<set
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
name="groups" table="t_group_role" lazy="false" inverse="true" cascade="save-update" sort="unsorted" >
<key column="role_id" > </key>
<many-to-many class="org.hibernate.sample.TGroup" column="group_id" outer-join="auto" /> </set> </class>
</hibernate-mapping>
xdoclet 如下:
public class TRole implements Serializable {
private Set groups = new HashSet();
…… /** * * @hibernate.set * name="groups" * table="t_group_role" * cascade="save-update" * inverse="true" * lazy="false" * * @hibernate.collection-key * column="role_id" * * @hibernate.collection-many-to-many * class="org.hibernate.sample.TGroup" * column="group_id" * *
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
*/
public Set getGroups() { return groups; } }
many-to-many 节点属性描述
描述 类型 必须
column class
outer-join
映射表中,关联标表的关联字段。
类名
类。 使接。
true使outer-join false不使outer-join auto(默认) :如果联对
Proxy 机制使outer-join.
Text Y Text Y
Text N
使
关系中,由于关系引用,状态必须
public void testPersist(){
TRole role1 = new TRole();
role1.setName("Role1");
TRole role2 = new TRole();
role2.setName("Role2");
TRole role3 = new TRole();
role3.setName("Role3");
TGroup group1 = new TGroup();
group1.setName("group1");
TGroup group2 = new TGroup();
group2.setName("group2");
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
TGroup group3 = new TGroup();
group3.setName("group3");
group1.getRoles().add(role1);
group1.getRoles().add(role2);
group2.getRoles().add(role2);
group2.getRoles().add(role3);
group3.getRoles().add(role1);
group3.getRoles().add(role3);
role1.getGroups().add(group1);
role1.getGroups().add(group3);
role2.getGroups().add(group1);
role2.getGroups().add(group2);
role3.getGroups().add(group2);
role3.getGroups().add(group3);
try {
Transaction tx = session.beginTransaction();
//关系必须时对方进
session.save(role1);
session.save(role2);
session.save(role3);
session.save(group1);
session.save(group2);
session.save(group3);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
代码3 TGroup 对象和 3 TRole 对象,并关系
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
数据访问
PO VO
PO Persistence Object VO Value Object
PO VO Hibernate 概念
先,何VO,简单,VO是一简单。 如:
TUser user = new TUser();
user.setName("Emma");
这里user 是一VO。VO 只是简单了对的一些属性信息
PO? Hibernate 框架中的 VO。子:
TUser user = new TUser(); TUser anotherUser = new TUser();
user.setName("Emma"); anotherUser.setName("Kevin");
//useranotherUserVO
Transaction tx = session.beginTransaction(); session.save(user);
//时的user经经过Hibernate个PO //anotherUserVO
tx.commit();
//表中一条用Emma //anotherUser无任何
Transaction tx = session.beginTransaction(); user.setName("Emma_1"); //PO anotherUser.setName("Kevin_1");//VO
tx.commit();
//PO状态被固到数据库 //是说数据库Emma的用更新“Emma_1
//anotherUser普通Java属性 //数据库任何影响
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
另外Hibernate的对PO:
//HibernatePO
TUser user = (TUser)session.load(TUser.class,new Integer(1));
VO经过HibernatePO 示例代码session.save(user)中,我们VO “user HibernateSession.save。在save中,Hibernate 如下
1前session所对(Entity Mapuser
的引用。
2如果引用在,则直接回useridsave过程束.
Hibernate中,个Session有一个实实际是一个Map象)
如果此容已经了目的引用,那么hibernate会认已经Session相关联。
save操作如果对经与Session相关即已被加Session),则无需进体的操作。后的Session.flush过程中,
Hibernate中的对象查找出体,生成相应update语
3如果引用在,据映射关系行insert作。
a) 我们这里示例中,nativeid生成机制此hibernate
从数据库得insert生成的id赋予userid属性
b) user的引用Hibernate c) save过程id.
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Session.load方中,回对前,Hibernate其实中。
VOPO主要
Ø VOJava Object
Ø PO是由Hibernate其实Entity Map的对
据库Hibernate实体,PO在事时将反应到实数据库中。
如果一POSession容器中分SessionPO那么时,又会VO
POVO概念一些系统设计的问题。如在传MVC中, 位于Model层PO,是到 其 层面。由于PO更新映射到实 际数据库中,如果PO在其层面View层变动那么可能Model破坏
,一直接PO到系统中的其层面,一种解是,VO通过属性复制使其PO同属性并以其为质(实际上 VO用作Data Transfer ObjectDTO,将VO给其 面以实必须数据
属性复制以通Apache Jakarta Commons Beanutilshttp://jakarta.apache.org/commons/beanutils/件提属性
量复制能,的get/set作。中,我们把user对的所有属性复制到anotherUser对中:
TUser user = new TUser();
TUser anotherUser = new TUser();
user.setName("Emma");
user.setUserType(1);
try {
BeanUtils.copyProperties(anotherUser,user);
System.out.println("UserName => "
+anotherUser.getName() );
System.out.println("UserType => "
+ anotherUser.getUserType() );
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
关于 unsaved-value
数据存时,Hibernate将据这判断对要保存。
,是代码中明session 的 save、update、saveOrupdate方
对对行持久如:
session.save(user);
情况下,如映射关系中,Hibernate Cascade)关系对联
代码联对,需Hibernate 象当
态判断要保存到数据库时,Hibernate unsaved-value
Hibernate 取出对象的 id
,将此 值 unsaved-value ,如果为目标
,无需作。
如:user前由 hibernate 从数据库获取时,user
联对address 被加此时我们向 user 对象新增一address 对
session.save(user)hibernate 会根据 unsaved-value 判断 user 对象address联对象中,些需save 作,
我们的 address ,由于其 idInteger 型)
null我们的 unsaved-valuenull)相hibernate
,将为其生成 insert
这里会产问,如果“原有”关联对象发生变动(user 个“原有
address 属性,所 谓“ 原有即此 address 已经与 user 相关联, 而不我们过程增的id 从数据库有发,自然unsaved-valuenull也不那么 Hibernate 是不是就不
POVO 讨论曾经涉到数据问题,实际这里
实际insert概念新关联对的加,而非数据库中原有联对
update”。所谓新关联对,一情况下可以理解为Session 发生关联的 VO原有”关联对象,则是 PO。如上POVO 中所
save而言如果对经与Session相关即已加入Session
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
无需进行具体的作。为之Session.flush过程中,Hibernate中的对,查找变化体,生成并相应update
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Inverse Cascade
Inverse“反。在 Hibernate 语义中,Inverse 指定了关系中的
关系中,inverse=false为主方,由责维护关系。具体可
见一对关系中的描述
Cascade译为,表明对关系,如 TUser Cascade 设为 all
表明如果发user 作,需 user 联的对进行作。如对 user 执行 save 作,必须user 象相关联的 address 执行 save 作。
常常混淆 inverse cascade,实际两个相关概念Inverse
的是关系控制cascade 的是级之间作。
延迟加载(Lazy Loading
免一些情况下,关系的无能开Hibernate延迟 概念 如,示例user在加的时会同读取联的多个地址(address address作的逻辑数据的自机制非常
是,如果我们是想user性别sex属性而不user地址address
信息那么address特性得多费。user
性别属性我们可能还要同从数据库读取条无用的地址数据这导致了大系统
延迟特性现,正是个问题。
延迟是在需数据的时真正数据加载作。
我们这里user对的加过程就意,加 user对只针对其本属性,
而当我们获取user联的address信息user.getAddresses 真正从数据库中加address据并
我们将前一对关系中的lazy属性修改为true即指定了联对延迟
<hibernate-mapping>
<class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true"
>
……
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
<set name="addresses" table="t_address"
lazy="true" inverse="false" cascade="all" sort="unsorted"
order-by="zipcode asc"
> <key column="user_id" > </key>
<one-to-many class="org.hibernate.sample.TAddress" /> </set> …… </class>
</hibernate-mapping>
行以代码
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list(); TUser user =(TUser)userList.get(0);
System.out.println("User name => "+user.getName());
Set hset = user.getAddresses();
session.close();//Session
TAddress addr = (TAddress)hset.toArray()[0];
System.out.println(addr.getAddress());
LazyInitializationException - Failed to lazily initialize a
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
collection - no session or session was closed
如果我们做调整,将session.close在代码末尾生这的问题。
我们实际加载user关联的address时,Hibernate试图
session从数据库中加实际数据我们读取address session,所session的错误。
这里问题,如果我们采延迟加载机制希望在一些情况下,现非延迟
时的是说,我们希望Session关useraddresses
属性。如,了向View数据我们必须User包含联的 address信息User必须Session以使用。
Hibernate.initialize载关联对
Hibernate.initialize(user.getAddresses());
session.close();
//Hibernate.initialize制读取数据
//addresses脱离session
Set hset= user.getAddresses(); TAddress addr = (TAddress)hset.toArray()[0]; System.out.println(addr.getAddress());
延迟机制hibernate包括JDK
Collection现。
如果我们HashSetHibernate的Set
Set hset = (HashSet)user.getAddresses();
会在到一java.lang.ClassCastException,实际上,此时的是
Hibernate的特定Set实现net.sf.hibernate.collection.Set”对义上的JDK Set现。
我们编写POJO时,必须JDK CollectionSet,Map,
特定JDK CollectionHashSetHashMapCollection属性
到前TUser类的义:
public class TUser implements Serializable {
……
private Set addresses = new HashSet();
……
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
} 我们过Setaddresses属性个HashSet
addresses便我们TUser以为其联的address
TUser user = new TUser();
TAddress addr = new TAddress(); addr.setAddress("Hongkong"); user.getAddresses().add(addr);
session.save(user);
时,这里的addresses属性还是一HashSet对其中包含了一address
的引用。那么当调session.save(user)时,Hibernate是如何HashSet
属性呢?
EclipseDebug我们以看到session.save法执前后user对象发
session.save前的user
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
session.save方的user对 可以看到,user通过Hibernate已经先,由于insert操作,Hibernate获得数据库id值(我们的中,
native方式的主键生成机制),填充user对的id属性。解。
一方Hibernate使用Collection实现
net.sf.hibernate.collection.Setuser中的HashSetaddresses属性进
数据对其进行填充保证addresses与原有的addresses包含元素
有自Collection实现,Hibernate就Collection
延迟特性有程真正读取这个Collection时,才激底层实际据库作。
管理
Hibernate JDBC 封装,本理能力。在事理层
Hibernate 委托给底层JDBC 或者 JTA以实现事调度
Hibernate 默认务处机制JDBC Transaction我们也配置
定采JTA 理实现:
<hibernate-configuration>
<session-factory>
……
<property name="hibernate.transaction.factory_class">
net.sf.hibernate.transaction.JTATransactionFactory
<!--net.sf.hibernate.transaction.JDBCTransactionFactory-->
</property>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
……
</session-factory>
</hibernate-configuration>
JDBC 管理
将事委托JDBC 进是最简单的方式,Hibernate 对JDBC
封装简单。
我们代码
session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); …… tx.commit();
JDBC 层面而代码实际
Connection dbconn = getConnection(); dbconn.setAutoCommit(false); …… dbconn.commit();
简单Hibernate 没有多的事实际的事
是将JDBC 代码进封装
这里要注意的是,在 sessionFactory.openSession()中,hibernate 始化
数据库此同时,将AutoCommit 设为状态false)而其,在
Session.beginTransaction 中,Hibernate 再次Connection AutoCommit 属性设为状态代码session Connection.AutoCommit 属性修改
是说,我们开始SessionFactory session属性
AutoCommit=false,下代码不会数据库产任何果:
session = sessionFactory.openSession(); session.save(user); session.close();
实际上相当于 JDBC Connection AutoCommit 属性设为 false
JDBC 操作后,commit 操作Connection 闭。
如果使代码真正作用到数据库,我们必须式的Transaction 令:
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); session.save(user); tx.commit();
session.close();
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
JTA 管理
JTA Session 的事务管理能力JDBC Transaction
JDBCConnnection 理,就是说,事 理实际是在 JDBC Connection
现。事 Connection 命周期之类样,对 JDBC TransactionHibernate 机制言,事理在 Session 依托的 JDBC Connection现,事Session 命周期。
JTA 管理 JTA 现,JTA 前加众多 Connection
行调度性要求。JTA 的事期可横跨多个 JDBC Connection 命周期。
样对JTA 事Hibernate 言,JTA 横跨横跨多个 Session。
的说明问题:
描述的是 JDBC Connection 关系Hibernate Session
这里JDBC Connection 逻辑含义
从上我们看出JTA 是由 JTA Container 维护
Connection 无需对事这也是说,如果JTA Transaction,我Hibernate Transaction
JDBC Transaction 代码这里就会产问题:
public class ClassA{
public void saveUser(User user){
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); session.save(user); tx.commit();
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
session.close();
}
}
public class ClassB{
public void saveOrder(Order order){
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); session.save(order); tx.commit();
session.close();
}
}
public class ClassC{
public void save(){ ……
UserTransaction tx = new InitialContext().lookup(“……”); ClassA.save(user); ClassB.save(order); tx.commit();
…… }
}
这里ClassA 和 ClassB,分 saveUser 和 saveOrder
信息和订信息。在 ClassC 中,我们调用ClassA.saveUser ClassB.saveOrder 时引JTA 中的 UserTransaction 以实现 ClassC.save 中的事
问题ClassA 和 ClassB 中分Hibernate 的 Transaction
。在 Hibernate JTA 封装中,Session.beginTransaction InitialContext.lookup法获取 UserTransaction,Transaction.commit 了 UserTransaction.commit 实际嵌套式的 JTA TransactionClassC ClassC ClassA ClassB 明自的事致运期错误。
,如果定采JTA Transaction再重复用 Hibernate
Transaction 代码修改如下:
public class ClassA{
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
public void save(TUser user){
session = sessionFactory.openSession(); session.save(user); session.close();
} ……
}
public class ClassB{
public void save (Order order){
session = sessionFactory.openSession(); session.save(order); session.close();
} ……
}
public class ClassC{
public void save(){ ……
UserTransaction tx = new InitialContext().lookup(“……”); classA.save(user); classB.save(order); tx.commit();
…… }
}
代码中的 ClassC.save 成这
public class ClassC{
public void save(){ ……
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
classA.save(user); classB.save(order);
tx.commit();
…… }
}
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
实际是利Hibernate 启动和提UserTransaction
原本直接通InitialContext 获取 UserTransaction 法消
资源,得不偿
EJB 中使用 JTA Transaction 无简便我们只需要将 save 方配置
JTA 务支即可,无需明任何事,下是一Session Bean save
的事属性“RequiredEJB 将自动维护法执行过程中的事
/**
* @ejb.interface-method * view-type="remote" * * @ejb.transaction type = "Required"
**/
public void save(){
//EJB环境中,配置即现事明,无需用事
classA.save(user); classB.save(log);
}//时,如果EJB
locking
业务逻辑过程中,往往要保证数据访问的排他。如在系统的日
中,我们希望针cut-off 数据行处理而不希望结算行过程 数据时,我们一些机保证数据过程修改,机制,在这里是所
我们选定标数据上使其法被修改。
Hibernate 锁机制通常所说的(Pessimistic Locking)”
Optimistic Locking)”
悲观锁(Pessimistic Locking
的是对数据被外(包括系统当前的
系统的事务处修改持态度,在整个数据理过程中,将数据处于锁 状态的实现,往往依靠数据库锁机制数据库层锁机制才能
真正保证数据访问的排他使在本系统锁机制保证部系修改数据)。
典型倚赖数据库用: select * from account where name=Erica for update
sql 定了 account 表中所有条件name=Erica
释放事过程中的修改
Hibernate 的数据库的锁机制现。 代码的加
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
String hqlStr = "from TUser as user where user.name='Erica'"; Query query = session.createQuery(hqlStr);
query.setLockMode("user",LockMode.UPGRADE); //
List userList = query.list();//获取数据
query.setLockMode 中,特定别名所对我们 TUser 类指定了别名“user”)这里是对的所有 user
观察期 Hibernate 生成SQL
select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name='Erica' ) for update
这里 Hibernate 过使数据库的 for update 锁机制
Hibernate 的加式有:
Ø LockMode.NONE 锁机制 Ø LockMode.WRITE :Hibernate 在 Insert 和 Update 的时
获取
Ø LockMode.READ : Hibernate 读取记的时动获取
上这锁机制Hibernate内使用,如 Hibernate 为了保证 Update
过程中对修改,save 法实现中自动为目WRITE
Ø LockMode.UPGRADE 数据库for update Ø LockMode. UPGRADE_NOWAIT Oracle 特定现,Oracle for
update nowait 现加 锁机制我们用的,加过以下方现: Criteria.setLockMode Query.setLockMode Session.lock 意,有在询开始之Hiberate 生成 SQL
真正数据库锁机制锁处数据已过不包含 for updateSelect SQL ,所谓数据库锁也
乐观锁(Optimistic Locking
对悲,乐锁机制加宽的加锁机制。悲大多情况下依数据库锁机制现,保证操作最大程度的独占而来数据库
能的销,特别是对言,样的往往无承受
如一系统操作读取户的数据,并在出的用数据础上进
修改时改用,如果机制整个过 程(从出数据、开修改提交修改果的全过程,至还包括 煮咖啡的时间数据库处于锁状态,可以见,如果
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
上千发,情况致怎果。
锁机制在一程度上解问题。乐大多数据版本
Version)记录机制现。何谓数据版本为数据增加一版本标,在基 数据库表的版本中,一是 通过为数据库表增加一个“version”字
现。
读取出数据时,将版本后更新时,对版本加一。时,将提
数据的版本数据据库表对前版本信息比对,如果提数据 版本大于数据库表前版本更新,为是过期数据
修改用信息数据库信息表中有一
version 1而当balance$100
1 A 时将出(version=1并从$50
$100-$50
2 A 作的过程中,员 B 信息version=1
除$20$100-$20
3 A 修改作,将数据版本加一version=2
balance=$50,提交数据库更新时由数据版本数据库录当前版本,数据更新数据库version 更新为 2
4 作员 B 完成了操作,将版本加一version=2试图向数据库
据(balance=$80)对数据库版本时发现,B 数据版本2数据库前版本2满足“版本必须大于前版本更新“作员 B 的提了操作员 B 用基version=1 数据修改的覆盖A 果的可
从上看出锁机制避中的数据库加销(作员 A B 过程中,有对数据库数据大大下的表现。
要注意的是,锁机制往往系统中的数据存储逻辑此也具备,如在中,由锁机制是在我们系统现,系统的用
额更新我们系统控制数据更新到数据库中。在 系统设计我们应考虑到这情况出现的可,并进相应调整( 数据库存储过程现,对 放 基 存储过程数据更新途 径而不是将数据库直接开)
Hibernate 其数据访问引置了现。如果考虑部系统 据库更新作,Hibernate 现,将大大我们
Hibernate 中可class 描述optimistic-lock 属性结合 version 描述指定
现在,我们之前示例中的 TUser 加锁机制。
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
1. 首TUser class 描述optimistic-lock 属性
<hibernate-mapping>
<class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true" optimistic-lock="version"
> …… </class>
</hibernate-mapping>
optimistic-lock 属性有如下可
Ø none
Ø version
版本机制
Ø dirty
变动属性
Ø all
所有属性
version 实现的锁机制Hibernate 官推荐锁实现,
Hibernate 中,前唯一在数据脱离 Session 修改的情况有效锁机,一情况下,我们version 方式作Hibernate 观锁机制
2加一个 Version 属性描述
<hibernate-mapping>
<class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true" optimistic-lock="version" >
<id name="id" column="id" type="java.lang.Integer" > <generator class="native">
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
</generator> </id>
<version column="version" name="version" type="java.lang.Integer" />
…… </class>
</hibernate-mapping>
注意
version
这里我们个 version 属性,用 的版本信息在 TUser 表的
version 中。
时如果我们编写代码更新 TUser 表中录数据,如:
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list(); TUser user =(TUser)userList.get(0);
Transaction tx = session.beginTransaction();
user.setUserType(1); //更新UserType
tx.commit();
每次TUser 进行更新的时我们可以发现,数据库中的 version 增。
如果我们tx.commit 前,动另外一个 Session,对名为 Erica 的用
作,以模更新时的
节点必须出现在ID节点之后。
Session session= getSession(); Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("name","Erica"));
Session session2 = getSession(); Criteria criteria2 = session2.createCriteria(TUser.class); criteria2.add(Expression.eq("name","Erica"));
List userList = criteria.list(); List userList2 = criteria2.list();
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
TUser user =(TUser)userList.get(0); TUser user2 =(TUser)userList2.get(0);
Transaction tx = session.beginTransaction();
Transaction tx2 = session2.beginTransaction();
user2.setUserType(99);
tx2.commit();
user.setUserType(1);
tx.commit();
行以上代码代码将在 tx.commit()抛出 StaleObjectStateException
版本前事试图个过数据。通捕捉常, 时进行相应
Hibernate 分页
数据,在系统现中往往带来较大,对于JDBC 的程
数据库提供的分部分读取)模往往各不相带来数据库间
问题。
Hibernate 中,数据库设计的分
机制
我们Criteria.setFirstResult Criteria.setFetchSize
范围,如:
Criteria criteria = session.createCriteria(TUser.class); criteria.add(Expression.eq("age","20"));
//索结果中获取10020 criteria.setFirstResult(100);
criteria.setFetchSize(20);
,Query 与其的方
Hibernate 中,类 net.sf.hibernate.dialect 指定了所有底层数据库的对
数据库相应dialect 现,数据库之得以而为机制明的、数据库存储基础
机制 dialect 如下:
Public String getLimitString(
String querySelect,
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
boolean hasOffset )
在现有 Select 基础上数据库特性
定子。如 MySQL 中对定子Limit,而 Oracle 中,可通 过 rownum
现。
我们MySQLDialect 中的 getLimitString 现:
public String getLimitString(String sql, boolean hasOffset) {
return new StringBuffer( sql.length()+20 ) .append(sql) .append( hasOffset ? " limit ?, ?" : " limit ?") .toString(); }
从上看到,MySQLDialect.getLimitString 实际是在
Select MySQL 所提SQL limit 来实现。
Oracle9Dialect 中的 getLimitString 现,过 Oracle 有的
rownum 数据的部分读取
public String getLimitString(String sql, boolean hasOffset)
{ StringBuffer pagingSelect =
new StringBuffer( sql.length()+100 );
if (hasOffset) { pagingSelect.append(
"select * from ( select row_.*, rownum rownum_ from ( "
);
}else { pagingSelect.append("select * from ( "); } pagingSelect.append(sql); if (hasOffset) { pagingSelect.append(
" ) row_ where rownum <= ?) where rownum_ > ?"
);
}else { pagingSelect.append(" ) where rownum <= ?"); } return pagingSelect.toString(); }
大多数据库了数据部分读取机制有提相应机制数据
Hibernate 也通过其途径,如通Scrollable ResultSet,如
JDBC Scrollable ResultSetHibernate 也会ResultSet next Hibernate 过底层对分机制封装使得开
人员无需数据现,将数据逻辑存储逻辑开来,在提效率
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
时,也大大强了系统不同数据库平台的可植性
Cache 管理
Cache 往往是提系统的最的手。在 中,DOS 时代 SmartDrv2所磁盘读写历历目(95Windowns 3.0,在 SmartDrv情况下,15 钟左右加载SmartDrv2 完成
整个过程
Cache 于大倚赖数据读取作的系统言(典型的,如 114 系统)
情况下,如果每次要向数据库直接做查询操作,所能开见,的网络传输、数据库磁盘大多数数据库身也Cache使访数据库销也大大低了系统体性
时,如果数据在本地中保镜像,下次访问时直接获取
那么然可著的倍,十倍的整体读取能提).
Cache 机制的是如何保证存中数据的有数据的出现将系统
果。
Hibernate 好的 Cache 机制我们Hibernate 部的 Cache 迅速系统数据读取
需要注意Hibernate 做为用级数据访封装作用范围Cache 数据的的有是说,在我们的系统系统共享数据库情况
下,Hibernate Cache 机制失效
Hibernate 在本JVM 维护缓冲池从数据库数据
以供次重复使(如果在 Hibernate 中数据变动,Hibernate 也会更新 中的数据版本
时,如果有第系统数据库进改,那么Hibernate 知道数据库数据经发化,也就是说,中的数据是修改之前的版本,下次读取时,
Hibernate 数据返回给代码致潜在的问题。
系统并非限于系统之外的第系统即使在本系统中,如果
Hibernate 数据存储机制数据存取那么 Cache 的有性也必须。如,在系统中,Hibernate JDBC 种数据访方式,那么
JDBC 更新数据库的时Hibernate 法获知数据更新情况现。
Java Cache 现,最简单的过于 HashTablehibernate 了基
Hashtable Cache 实现机制,不过,由于其上的供开发调试使 用。时,Hibernate 还提向第Cache 现的,如 JCS、EHCache、
OSCacheJBoss CacheSwarmCache
Hibernate 中的 Cache ,第一Cache Session 现, 数据缓冲,一个 Cache 失效Cache 为内现,无需我们
2
DOS 下的磁盘缓冲
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Cache,是 Hibernate 中对其实范围内的数据理容器。也是
这里我们讨题。
Hibernate 期版本中JCSJava Caching System Apache Turbine
项目中的一项目)作默认的第Cache 现。由 JCS 的发展停顿,其内 的一些问题(在情况下,可 版本的 Hibernate 经将
JCS ,并EHCache 为其默认的第Cache 现。
JCSEHCache 更好的调度缺陷做到
,如果我们系统共享数据库必须使Cache 实JCSJBossCache)以现不系统实之间数据情况
Hibernate Cache 进行封装Cache 机制使得我们上层结构现中无需面对Cache 维护
Hibernate 支持Cache 实现有:
名称 集群支持
HashTable
EHCache OSCache SwarmCache
JBossCache
中 SwarmCache JBossCache Cache
(:最版本的 OSCache 现。)
SwarmCache 的是 invalidation 方式的分中的 节点更新中的数据中的节点数据节点需要
到这数据的时新从数据库入并填充中。
JBossCache 提供的是 Reapplication 式的缓冲如果集群某个节点数据
此节点会将发数据的最版本复制中的个节点以保所有 节点状态
使用第Cache,需 要 hibernate.cfg.xml 配置下参数( EHCache
net.sf.hibernate.cache.HashtableCacheP rovider
net.sf.ehcache.hibernate.Provider N Y net.sf.hibernate.cache.OSCacheProvider N Y net.sf.hibernate.cache.SwarmCachePro
vider net.sf.hibernate.cache.TreeCacheProvid
er
N Y
Y
Y
查询缓冲
<hibernate-configuration>
<session-factory> ……
<property name="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.Provider
</property>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
……
</session-factory>
</hibernate-configuration>
另外对 Cache 现本配置,如 EHCache 配置文件:
<ehcache>
<diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" //Cache中最数据数 eternal="false" //Cache数据 timeToIdleSeconds="120" //数据 timeToLiveSeconds="120" //数据 overflowToDisk="true" //时,是磁盘缓 />
</ehcache>
//开始加,实际配置文件中应出现。
,需要在我们映射文件中指定各映射体的 Cache
<class name=" org.hibernate.sample.TUser" .... >
<cache usage="read-write"/>
....
<set name="addresses" .... >
<cache usage="read-only"/>
....
</set>
</class>
缓冲描述cache 可用描述映射属性
中,Class 节点下的 cache 描述指定了TUser read-write”缓冲中的 TUser 可写,集合属性 addresses
只读
cache usage
1read-only
只读
2read-write
3nonstrict-read-write
如果数据修改非常偶尔更新数据,可用 本查,好的性能。
4transactional
cache。在事Cache 中,Cache 的相关操作也添加到事之中, 如果由务失我们缓冲池中的数据 始之前的状态。Hibernate 置的 Cache 中,JBossCache
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Cache 现。
Cache 现,usage 也各
名称
HashTable Y Y Y EHCache Y Y Y
OSCache SwarmCache JBossCache
配置Cache 后,Hibernate 在Cache 机制,就是说,我们PO 的更新会自同步Cache 中数据的读取也会自化的Cache 中 获取,对逻辑代码,有Cache 机制么影响
要注意的是 Hibernate 的数据库机制我们果中出数据的时, 用的最的是法:
Query.list();
Query.iterate();
list 而言实际上 Hibernate 是通一条 Select SQL 获取所有的入到 POJO
iterate 一条 Select SQL 获取所有条件的 idid 作,Select SQL id 所对
,之POJO
是说,对list 作,需要一条 SQL iterate 作,需要 n+1
SQL
看上iterate 法似有些情况的功,如对数据,如果用 list 次取法承受
一方,对 于 我们现在的 Cache 机制list 将不Cache 读取数据
它总是一从数据库直接所有条件的而 iterate 法因每次 id 获取数据机制就为从 Cache 读取数据,hibernate
据这id 在本Cache 对应数据,如果找到去数据库检索。如果设计中对 Cache ,则请编码中这的应,有的改 代码,最大程度升系统现。
内容Hibernate 通Cache 封装,对 上 逻辑层而言Cache
read-only read-write nonstrict-read-write transactional
Y Y Y Y Y Y Y
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
现,程序员编码无需数据Cache 中的状态调度效率
Session 管理
Session 是 Hibernate 运作的,作 贯穿 Hibernate 应用的Session
包含数据库操作相关的状态信息。如对 JDBC Connection 维护,数据体的状态维
Session 进的意JDBC 设计中对JDBC Connection 的
。有Session 机制,Hibernate 设计
大多情况下,Session 管理聚焦的设计,Session
JVM 垃圾收,保证系统效平行。
Session 理方案中, ThreadLocal 模式得使用。ThreadLocal 是
Java 中一为特线绑定机制ThreadLocal 存取数据与当前线相关是说,JVM 个运行的线定了有的本地例存取而为多线程环境常出
现的访问问题提机制
先,我们知道SessionFactory 创建 SessionSessionFactory 线
全的,多个线访问一个 SessionFactory 并从获取 Session Session 并非线全,是说,如果多个线使用一个 Session 数据存取
Session 数据存取逻辑。下是一典型Servlet我们试图 变量 session Session 的重用,每次
public class TestServlet extends HttpServlet {
private Session session;
public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
session = getSession(); doSomething(); session.flush(); }
public void doSomething(){
......//session存取
}
}
代码看上无误,我们的时问题,
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
译部实际环境中,而来的错误使得我们头脑。 问题
先,Servlet 运行线的,并不线程Servlet
也就是说,TestServlet 有一个实Tomcat 中是,其
务器不同个实例会多个线用,doGet 法也线用,可每次doGet 一的 TestServlet
session 变量都被重置,线A 的行过程中,他的线程如果被执那么 session 的引用将发线A session,可时的 session 与其前所用的
session 就不,错误就不
ThreadLocal 现,使得问题迎刃 我们一些小小的修改:
public class TestServlet extends HttpServlet {
private ThreadLocal localSession = new ThreadLocal();
public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
localSession.set(getSession()); doSomething(); session.flush(); }
public void doSomething(){ Session session = (Session)localSession.get();
......//session存取
}
}
以看到localSession 是一ThreadLocal 类型的对,在 doGet 中,我们
过其 set 获取session doSomething 中,get 法取session
ThreadLocal 特之线维护有的变量实际上
其实现原是在 JVM 维护MapMap key 前的线value 线ThreadLocal.set 的对当线程调ThreadLocal.get 时,
ThreadLocal 会根据线对象的引用,取出 Map 中对应的对
ThreadLocal 通过以线对象的引用作分,从同线变量
到上ThreadLocal 机制线程 A session 实例只能为线A
所用,,其线程session 实也各线我们就实了线
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
全的 Session 共享机制
Hibernate 示例中,提ThreadLocal 维护 Session 的好
public class HibernateUtil {
private static SessionFactory sessionFactory;
static { try { // Create the SessionFactory sessionFactory = new
Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) { throw new RuntimeException(
"Configuration problem: " + ex.getMessage(),
ex
); } }
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException
{ Session s = (Session) session.get(); // Open a new Session, if this Thread has none yet if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; }
public static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); } }
代码中,要借具类获取 Session 我们以实线范围
Session 共享线毁 Session 不过意在线 闭 Session
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
一提的是,版本的 Hibernate 在处Session 的时经内置了延迟
,只有在真正生数据库的时从数据库获取数据库我们不必过于
Session 共享会导整个线程生命周内数据库续占用。
HibernateUtil 以应在任何类型Java 中。特别的,对Web
我们Servlet2.3 的 Filter 机制轻松线命周 Session (关Filter 描述,请Servlet2.3
Filter命周贯穿覆盖Servlet(JSP作是一Servlet)
其底层对Filter 在 Servlet 调用行,在 Servlet 调用后结束。此,Filter 中Session 对Web 成。下是一Filter 进 Session 典型例:
public class PersistenceFilter implements Filter
{ protected static ThreadLocal hibernateHolder = new ThreadLocal();
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { hibernateHolder.set(getSession());
try
{
……
chain.doFilter(request, response);
……
} finally { Session sess = (Session)hibernateHolder.get(); if (sess != null) { hibernateHolder.set(null);
try { sess.close(); } catch (HibernateException ex) {
throw new ServletException(ex);
} } } }
……
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
}
doFilter 获取Session在周的所有对象(Filter
Filter,及其覆盖Servlet 象)Session 用,保证了
Http Request 理过程中用一Session,提高了表现。
实际设计中,Session 的线级别一够,HttpSession
现用Session 用反他的问题。凡事不能过火,Session 重用一样。J
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
Hibernate in Spring
下面主要就HibernateSpring中的用加以介绍关于Spring Framework另外
Springhttp://www.xiaxin.net/Spring_Dev_Guide.rar
Spring于Spring Framework
发中,尽使管理,以数据逻辑代码的最。下面 的介绍中,将 代码控制的事管理部分,而的容用。代码管理实
现原Spring中的相关内容
先,Hibernate我们如下配置
Hibernate-Context.xml:
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"> <value>net.sourceforge.jtds.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value> </property> <property name="username"> <value>test</value> </property> <property name="password"> <value>changeit</value> </property> </bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean"
>
<property name="dataSource"> <ref local="dataSource" /> </property> <property name="mappingResources"> <list> <value>net/xiaxin/dao/entity/User.hbm.xml</value> </list> </property> <property name="hibernateProperties">
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
<props> <prop key="hibernate.dialect"> net.sf.hibernate.dialect.SQLServerDialect </prop> <prop key="hibernate.show_sql"> true </prop> </props> </property> </bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionMana ger">
<property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO"> <property name="sessionFactory"> <ref local="sessionFactory" /> </property> </bean>
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.TransactionPro xyFactoryBean">
<property name="transactionManager"> <ref bean="transactionManager" /> </property>
<property name="target"> <ref local="userDAO" /> </property>
<property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
</beans>
中:
1 SessionFactory配置
HibernateSessionFactory维护SessionSpring SessionFactory配置也,无需Hibernate.cfg.xml SessionFactory行设
SessionFactory节点mappingResources属性包含映射文件的,list 节点下可配置多个映射文件。
hibernateProperties节点所有的属性配置
Hibernate.cfg.xml文件结构这里SessionFactory配置
2 采用Hibernate的TransactionManager现:
org.springframework.orm.hibernate.HibernateTransactionManag
er
这里非常简单表:Users如下映射 User.java:
/**
* @hibernate.class table="users" */
public class User {
public Integer id;
public String username;
public String password;
/** * @hibernate.id * column="id" * type="java.lang.Integer" * generator-class="native" */ public Integer getId() { return id; }
public void setId(Integer id) { this.id = id;
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
}
/** * @hibernate.property column="password" length="50" */ public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
/** * @hibernate.property column="username" length="50" */ public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; } }
代码中,过 xdoclet 指定了类/属性/映射关系过 xdoclet ant task 我们据代码生成user.hbm.xml 文件。
生成user.hbm.xml
<hibernate-mapping>
<class
name="net.xiaxin.dao.entity.User"
table="users" dynamic-update="false" dynamic-insert="false" >
<id
name="id"
column="id" type="java.lang.Integer" >
<generator class="native"> </generator> </id>
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
<property
name="password"
type="java.lang.String" update="true" insert="true" access="property" column="password" length="50" />
<property
name="username"
type="java.lang.String" update="true" insert="true" access="property" column="username" length="50" />
</class>
</hibernate-mapping>
UserDAO.java:
public class UserDAO extends HibernateDaoSupport implements IUserDAO
{ public void insertUser(User user) { getHibernateTemplate().saveOrUpdate(user); }
}
看到这代码乎太简单……不过短短
代码我们已经实示例相,这体现Spring+Hibernate
所在。
的UserDAOIUserDAO扩展
HibernateDaoSupport
HibernateSupportHibernateTemplateSessionFactory联。
HibernateTemplateHibernate Session作进封装 HibernateTemplate.execute是一封装机制兴趣者可以研究 其实机制
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
HibernateTemplate我们脱离每次数据作必须Session实例、提/事务烦杂try/catch/finally等作。而获得以代码
中的逻辑呈现果。
了同能的Hibernate原生代码,更有体
Session session
try {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory(); session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User(); user.setName("erica"); user.setPassword("mypass"); session.save(user);
tx.commit();
} catch (HibernateException e) { e.printStackTrace(); tx.rollback(); }finally{ session.close(); }
代码:
InputStream is = new FileInputStream("Hibernate-Context.xml"); XmlBeanFactory factory = new XmlBeanFactory(is); IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy");
User user = new User(); user.setUsername("erica"); user.setPassword("mypass");
userDAO.insertUser(user);
September 2, 2004 So many open source projects. Why not Open your Documents?
Hibernate Developers Guide Version 1.0
编后赘言
Hibernate 是一个ORM 现,不过意,是一个 ORM
不能保证是最的。
使ORM 实现中,Apache OJBOracle TopLinkIBatis
Jaxor 给笔者深刻,是 否选Hibernate 为持久层实现,结合实际情况考虑(在情况下,比如对遗留系统的改项目中、
ibatis 能更
设计冷静个系统的最实际的标
在网上看到Hibernate 一些项目或者框架狂热 鼓吹项目EJB 摇旗呐喊
设计用时间来沉淀是如……
September 2, 2004 So many open source projects. Why not Open your Documents?
Loading...