Session是Hibernate运作的中心,对象的生命周期、事务的管理、数据库的存取,都与Session息息相关,就如同在编写JDBC时需关心 Connection的管理,以有效的方法创建、利用与回收Connection,以减少资源的消耗,增加系统执行效能一样,有效的Session管理,也是Hibernate应用时需关注的焦点。 Session是由SessionFactory所创建,SessionFactory是执行绪安全的(Thread-safe),您可以让多个执行绪同时存取SessionFactory而不会有数据共享的问题,然而Session则不是设计为执行绪安全的,所以试图让多个执行绪共享一个 Session,将会发生数据共享而发生混乱的问题。 在Hibernate参考手册中的 Quickstart with Tomcat 中,示范了一个HibernateUtil,它使用了ThreadLocal类别来建立一个Session管理的辅助类,这是Hibernate的Session管理一个广为应用的解决方案,ThreadLocal是*Thread-Specific Storage 模式*的一个运作实例。 由于Thread-Specific Stroage模式可以有效隔离执行绪所使用的数据,所以避开Session的多执行绪之间的数据共享问题,以下列出Hibernate参考手册中的HibernateUtil类: HibernateUtil.java import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.*; import org.hibernate.cfg.*;public class HibernateUtil { private static Log log = LogFactory.getLog(HibernateUtil.class); private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory sessionFactory = new Configuration().configure() .buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed log.error("Initial SessionFactory creation failed.", ex); throw new ExceptionInInitializerError(ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() { 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() { Session s = (Session) session.get(); if (s != null) { s.close(); } session.set(null); } } 在同一个执行绪中,Session被暂存下来了,但无须担心数据库连结Connection持续占用问题,Hibernate会在真正需要数据库操作时才(从连接池中)取得Connection。 在程序中可以这么使用HibernateUtil: Session session = HibernateUtil.currentSession(); User user = (User) session.load(User.class, new Integer(1)); System.out.println(user.getName()); HibernateUtil.closeSession(); 在Web应用程序中,可以藉助Filter来进行Session管理,在需要的时候开启Session,并在Request结束之后关闭Session,这个部份,在 JavaWorld 技术论坛 的 Wiki 上有篇 在filter中关闭session 可以参考。
我们现在的项目,关于DB操作分domain,dao,manager三层, 分别对应映射类, dao操作,以及业务逻辑操作 有一个HibernateUtil类class HibernateUtil{ public UserTransaction beginTransaction(){...} public void commitTransaction(UserTransaction tx){.../*session be closed*/} public void rollbackTransaction(UserTransaction tx); } 在manager类里面的业务处理代替是这样一个结构class Manager{ public void business(){ try{ UserTransaction tx = HibernateUtil.beginTransaction(); //dao operations HibernateUtil.commitTransaction(tx); }catch(Exception e){ HibernateUtil.rollbackTransaction(tx);//问题1:commitTransaction已经把session关闭了,怎么还能rollback?要么在commit中出错抛异常的情况下session没有去关闭? } } } 问题2:在业务逻辑处理过程中,很容易有manager1.business()调用manager2.business()的情况,这样就出现了下面的结构(这个问题我在另一个帖子也问了,可能有人也看到了)class Manager1{ public void business(){ Manager2.business(); } } beginTransaction beginTransaction commitTransaction commitTransaction也就是出现了事务嵌套的情况,但是从设计上来讲,manager自己处理一个business,包含在一个beginTransaction和commitTransaction中也没错吧这个设计很让我迷惑,感觉很矛盾,各位指点一下吧
楼主【believefym】截止到2008-06-24 11:16:24的历史汇总数据(不包括此帖):
发帖数:61 发帖分:3762
结贴数:58 结贴分:3562
未结数:3 未结分:200
结贴率:95.08 % 结分率:94.68 %
值得尊敬
session接口提供了一系列操作数据库的方法
也就是说你想调用这些方法必须用session.XX();的形式
session是轻量级的,也就是可以创建多个session.而sessionfacotry就是重量级的了
transaction是事物管理接口,你去看看hibernate的API文档就知道怎么回事了!
如有不对请楼下的指正
谁再说说关于session,transaction作用范围,session关闭状态的后果之类的,大家能理解我的意思就行,说得可能不是很专业
transaction---current session
这里有些关于hibernate的资料
快取(Cache)是数据库在内存中的临时容器,从数据库中读取的数据在快取中会有一份临时拷贝,当您查询某个数据时,会先在快取中寻找是否有相对应的拷贝,如果有的话就直接返回数据,而无需连接数据库进行查询,只有在快取中找不到数据时,才从数据库中查询数据,藉由快取,可以提升应用程序读取数据时的效能。
对于Hibernate这样的ORM框架来说,快取的机制更形重要,在Hibernate中快取分作两个层级:Session level与SessionFactory level(又称Second level快取)。
这边先介绍Session level的快取,在Hibernate中Session level快取会在使用主键加载数据或是延迟初始(Lazy Initialization) 时作用,Session level的快取随着Session建立时建立,而Session销毁时销毁。
Session会维护一个Map容器,并保留与目前Session发生关系的资料,当您透过主键来加载数据时,Session会先依据所要加载的类别与所给定的主键,看看Map中是否已有数据,如果有的话就返回,若没有就对数据库进行查询,并在加载数据后在Map中维护。
可以透过==来比较两个名称是否参考至同一个对象,以检验这个事实:
Session session = sessionFactory.openSession();
User user1 = (User) session.load(User.class, new Integer(1));
User user2 = (User) session.load(User.class, new Integer(1));
System.out.println(user1 == user2);
session.close();
第二次查询数据时,由于在快取中找到数据对象,于是直接返回,这与第一次查询到的数据对象是同一个实例,所以会显示true的结果。
可以透过evict()将某个对象从快取中移去,例如:
Session session = sessionFactory.openSession();
User user1 = (User) session.load(User.class, new Integer(1));
session.evict(user1);
User user2 = (User) session.load(User.class, new Integer(1));
System.out.println(user1 == user2);
session.close();
由于user1所参考的对象被从快取中移去了,在下一次查询时,Session在Map容器中找不到对应的数据,于是重新查询数据库并再封装一个对象,所以user1与user2参考的是不同的对象,结果会显示false。
也可以使用clear()清除快取中的所有对象,例如:
Session session = sessionFactory.openSession();
User user1 = (User) session.load(User.class, new Integer(1));
session.clear();
User user2 = (User) session.load(User.class, new Integer(1));
System.out.println(user1 == user2);
session.close();
同样的道理,这次也会显示false。
Session level的快取随着Session建立与销毁,看看下面这个程序片段:
Session session1 = sessionFactory.openSession();
User user1 = (User) session1.load(User.class, new new Integer(1));
session1.close(); Session session2 = sessionFactory.openSession();
User user2 = (User)session2.load(User.class, new Integer(1));
session2.close(); System.out.println(user1 == user2);
第一个Session在关闭后,快取也关闭了,在第二个Session的查询中并无法用到第一个Session的快取,两个Session阶段所查询到的并不是同一个对象,结果会显示false。
在加载大量数据时,Session level 快取的内容会太多,记得要自行执行clear()清除快取或是用evict()移去不使用对象,以释放快取所占据的资源。
Session在使用save()储存对象时,会将要储存的对象纳入Session level快取管理,在进行大量数据储存时,快取中的实例大量增加,最后会导致OutOfMemoryError,可以每隔一段时间使用Session的 flush()强制储存对象,并使用clear()清除快取,例如:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();while(....) { // 大量加载对象时的循环示意
....
session.save(someObject);
if(count % 100 == 0) { // 每100笔资料
session.flush(); // 送入数据库
session.clear(); // 清除快取
}
}tx.commit();
session.close();
在SQL Server、Oracle等数据库中,可以在Hibernate设定文件中设定属性hibernate.jdbc.batch_size来控制每多少笔数据就送至数据库,例如:
....
<hibernate-configuration>
<session-factory>
....
<property name="hibernate.jdbc.batch_size">100</property>
....
</session-factory>
<hibernate-configuration>
在MySQL中则不支持这个功能。
在JDBC中,可以用Connection来管理事务,可以将Connection的AutoCommit设定为false,在下达一连串的SQL语句后,自行呼叫Connection的commit()来送出变更,如果中间发生错误,则撤消所有的执行,例如:
try {
.....
connection.setAutoCommit(false);
..... // 一连串SQL操作 connection.commit();
} catch(Exception) {
// 发生错误,撤消所有变更
connection.rollback();
}
Hibernate本身没有事务管理功能,它依赖于JDBC或JTA的事务管理功能,预设是使用JDBC事务管理,可以在配置文件中加上hibernate.transaction.factory_class属性来指定Transaction的工厂类别,例如:
hibernate.cfg.xml
<?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-factor....
<!-- 设定事务管理的工厂类 -->
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<!-- 对象与数据库表格映像文件 -->
<mapping resource="onlyfun/caterpillar/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
基于JDBC的事务管理是最简单的方式,事实上,Hibernate基于JDBC的事务管理只是对JDBC作了个简单的封装:
try {
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
....
tx.commit(); // 必须commit才会更新数据库
} catch(HibernateException e) {
tx.rollback();
}
在一开始的openSession()取得Session时,JDBC的Connection实例之AutoCommit就被设定为false,在 beginTransaction()时,会再度检查Connection实例的AutoCommit为false,在操作过程中,最后要commit (),否则的话对数据库的操作不会有作用,如果操作过程中因发生例外,则最后commit()不会被执行,之前的操作取消,执行rollback()可撤消之前的操作,一个实际的程序如下所示
FirstHibernate2.java
package onlyfun.caterpillar;import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;public class FirstHibernate2 {
public static void main(String[] args) {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory(); User user = new User();
user.setName("momor");
user.setAge(new Integer(26)); Session session = null;
Transaction tx = null; try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
session.save(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace(); if (tx != null) {
try {
tx.rollback();
} catch (HibernateException ee) {
ee.printStackTrace();
}
}
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
} sessionFactory.close();
}
}
PS. 要使用MySQL中的事务处理,必须建立事务表类型的表格,例如InnoDB的表格:
CREATE TABLE user (
.....
....
) TYPE = InnoDB;
Session是由SessionFactory所创建,SessionFactory是执行绪安全的(Thread-safe),您可以让多个执行绪同时存取SessionFactory而不会有数据共享的问题,然而Session则不是设计为执行绪安全的,所以试图让多个执行绪共享一个 Session,将会发生数据共享而发生混乱的问题。
在Hibernate参考手册中的 Quickstart with Tomcat 中,示范了一个HibernateUtil,它使用了ThreadLocal类别来建立一个Session管理的辅助类,这是Hibernate的Session管理一个广为应用的解决方案,ThreadLocal是*Thread-Specific Storage 模式*的一个运作实例。
由于Thread-Specific Stroage模式可以有效隔离执行绪所使用的数据,所以避开Session的多执行绪之间的数据共享问题,以下列出Hibernate参考手册中的HibernateUtil类:
HibernateUtil.java
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.*;
import org.hibernate.cfg.*;public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory
sessionFactory = new Configuration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
log.error("Initial SessionFactory creation failed.", ex);
throw new ExceptionInInitializerError(ex);
}
} public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() {
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() {
Session s = (Session) session.get(); if (s != null) {
s.close();
} session.set(null);
}
}
在同一个执行绪中,Session被暂存下来了,但无须担心数据库连结Connection持续占用问题,Hibernate会在真正需要数据库操作时才(从连接池中)取得Connection。
在程序中可以这么使用HibernateUtil:
Session session = HibernateUtil.currentSession();
User user = (User) session.load(User.class, new Integer(1));
System.out.println(user.getName());
HibernateUtil.closeSession();
在Web应用程序中,可以藉助Filter来进行Session管理,在需要的时候开启Session,并在Request结束之后关闭Session,这个部份,在 JavaWorld 技术论坛 的 Wiki 上有篇 在filter中关闭session 可以参考。
分别对应映射类, dao操作,以及业务逻辑操作
有一个HibernateUtil类class HibernateUtil{
public UserTransaction beginTransaction(){...}
public void commitTransaction(UserTransaction tx){.../*session be closed*/}
public void rollbackTransaction(UserTransaction tx);
}
在manager类里面的业务处理代替是这样一个结构class Manager{
public void business(){
try{
UserTransaction tx = HibernateUtil.beginTransaction();
//dao operations
HibernateUtil.commitTransaction(tx);
}catch(Exception e){
HibernateUtil.rollbackTransaction(tx);//问题1:commitTransaction已经把session关闭了,怎么还能rollback?要么在commit中出错抛异常的情况下session没有去关闭?
}
}
}
问题2:在业务逻辑处理过程中,很容易有manager1.business()调用manager2.business()的情况,这样就出现了下面的结构(这个问题我在另一个帖子也问了,可能有人也看到了)class Manager1{
public void business(){
Manager2.business();
}
}
beginTransaction
beginTransaction
commitTransaction
commitTransaction也就是出现了事务嵌套的情况,但是从设计上来讲,manager自己处理一个business,包含在一个beginTransaction和commitTransaction中也没错吧这个设计很让我迷惑,感觉很矛盾,各位指点一下吧