一对一
name 映射属性
class 目标映射类。
cascade 操作级联关系。可选值:
all:所有情况下均进行级联操作。
none:所有情况都不进行级联操作。
save-update:在执行save-update时进行级联操作。
constrained 约束。
outer-join 是否使用外联接。
property-ref 关联中用于主控类相关联的属性名称。
access 属性值的读取方式。
新增一个对象:
Transaction tx = session.beginTransaction();
TAddress addr = new TAddress();
addr.setTel("1123");
addr.setZipcode("233123");
addr.setAddress("HongKong");
user.getAddress().add(addr);
session.save(user);
tx.commit();
两种方法来保存:
sava(user)时候;
insert into t_address(user_id,address,zipcode,tel) values(1,"Hongkong","233123","1123")
tx.commit()时:
update t_address set user_id="1",address="Hongkong",zipcode="233123",tel="1123" where id = 2
PO和VO概念
PO 即Persistence Object 即纳入Hibernate管理框架中的VO.
VO 即Value Object 就是一个简单的值的对象.
Locking锁
悲观锁和乐观锁.
悲观锁的调用:
select * from accout where name="Erica" for update
这条sql 语句锁定了account 表中所有符合检索条件(name=”Erica”)的记录。
Hibernate的悲观锁,也是基于数据库的锁机制实现。
下面的代码实现了对查询记录的加锁:
String hqlStr = "from TUser as user where user.name='Erica'";
Query query=session.createQuery(hqlStr);
query.setLockMode("user",LockMode.UPGRADE);//枷锁
List userList = query.list();//执行查询.获得数据
何谓数据版本?
即为数据增加一个版本标识,在基于
数据库表的版本解决方案中,一般是
通过为数据库表增加一个“version”字段来
实现。
optimistic-lock属性有如下可选取值:
none
无乐观锁
version
通过版本机制实现乐观锁
dirty
通过检查发生变动过的属性实现乐观锁
all
通过检查所有属性实现乐观锁
Hibernate分页:
我们可以通过Criteria.setFirstResult和Criteria.setFetchSize方法设定分页范围
Criteria criteria = session.createCriteria(TUser.class);
Criteria.add(Expression.eq("age","20"));
//从检索中获得第100条纪录开始的20条纪录
criteria.setFirstResult(100);
criteria.setFetchSize(20);
MySQLDialect中的getLimitString实现
public String getLimitString(String sql, boolean hasOffset) {
return new StringBuffer( sql.length()+20 )
.append(sql)
.append( hasOffset ? " limit ?, ?" : " limit ?")
.toString();
}
Oracle9Dialect 中的getLimitString 实现,其中通过Oracle 特有的
rownum子句实现了数据的部分读取。
public String getLimitString(string sql,boolean hasOffset)
{
StringBuffer pagingSelect = new StringBuffer(sql.length()+100);
if(hasOffset){
pageingSelect.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();
}
Cache管理
Cache往往是提高系统性能的最重要的手段
Hibernate 中实现了良好的Cache 机制,我们可以借助Hibernate 内部的Cache
迅速提高系统数据读取性能
在Hibernate.cfg.xml中配制
<hibernate-configuration>
<session-factory>
……
<property name="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.Provider
</property>
……
</session-factory>
</hibernate-configuration>
另外cache本身还需要配制
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultcache
maxElementsInMemory="1000" //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 usage可选值有以下几种:
1. read-only
只读。
2. read-write
可读可写。
3. nonstrict-read-write
如果程序对并发数据修改要求不是非常严格,只是偶尔需要更新数据,可以采用
本选项,以减少无谓的检查,获得较好的性能。
4. transactional
事务性cache。在事务性Cache 中,Cache 的相关操作也被添加到事务之中,
如果由于某种原因导致事务失败,我们可以连同缓冲池中的数据一同回滚到事务
开始之前的状态。目前Hibernate 内置的Cache 中,只有JBossCache 支持
事务性的Cache实现。
需要注意的是Hibernate 的数据库查询机制。
我们从查询结果中取出数据的时候,用的最多的是两个方法:
Query.list(); 对于list 操作,需要一条SQL 完成。
Query.iterate(); 对于iterate 操作,需要n+1条SQL。
对于list方法而言,实际上Hibernate是通过一条Select SQL获取所有的记录。
并将其读出,填入到POJO中返回。
而iterate 方法,则是首先通过一条Select SQL 获取所有符合查询条件的记录的
id,再对这个id 集合进行循环操作,通过单独的Select SQL 取出每个id 所对应的记
录,之后填入POJO中返回。
Session管理
无疑,Session是Hibernate运作的灵魂,作为贯穿Hibernate应用的关键,Session
中包含了数据库操作相关的状态信息。如对JDBC Connection 的维护,数据实体的状态维持
等。
对Session 进行有效管理的意义,类似JDBC 程序设计中对于JDBC Connection 的调
度管理。有效的Session管理机制,是Hibernate应用设计的关键。
在各种Session 管理方案中, ThreadLocal 模式得到了大量使用。ThreadLocal 是
Java中一种较为特殊的线程绑定机制。通过ThreadLocal存取的数据,总是与当前线程相关,
也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出
现的并发访问问题提供了一种隔离机制。
SessionFactory负责创建Session,SessionFactory是线程
安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session 实例。而
Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,
则将会导致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();
}
}
在Filter 中管理Session 对于Web 程序而言就显得水到渠成
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);
}
}
}
}
……