重新探索自我

    客观条件受制于人,并不足惧。重要的是,我们拥有选择的自由,可以对现实环境积极回应,
    为生命负责,为自己创造有利的机会,做一个“真正”操之在我的人!

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  3 随笔 :: 10 文章 :: 5 评论 :: 0 Trackbacks

一、Hibernate 的 CRUD 基本操作


// 取得 session ,通常我们利用 hibernate.cfg.xml 的配置

// 以用户表和部门为例

Configuration config = new Configuration().configure();

SessionFactory sessionFactory =

config.buildSessionFactory();

Session session = sessionFactory.openSession();

(1) 查询数据

// 取所有记录

Criteria criteria = session.createCriteria(User.class);

Query query = session. createQuery ;

List resultList = criteria.list()/ query . list();

// 按条件查询

Query query = session .createQuery("from User where id between :ID1 and :ID2");

query.setInteger("ID1",0);

query.setInteger("ID2",2);

Criteria criteria = getSession().createCriteria(User.class);

criteria.add(Restrictions.eq("id",new Integer(1)));

// 更复查的查询见 Criteria 详解

(2) 插入记录

// 不设关联的时候,可以直接 save 一个对象

User user = new User();

user.setUserName(“jiangliwen”);

user.setSex(“ 男 ”);

session.save(user);

(3) 删除记录

// 把一个 POJO 变成 PO 后就可以删除,不过有时候方法会在删除的时候自动变为 PO

// 当你发现 User user = new User(New Integer(1)), 出错的时候,说明不行

User user = (User)session.load(User.class,new Integer(1));

session.delete(user);

(4) 更新记录

// 过程为取出、修改、保存

User user = (User)session.load(User.class,new Integer(1));

user.setRealName(“ 哈哈 ”);

session.update(user);

二、Criteria 查询总结,能完成一般查询、统计、分组、多表查询


填入任一查询参数,模糊查询

Criteria criteria = getSession().createCriteria(User.class);
criteria.add(Restrictions.eq("id",new Integer(1)));
List list = criteria.list();
criteria.add(Restrictions. like("username",”%jiang%”));

您可以使用 Criteria 進行查詢,並使用 Order 對結果進行排序,例如使用 Oder.asc() 由小到大排序
(反之則使用 desc() ):

Criteria criteria = session.createCriteria(User.class);
criteria.addOrder(Order.asc("age"));
List users = criteria.list();


setMaxResults() 方法可以限定查詢回來的筆數,如果配合 setFirstResult() 設定傳回查詢結果
第一筆資料的位置,就可以實現簡單 的分頁,例如傳回第 51 筆之後的 50 筆資料(如果有的話):

Criteria criteria = session.createCriteria(User.class);
criteria.setFirstResult(51);
criteria.setMaxResult(50);
List users = criteria.list();


您可以對查詢結果進行統計動作,使用 Projections 的 avg() 、 rowCount() 、 count() 、 max() 、 min() 、
countDistinct() 等方法,例如對查詢結果的 "age" 作平均:

Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.avg("age"));
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}


還可以配合 Projections 的 groupProperty() 來對結果進行分組,例如以 "age" 進行分組,也就是如果資料中 "age"
如果有 20 、 20 、 25 、 30 ,則以下會顯示 20 、 25 、 30 :

Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.groupProperty("age"));
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}


如果想結合統計與分組功能,則可以使用 ProjectionList ,例如下面的程式會計算每個年齡各有多少個人:

ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("age"));
projectionList.add(Projections.rowCount());

Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(projectionList);
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
Object[] o = (Object[]) iterator.next();
System.out.println(o[0] + "\t" + o[1]);
}


如果有一個已知的物件,則可以根據這個物件作為查詢的依據,看看是否有屬性與之類似的物件,例如:

User user = new User();
user.setAge(new Integer(30));

Criteria criteria = session.createCriteria(User.class);
criteria.add(Example.create(user));

List users = criteria.list();
Iterator iterator = users.iterator();
System.out.println("id \t name/age");
while(iterator.hasNext()) {
User ur = (User) iterator.next();
System.out.println(ur.getId() +
" \t " + ur.getName() +
"/" + ur.getAge());
}


在這個例子中, user 物件中有已知的屬性 "age" 為 30 ,使用 Example 會自動過濾掉 user 的空屬性,
並以之作為查詢的依據,也就是找出 "age" 同為 30 的資料。

Criteria 可以進行複合查詢,即在原有的查詢基礎上再進行查詢,例如在 Room 對 User 的一對多關聯中,
在查詢出所有的 Room 資料之後,希望再查詢 users 中 "age" 為 30 的 user 資料:

Criteria roomCriteria = session.createCriteria(Room.class);
Criteria userCriteria = roomCriteria.createCriteria("users");
userCriteria.add(Restrictions.eq("age", new Integer(30)));
List rooms = roomCriteria.list(); //
只列出 users 屬性中有 user "age" 30 Room
Iterator iterator = rooms.iterator();

三、Hibernate 的事务管理

Hibernate 是 JDBC 的轻量级封装,本身并不具备事务管理能力。在事务管理层,

Hibernate 将其委托给底层的 JDBC 或者 JTA ,以实现事务管理和调度功能。

Hibernate 的默认事务处理机制基于 JDBC Transaction 。我们也可以通过配置文

件设定采用 JTA 作为事务管理实现:

< property name = "hibernate.transaction.factory_class" >

net.sf.hibernate.transaction.JTATransactionFactory

<!--net.sf.hibernate.transaction.JDBCTransactionFactory-->

</ property >

基于 JDBC 的事务管理

session = sessionFactory.openSession();

Transaction tx = session.beginTransaction();

……

tx.commit();

从 JDBC 层面而言,上面的代码实际上对应着:

Connection dbconn = getConnection();

dbconn.setAutoCommit( false );

……

dbconn.commit();

基于 JTA 的事务管理

JTA 提供了跨 Session 的事务管理能力。这一点是与 JDBC Transaction 最大的

差异。

JDBC 事务由 Connnection 管理,也就是说,事务管理实际上是在 JDBC Connection

中实现。事务周期限于 Connection 的生命周期之类。同样,对于基于 JDBC Transaction

的 Hibernate 事务管理机制而言,事务管理在 Session 所依托的 JDBC Connection

中实现,事务周期限于 Session 的生命周期。

JTA 事务管理则由 JTA 容器实现, JTA 容器对当前加入事务的众多 Connection 进

行调度,实现其事务性要求。 JTA 的事务周期可横跨多个 JDBC Connection 生命周期。

同样对于基于 JTA 事务的 Hibernate 而言, JTA 事务横跨可横跨多个 Session 。

因此当 open 多个 session 时候,用 JTA 来管理事务。

在 EJB 中使用 JTA Transaction 无疑最为简便,我们只需要将 save 方法配置为

JTA 事务支持即可,无需显式申明任何事务,下面是一个 Session Bean 的 save 方法,

它的事务属性被申明为“ Required ”, EJB 容器将自动维护此方法执行过程中的事务:

Hibernate 支持两种锁机制:即通常所说的“悲观锁( Pessimistic Locking )”

和“乐观锁( Optimistic Locking )”

悲观锁:保守态度,一旦上锁,外界无法修改,直到释放

乐观锁: Hibernate 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数

据库的更新操作,利用 Hibernate 提供的透明化乐观锁实现,将大大提升我们的

生产力。

< class

name = "org.hibernate.sample.TUser"

table = "t_user"

dynamic-update = "true"

dynamic-insert = "true"

optimistic-lock = "version"

>

乐观锁,大多是基于数据版本

( Version )记录机制实现。

Cache 管理

使用 cache 的目的往往是为了提高系统的性能;

引入 Cache 机制的难点是如何保证内存中数据的有效性,否则脏数据的出现将给系统

带来难以预知的严重后果。

Hibernate 中的 Cache 大致分为两层,第一层 Cache 在 Session 实现,属于事务

级数据缓冲,一旦事务结束,这个 Cache 也就失效。

第二层 Cache ,是 Hibernate 中对其实例范围内的数据进行缓存的管理容器。

我们需要讨论的是第二层 Cache, 最简单是基于 HashTable 的 cache 机制 .

使用了 Cache 机制之后,应当注意编码的结合,特别在查询数据的时候使用:

Query.list(); 取出所有的数据 , 一次 sql

Query.iterate(); 两次 sql, 一次去 ID , 如果有 cache 则优先查找,二次才取数据

Session 管理

SessionFactory 负责创建 Session , SessionFactory 是线程

安全的,多个并发线程可以同时访问一个 SessionFactory 并从中获取 Session 实例。而

Session 并非线程安全,也就是说,如果多个线程同时使用一个 Session 实例进行数据存取,

则将会导致 Session 数据存取逻辑混乱。

我们可以通过应用 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();

}

}

对于 web 程序而言

我们可以借助 Servlet2.3 规范中新引入的 Filter 机制,轻松实现线程生命周期内的 Session 管理

四、再度思考

1 、对 ORM 的理解

ORM ( Object Relational Mapping )简单的说,就是对象与关系的映射,对于实际应用来讲,
对象一般指面向对象中的对象,关系指关系型数据库,对于我们具体的项目来说,就是将 java 中的
对象与关系型数据库( oracle , mysql )中的表联系起来。

ORM 解决方案有以下四部分组成:

■ 在持续类的对象上执行基本的 CRUD 操作的一组 API 。

■ 用于指定查询的一种语言或一组 API ,这些查询会引用类和类属性。

■ 用于指定映射元数据的工具。

■ 实现 ORM 的一项技术,用来与事务对象交互以完成脏检查、懒关联存取和其它优化功能。

ORM 这种解决方案的好处:

对底层的封装,因此,可移植性好,厂商独立;

解决对象 - 关系不匹配问题;

在传统我们在持久层通常使用 SQL 和 JDBC ,通常认为这样方式已经让大家感到厌倦了,特别是烦琐的代码;

2 、 hibernate 可以认为是最优秀的 ORM 工具

Hibernate 是一个雄心勃勃的项目,它的目标是成为 Java 中管理持续性数据问题的一种完

整的解决方案。它协调应用与关系数据库的交互,让开发者解放出来专注于手中的业务问题。

Hibernate 符合 java 编程习惯,它把数据库与一个 POJO (简单 Java 对象)关联起来,
使得对数据库进行 CRUD 等操作时候,直接操作 Java 对象就可以了。通过以前 Java Bean 一样 ,
使用 setter 和 getter 方法。

五、辅助工具

(1)自动生成 hibernate 的映射文件

一般考虑两个方向:从数据库到映射文件,从 java 类到映射文件

数据库到映射文件可以采用 Middlegen-Hibernate ,这个能很直观的看到表之间的关系,并且能适当的做修改;

从 java 类到映射文件的生成,可以用 XDoclet ,不过需要在 java 类中加上一些标记

从生成的映射文件自动生成 java 类,可以用用一些工具,如 hbm2java

从这四种自动生成工具来看,  mapping file, java file and DDL ,只要知道任何一种文件,都可以得到另外两种文件,

如:

1.  只有 mapping file:

mapping file---hbm2java----java---SchemaExport----DDL

2. 只有 DDL

DDL---Middlegen---hbm----hbm2java----java

3. 只有 Java

java---XDoclet---hbm----SchemaExport----DDL

从这里,大家也可以体会到 , Hibernate 强大的灵活性

不过我们通常习惯专门的工具设计数据库,譬如 power designer 等工具,会自动生成 DDL ,
所以我们更需要通过 DDL ,就自动生成 Mapping file 和 java 类

(2)在 Eclipse 开发工具中,有一个比较好用的插件

Hibernate Synchronizer

•  自动生成基本的 Hibernate 配置文件

•  自动由表结构生成 POJO 类, XML Mapping 和基本的 DAO 类。

•  精巧的继承结构将自动生成代码和用户定制的代码巧妙的分割开来。

•  将自动生成的代码放在基类( Base* )中,将用户定制的代码放在子类中。分割了自动生成的代码和用户定制的代码。

•  当表结构发生了变化时,插件只需要更改自己生成的基类,不用管用户定制的子类。用户定制的子类几乎不用改动,
   或只需要很少的改动即可适应新的表结构。

另:在 hibernate 使用一个 sessionFactory 操作多个数据库时候,可以使用

public StatelessSession openStatelessSession(Connection connection); 方法

--------------------------------------------------------------------------------------

路漫漫兮其修远兮,吾将上下而求索!

不过对于hibernate的学习暂且告一段落,哈哈!

posted on 2006-01-18 10:42 蒋利文 阅读(4833) 评论(3)  编辑  收藏 所属分类: 技术总结

评论

# re: Hibernate学习总结 2006-01-18 12:33 蒋利文
哈哈,自己先顶  回复  更多评论
  

# re: Hibernate学习总结 2006-12-22 14:12 lfh
有收获,谢谢  回复  更多评论
  

# RE: Hibernate学习总结 2009-03-29 00:17 瞿孟林
理解深刻独到  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: