Hibernate 超实用解析(一)
解压缩从Hibernate网站http://www.hibernate.org下载的Hibernate发布包,并把/lib目录下所有需要的库文件拷到新建开发目录下的/lib目录下。
想使用Hibernate,以下是运行时所需要的最小库文件集合:
antlr.jar
cglib.jar
asm.jar
asm-attrs.jars
commons-collections.jar
commons-logging.jar
ehcache.jar
hibernate3.jar
jta.jar
dom4j.jar
log4j.jar
配置Hibernate
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<!-- 将显示的SQL排版,方便观看 -->
<property name="format_sql">true</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="events/Event.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate日志类别
类别 功能
org.hibernate.SQL 在所有SQL DML语句被执行时为它们记录日志
org.hibernate.type 为所有JDBC参数记录日志
org.hibernate.tool.hbm2ddl 在所有SQL DDL语句执行时为它们记录日志
org.hibernate.pretty 在session清洗(flush)时,为所有与其关联的实体(最多20个)的状态记录日志
org.hibernate.cache 为所有二级缓存的活动记录日志
org.hibernate.transaction 为事务相关的活动记录日志
org.hibernate.jdbc 为所有JDBC资源的获取记录日志
org.hibernate.hql.AST 在解析查询的时候,记录HQL和SQL的AST分析日志
org.hibernate.secure 为JAAS认证请求做日志
org.hibernate 为任何Hibernate相关信息做日志 (信息量较大, 但对查错非常有帮助)
class元素来定义一个持久化类:
<class
name="ClassName"
table="tableName"
discriminator-value="discriminator_value"
mutable="true|false"
schema="owner"
catalog="catalog"
proxy="ProxyInterface"
dynamic-update="true|false"
dynamic-insert="true|false"
select-before-update="true|false"
polymorphism="implicit|explicit"
where="arbitrary sql where condition"
persister="PersisterClass"
batch-size="N"
optimistic-lock="none|version|dirty|all"
lazy="true|false"
entity-name="EntityName"
check="arbitrary sql check condition"
rowid="rowid"
subselect="SQL expression_r"
abstract="true|false"
node="element-name"
/>
1. name (可选): 持久化类(或者接口)的Java全限定名。如果这个属性不存在,Hibernate将假定这是一个非POJO的实体映射。
2. table (可选 - 默认是类的非全限定名): 对应的数据库表名。
3. discriminator-value (可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用。它可以接受的值包括 null 和 not null。
4. mutable (可选,默认值为true): 表明该类的实例是可变的或者不可变的。
5. schema (可选): 覆盖在根<hibernate-mapping>元素中指定的schema名字。
6. catalog (可选): 覆盖在根<hibernate-mapping>元素中指定的catalog名字。
7. proxy (可选): 指定一个接口,在延迟装载时作为代理使用。 可以在这里使用该类自己的名字。
8. dynamic-update (可选, 默认为 false): 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。
9. dynamic-insert (可选, 默认为 false): 指定用于INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。
10. select-before-update (可选, 默认为 false): 指定Hibernate除非确定对象真正被修改了(如果该值为true-译注),否则不会执行SQL UPDATE操作。在特定场合(实际上,它只在一个瞬时对象(transient object)关联到一个新的session中时执行的update()中生效),这说明Hibernate会在UPDATE 之前执行一次额外的SQL SELECT操作,来决定是否应该执行 UPDATE。
11. polymorphism(多态) (可选, 默认值为 implicit (隐式) ): 界定是隐式还是显式的使用多态查询(这只在Hibernate的具体表继承策略中用到-译注)。
12. where (可选) 指定一个附加的SQLWHERE 条件, 在抓取这个类的对象时会一直增加这个条件。
13. persister (可选): 指定一个定制的ClassPersister。
14. batch-size (可选,默认是1) 指定一个用于 根据标识符(identifier)抓取实例时使用的"batch size"(批次抓取数量)。
15. optimistic-lock(乐观锁定) (可选,默认是version): 决定乐观锁定的策略。
(16) lazy (可选): 通过设置lazy="false", 所有的延迟加载(Lazy fetching)功能将被全部禁用(disabled)。
(17) entity-name (可选,默认为类名): Hibernate3允许一个类进行多次映射( 前提是映射到不同的表),并且允许使用Maps或XML代替Java层次的实体映射 (也就是实现动态领域模型,不用写持久化类-译注)。
(18) check (可选): 这是一个SQL表达式,用于为自动生成的schema添加多行(multi-row)约束检查。
(19) rowid (可选): Hibernate可以使用数据库支持的所谓的ROWIDs,例如: Oracle数据库,如果设置这个可选的rowid, Hibernate可以使用额外的字段rowid实现快速更新。ROWID是这个功能实现的重点,它代表了一个存储元组(tuple)的物理位置。
(20) subselect (可选): 它将一个不可变(immutable)并且只读的实体映射到一个数据库的子查询中。当想用视图代替一张基本表的时候,这是有用的,但最好不要这样做。更多的介绍请看下面内容。
(21) abstract (可选): 用于在<union-subclass>的继承结构 (hierarchies)中标识抽象超类。
强烈建议在Hibernate中使用version/timestamp字段来进行乐观锁定。对性能来说,这是最好的选择,并且这也是唯一能够处理在session外进行操作的策略(例如:在使用Session.merge()的时候)。
UUID包含:IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。在Java代码中不可能获得MAC地址或者内存地址,所以这已经是在不使用JNI的前提下的能做的最好实现了。
Hibernate要求持久化集合值字段必须声明为接口
为了能在应用程序服务器(application server)中使用Hibernate, 应当总是将Hibernate 配置成从注册在JNDI中的Datasource处获得连接,至少需要设置下列属性中的一个.
这是一个使用应用程序服务器提供的JNDI数据源的hibernate.properties样例文件:
hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
Hibernate自带的连接池算法相当不成熟. 并不适合用于产品系统或性能测试中。出于最佳性能和稳定性考虑应该使用第三方的连接池。只需要用特定连接池的设置替换 hibernate.connection.pool_size即可。可以使用C3P0连接池:
<!-- C3P0 连接池设定 -->
<!-- 最小的Connection数目 -->
<property name="c3p0.min_size">5</property>
<!-- 最大的Connection数目 -->
<property name="c3p0.max_size">20</property>
<!-- 允许的idle时间 -->
<property name="c3p0.timeout">300</property>
<!-- 最大的Statement数目 -->
<property name="c3p0.max_statements">50</property>
<!-- idle的测试周期 -->
<property name="c3p0.idle_test_period">3000</property>
使用Tomcat的话,也可以透过它提供的DBCP连接池来取得连接。
设定好容器提供的DBCP连接池之后,只要在配置文件中加入connection.datasource属性,例如在 hibernate.cfg.xml中加入:
<property name="connection.datasource">java:comp/env/jdbc/dbname</property>
如果是在hibernate.properties中的话,则加入:
hibernate.connection.datasource = java:comp/env/jdbc/dbname
如果有个属性,实际上并没有与之对应,例如使用COUNT('filed')来取得,则可以使用formula属性,例如:
...
<property name="average" formula="(SELECT AVG(u.age) FROM T_USER u)"/>
...
设定< id>标签的unsaved-value来决定什么是新的值必需,什么是已有的值必须更新:
<id name="id" column="id" type="java.lang.Integer" unsaved-value="null">
<generator + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Session在第一次被使用的时候,即第一次调用getCurrentSession()的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate会自动把Session从当前线程剥离,并且关闭它。Hibernate Session的生命周期可以很灵活,但是绝不要把的应用程序设计成为每一次数据库操作都用一个新的Hibernate Session。
持久化类(Persistent Classes)所有的持久化类都必须有一个默认的构造方法(可以不是public的),建议对持久化类声明命名一致的标识属性,建议使用一个可以为空(也就是说,不是原始类型)的类型如:Integer。 Hibernate可以持久化有 default、protected或private的get/set方法的属性。
如果想把持久类的实例放入Set中(当表示多值关联时,推荐这么做)或希望Set有明确的语义,就必须实现equals() 和hashCode()。
建议使用业务键值相等(Business key equality)来实现equals() 和 hashCode()。业务键值相等的意思是,equals()方法仅仅比较形成业务键的属性,它能在现实世界里标识的实例(是一个自然的候选码)。
关联映射
使用Java的集合类(collection):Set,因为set 不包含重复的元素及与无关的排序。
1.多对多关联(或叫n:m实体关系), 需要一个关联表(association table)。表里面的每一行代表从person到event的一个关联。表名是由set元素的table属性配置的。关联里面的标识符字段名,对于person的一端,是由<key>元素定义,而event一端的字段名是由<many-to-many>元素的column属性定义。
使用Hibernate的多对多映射:
<class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator table="PERSON_EVENT">
<key column="PERSON_ID"/>
<many-to-many column="EVENT_ID" class="eg.Person"/>
SELECT person.NAME AS {person.name},
person.AGE AS {person.age},
person.SEX AS {person.sex}
FROM PERSON person
WHERE person.NAME LIKE :namePattern
</sql-query>
List people = sess.getNamedQuery("persons")
.setString("namePattern", namePattern)
.setMaxResults(50)
.list();
<idbag>映射定义了代理键,因此它总是可以很高效的被更新。事实上, <idbag>拥有着最好的性能表现。