一、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的学习暂且告一段落,哈哈!