随笔-12  评论-1  文章-0  trackbacks-0

看这个链接作了解:http://zhaohe162.blog.163.com/blog/static/3821679720110251181721/
一、HQL查询的from子句

from是最简单的语句,也是最基本的HQL语句。from关键字后紧跟持久化类的类名。

例如:

from Person  表明从Person持久化类中选出全部的实例

推荐为Person持久化类的每个实例起别名,例如:

from Person as p

p作为Person的实例的别名,因此也应该遵守Java的命名规则:第一个单词的首字母小写,后面每个单词的首字母大写。

命名别名时,as关键字是可选的,但为了增加可读性,建议保留。

from 后还可同时出现多个持久化类,此时将产生一个笛卡尔积或跨表的连接,但实际上这种用法很少使用,因为通常我们可能需要使用跨表的连接,此时可以考虑使用隐式连接或显示连接,而不是直接在from后紧跟多个表名。

二、关联和连接

       Hibernate使用关联映射来处理底层数据表之间的连接,一旦我们提供了正确的关联映射后,当程序通过Hibernate进行持久化访问时,将可利用Hibernate的关联来进行连接。

      HQL支持两种关联连接(join)的形式:隐式(implicit)与显示(explicit)。

隐式连接形式不适用join关键字,使用英文点号(.)来隐式连接来关联实体,而Hibernate底层将自动进行关联查询。如下HQL语句:

from Person p where p.myEvent.title > :title

上面的p.myEvent属性的实质是一个持久化实体,因此Hibernate底层隐式地自动进行连接查询。

显示连接则需要使用xxx join关键字,例如如下语句:

//使用显示连接

from Person p

inner join p.myEvent event

where event.happenDate < :endDate

使用显示连接时,可以为相关联的实体,甚至是关联集合中的全部元素指定一个别名。

Hibernate支持的HQL连接类型,可使用如下几种连接方式:

inner join(内连接),可简写成join。

left outer join(左外连接),可简写成left join。

right outer join(右外连接),可简写成right join。

full join(全连接),并不常用。

使用显示连接时,还可通过HQL的with关键字来提供额外的连接条件,例如如下HQL语句:

from Person p

inner join p.myEvent event

with p.id > event.id

where event.happenDate < :endDate

       HQL语句中的with关键字的作用基本等同于SQL99中on关键字的作用:都是用于指定连接条件。通过在HQL语句中使用with关键字,可以让HQL语句执行非等值连接查询。

      由于表连接的方式都是基于底层SQL来实现的,如果底层不支持这些外连接,那么执行对应的HQL时就会相应地引发异常。

 

三、隐式连接和显示连接有如下两点区别:

(1)隐式连接底层转换成SQL92的内连接,显示连接层将转换成SQL99的多表连接。

(2)隐式连接和显示连接查询后返回的结果不同。

当HQL语句中省略select关键字时,使用隐式连接查询返回的结果是多个被查询实体组成的集合。

当HQL语句中省略select关键字时,使用显示连接查询返回的结果也是集合,但集合元素是被查询持久化对象、所有被关联的持久化对象所组成的数组。

 注意:

       对于Hibernate3.2.3以后的版本,如果关联实体是单个实体或单个的组件属性,HQL依然可以似乎用英文点号(.)来隐式连接关联实体或组件;但如果关联实体是集合(包括1-N关联、N-N关联和集合元素时组件等),则必须使用xxx join来显示连接关联实体或组件。

       对于集合属性的,Hibernate默认采用延迟加载策略,解决办法:

       (2.1)可以在Hibernate映射文件中指定lazy="false"来关闭延迟加载。

       (2.2)使用join fetch,通常无须指定别名,因为相关联的对象不应当在where子句(或其他任何子句)中使用。而且被关联的对象也不会再被查询的结果中直接返回,而是应该通过其父对象来访问。

使用fetch关键字时,有如下几个注意点:

       fetch不应该与setMaxResults()或setFirstResult()共用。因为这些操作是基于结果集的,而在预先抓取集合类时可能包含重复的数据,即无法预先知道精确的行数。

       fetch不能与独立的with条件一起使用。

       如果在一次查询中fetch多个集合,可以查询返回笛卡尔积,因此请多加注意。

       对bag映射而言,同时join fetch多个集合时可能出现非预期结果,因此需要谨慎使用。

      full join fetch 与right join fetch是没有任何意义的。

程序里希望预加载那些原本应延迟加载的属性,则可以通过fetch all properties来强制Hibernate立即抓取这些属性。例如:

from Document fetch all properties order by name


四、HQL查询的select子句

(1)select子句用于选择指定的属性或直接选择某个实体,当然select选择的属性必须是from后持久化类包含的属性。

例如:

select p.name from Person as p

(2)select可以选择任意属性,即不仅可以选择持久化类的直接属性,还可以选择组件属性包含的属性。例如:

select p.name.firstName from Person as p

(3)在特殊情况下,如果select后只有一项(包括持久化实例或属性),则查询得到的集合元素就是该持久化实例或属性。

(4)如果select后有多个项,则每个集合就是选择出的多项组成的数组。

例如:

select p.name,p from Person as p

执行该HQL语句得到的集合元素时类似于[String,Person]结构的数组,其中第一个元素时Person实例的name属性,第二个元素时Person实例。

注意:即使select后的列表项选出某个持久化类的全部属性,这些属性依然是属性,Hibernate不会将这些属性封装成对象。只有在select后的列表里给出持久化类的别名(其实就是实例名),Hibernate才会将该项封装成一个持久化实体。

(5)select支持将选择出的属性存入一个List对象中。

例如:

select new list(p.name, p.address) from Person as p

 (6)select支持将选择出的属性封装成对象,前提是该对象拥有支持这些属性的构造器。

例如:

select new ClassTest(p,name, p.address) from Person as p;

而ClassTest必须有如下的构造器:ClassTest(String s1, String s2)

(7)select还支持给选中的表达式命名别名。例如:

select p.name as personName from Person as p

这种用法与new map 结合使用更普遍。例如:

select new map(p.name as personName) from Person as p

执行上面的HQL语句返回的结果是集合,其中集合元素时Map对象,以personName作为Map的key,实际选出的值作为Map的value。


 

五、HQL查询的聚集函数

HQL支持的聚集函数与SQL的完全相同:avg,count,max,min,sum。

例如,如下的HQL语句:

select count(*) from Person

select max(p.page) from Person as p

select子句还支持字符串连接符、算术连接符,以及SQL函数。例如:

select p.name||""||p.address from Person as p

select子句也支持使用distinct和all关键字,此时的效果与SQL的效果完全相同。


 

六、多态查询

       HQL语句被设计成能够理解多态查询,from后跟持久化类名,不仅会查询出该持久化类的全部实例,还会查询出该类的子类的全部实例。

如下面的查询语句:from Person as p

       如果Named接口有多个持久化实现类,下面的语句将返回这些持久化类的全部实例。

如下面的查询语句:from Named as n

注意:上面最后一条查询,需要多个SQL SELECT 语句,因此无法使用order by子句对结果集排序,从而不允许对这些查询结果使用Query.scroll()方法。


 

七、HQL查询的where子句

(1)where子句用于筛选选中的结果,缩小选择的范围。如果没有为持久化实例命名别名,则可以直接使用属性名来引用属性。

如下面两条HQL语句:

from Person where name like "tom%"

form Person as p where p.name like "tom%"

(2)复合属性表达式加强了where子句的功能,例如,如下的HQL语句:

from Cat cat where cat.mate.name like "kit%"

上面语句被翻译成以下含有内连接的SQL查询:

select * from cat_table as table1 cat_table as table2

where table1.mate = table2.mate

and table1.name like '''kit%'"

实际上这种用法使用了隐式连接查询,从Hibernate3.2.3之后,只有当cat,mate属性引用的是普通组件属性或者单独的关联实体时才可接着在后面使用点好(.)来引用mate属性,如cat,mate.name;如果cat,mate是集合属性,Hibernate3.2.3以后的版本不支持这种用法。

"="号不仅可以被用来比较属性的值,也可以用来比较实例。

select cat,mate from Cat cat, Cat mate where cat.mate = mate

(3)在进行多态持久化的情况下,class关键字用来存取一个实例的鉴别值。嵌入where子句的Java类名,将被作为该类的鉴别值。

//执行多态查询时,默认会选出Cat及其所有子类的实例

//在如下HQL语句中,将只选出DomesticCat类的实例

from Cat cat where cat.class = DomesticCat

(4)当where子句中的运算符只支持基本类型或者字符串时,where子句中的属性表达式必须以基本类型或者字符串结尾,不要使用组件类型属性结尾,例如Account和Person属性,而Person有Name属性,Name属性有firstName属性。

如下所示:

//firstName是字符串

from Account as a where a.person.name.firstName like "dd%"

//下面是错误实例

from Account as a where a.person.name like "dd%"


 

八、表达式

1、HQL的功能非常丰富,where子句后支持的运算符,不仅包括SQL的运算符,也包括EJB-QL的运算符等。

where子句中允许使用大部分SQL支持的表达式,包括如下种类:

(1)字符串连接:如value1||value2,或使用字符串连接函数concat(value1, value2)

(2)简单的case,case...when...then...else...end和case,case when...then...else...end等。

(3)时间操作函数:current_date()、current_time、year()等。

(4)EJB-QL3.0的函数:substring()、trim()、abs()、sqrt()等。

(5)可在where子句中使用SQL常量。

(6)在HQL语句中使用Java中的public static final类型的常量,例如Color.RED

(7)HQL语句支持使用英文问号(?)作为参数占位符,这与JDBC的参数占位符一致;也使用命名参数占位符号,方法在参数名前加英文冒号(:),例如:start_date等。

(8)如果底层数据库支持单行函数,则HQL语句也完全可以支持。

(9)支持数据库的类型转换函数,如cast(... as ...),第二个参数是Hibernate的类型名,或者extract(... from ,,,),前提是底层数据库支持ANSI cast()和extract()。

2、如果在Hibernate配置文件中进行如下声明:

<property name="hibernate.query.substitutions">true 1,false 0</property>

上面的声明表明:HQL转换SQL语句时,将使用字符1和0来取代关键字true和false,然后将可以在表达式中使用布尔表达式。

3、有用的elements()和indices函数,用于返回指定集合的所有元素和所有索引。

4、在where子句中,有序集合(数组、List集合、Map对象)的元素可以通过【】运算符来访问。如下:

from Order order where order.items[0].id=1234

在【】中的表达式甚至可以是一个算式表达式。

5、结构变量:size、elements、indices等,只能在where子句中使用。


 

九、order by子句

查询返回的集合根据类或组件属性的任何属性进行排序。例如:

from Person as p order by p.name,p.age

还可以使用as或desc关键字指定升序或降序的排序规则。例如:

from Person as p order by p.name asc,p.age desc

如果没有指定排序规则,默认采用升序规则。

十、group by子句

返回聚集值的查询可以对持久化类或组件属性的进行分组,分组使用group by子句。看下面的HQL查询语句:

select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color

其规则类似于SQL规则。

having子句用于对分组进行过滤,如下所示:

select cat,color,sum(cat.weight),count(cat) from Cat cat group by cat.color having cat.color in (eg.Color.TABBY,eg.Color.BLACK)

注意:group by子句与order by 子句中都不能包含算术表达式


 

十一、子查询

(1)如果底层数据库支持子查询,则可以在HQL语句中使用子查询。如下:

from Cat as fatcat where fatcat.weight > (select avg(cat.weight) from DomesticCat cat)

(2)如果子查询是多行结果集,则应该使用多行运算符。如下:

from Cat as cat where not(cat.name, cat.color) in (select cat.name, cat.color from DomesticCat cat)

(3)SQL语法中子查询还可以出现在select子句之后,HQL也支持这种用法,看如下HQL语句:

select cat.id,(select max(kit.weight) from cat.kitten kit)

from Cat as cat

注意:HQL子查询只可以在select子句或者where子句中出现。

 

十二、命名查询

HQL支持将查询所用的HQL语句放入配置文件中,而不是代码中。

在Hibernate映射文件的<hibernate-mapping/>元素中使用<query/>子元素来定义命名查询,使用<query/>元素只需要指定一个name属性,指定该命名查询的名字。该元素的内容就是命名查询的HQL语句。如下配置文件片段:

<query name="myNameQuery">

        from Person as p where p.age > ?

</query>

配置好后,通过Session提供的一个getNameQuery(String name)方法,该方法用于创建一个Query对象,剩下的操作与普通HQL完全一样。如下所示:

List p1 = sess.getNamedQuery("myNameQuery").setInteger(0,20).list()


 

十三、条件查询

条件查询通过如下3个类完成:

Criteria:代表一次查询。

Criterion:代表一个查询条件。

Restrictions:产生查询条件的工具类。

执行条件查询的步骤如下:

(1)获得Hibernate的Session对象。

(2)以Session对象创建Criteria对象。

(3)使用Restrictions的静态方法创建Criterion查询条件。

(4)向Criteria查询中体检Criterion查询条件。

(5)执行Criteria的list等方法返回结果集。

代码片段如下:

List l = session.createCriteria(Student.class)

            //此处增加限制条件必须是Student已经存在的属性

             .add(Restrictions.get("studentNumber", 20050231L))

            //如果要增加对Student的关联类的属性的限制

            //则必须重新createCriteria()

            //如果此关联属性是集合,则只要集合里任意一个对象的属性满足下面条件即可

            .createCriteria("enrolments")

            .add(Restrictions.gt("semester",2))

            .list();

在条件查询中,Criteria接口代表依次查询,该查询本身不具备任何的数据筛选功能,Session调用createCriterial(Class clazz)方法对某个持久化类创建条件查询实例。

Criteria对象不具备任何的数据筛选功能,但程序可以通过向Criteria对象中组合多个Criterion(每个Criterion对象代表一个过滤条件)即可实现数据过滤了。

Criterion接口代表一个查询条件,该查询条件由Restrictions负责产生。Restrictions是专门用于产生查询条件的工具类,它的方法大部分都是静态方法,常用的方法如下:

(1)static Criteion allEq(Map propertyNameValues):判断指定属性(由Map参数的key指定)和指定值(由Map参数的value指定)是否完全相等。

(2)static Criterion between(String propertyName, Object lo, Object hi):判断属性值在某个指范围之内。


 

十四、关联和动态关联

代码片段如下:

List l = session.createCriteria(Student.class)

            //此处增加限制条件必须是Student已经存在的属性

             .add(Restrictions.get("studentNumber", 20050231L))

            //如果要增加对Student的关联类的属性的限制

            //则必须重新createCriteria()

            //如果此关联属性是集合,则只要集合里任意一个对象的属性满足下面条件即可

            .createCriteria("enrolments")

            .add(Restrictions.gt("semester",2))

            .list();

上面的代码表示建立Person类的条件查询,第一个查询条件是直接过滤Person的属性。第二个查询条件则过滤Person的关联实体的属性,其中enrolments是Person类的关联实体,而semester则是Enrolment类的属性。值得注意的是,返回的并不是Enrolment对象,而是Person对象的集合。

注意:使用关联类的条件查询,依然是查询原有持久化类的实例,而不是查询被关联类的实例。

可使用条件查询支持的替换形态,将上面查询代码替换成如下形式:

List l = session.createCriteria(Student.class)

            .add(Restrictions.gt("studentNumber",20050231L))

            .createAlias("enrolments","en")

            .add(Restrictions.gt("semester",2))

             .list();

createAlias()方法并不创建一个新的Criteria实例,它只是给关联实体(包含集合里包含的关联实体)起一个别名,让后面过滤条件可根据关联实体进行筛选。

在默认情况下,条件查询将根据映射文件指定的延迟加载策略来加载关联实体,如果希望在条件查询中改变延迟加载策略(就像在HQL查询中使用fetch关键字一样),那就可通过Creteria的setFetchMode()方法来实现,该方法接受一个FetchMode参数。

FetchMode里有几个常量,如下:

DEFAULT:使用配置文件制定的延迟加载策略处理。

JOIN:使用外连接,预初始化所有关联实体。

SELECT:启用延迟加载,系统将使用单独的select语句来初始化关联实体。只有当个真正访问关联实体的时候,才会执行第二条select语句。

初始化Student对象时,也可以初始化Student关联的Enrolment实体,实体使用如下代码:
List l = session.createCriteria(Student.class)

            .add(Restrictions.gt("studentNumber",20050231L))

            .setFetchMode("enrolments", FetchMode.JOIN)

            .list();


 

十五、投影、聚合和分组

投影运算实际上就是一个基于列的运算,通常用于投影到指定列(也就是过滤其他列,类似select子句的作用),还可以完成SQL语句中常用的分组、组筛选等功能。

Hibernate的条件过滤中使用Projection代表投影运算,Projection是一个接口,而Projections作为Projection的工厂,负责生成Projection对象。

一旦产生了Projection对象之后,就可通过Criteria提供的setProjection(Projection projection)方法来进行投影运算。从该方法上看,每个Criteria只能接受一个投影运算,似乎无法进行多个投影运算,但实际上Hibernate又提供了一个ProjectionList类,该类是Projection的子类,并可以包含多个投影运算,通过这种方式即完成多个投影运算。

因此,一个条件查询的投影运算通常有如下程序结构:

List cats = session.createCriteria(Cat.class)

                 .setProjection(Projections.projectionList()

                 .add(Projections.rowCount())

                 .add(Projections.avg("weight"))

                 .add(Projections.groupProperty("color"))

                  ).addOrder(Order.asc("color"))

                  .list();

注意:使用条件查询的投影运算时,不能使用显示的分组子句,但某些投影类型的实质就是分组投影,这些投影元素将出现在SQL的group by子句中——如上的groupProperty("color")投影。

投影运算的实质和group by子句、聚集函数的功能大致一致。

除此之外,如果我们希望对分组(投影)后属性进行排序,那就需要为投影运算指定一个别名。为投影运算指定别名有3种方法:

(1)使用Projections的alias()方法为指定投影指定别名。一旦为projection指定了别名,则程序就可以根据该Projection别名来进行其他额外操作了,比如排序。条件查询片段如下:

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course进行分组

           .add(Projections.groupProperty("course"))

           //统计记录条数,并为统计结果指定别名c

           .add(Projections.alias(Projections.rowCount()," c"))

             ).addOrder(Order, asc("c"))

           .list();

(2)使用SimpleProjection的as()方法为自身指定别名。

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course进行分组

           .add(Projections.groupProperty("course").as("c"))

           //统计记录条数,并为统计结果指定别名c

           .add(Projections.rowCount())

             ).addOrder(Order, asc("c"))

           .list();

(3)使用ProjectionList的add()方法添加投影时指定别名。

ProjectionList的add()方法有两个重载形式,一个是直接添加投影,另一个是在添加投影时指定别名。条件查询片段如下:

List l = session.createCriteria(Enrolment.class)

           .setProjection(Projections.projectionList()

            //按course进行分组,指定别名为c

           .add(Projections.groupProperty("course"),("c"))

           //统计记录条数,并为统计结果指定别名rc

           .add(Projections.rowCount(),"rc")

             ).addOrder(Order, asc("c"))

           .list();

除此之外,Hibernate还提供了Property执行投影运算,Property投影的作用类似于SQL语句中的select,条件查询的结果只有被Property投影的列才会被选出,条件查询片段如下:

List l = session.createCriteria(Student.class)

            .setProjection(Property.forName("name"))

            .list();

上面条件查询执行的结果不再是Student对象集合,而是name属性所组成的集合。


 

十六、离线查询和子查询

条件查询的离线查询由DetachedCriteria来代表,DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的Session来执行它。

DetachedCriteria还可代表子查询,当我们把DetachedCriteria传入Criteria中作为查询条件时,DetachedCriteria就变成了子查询。以下代码片段所示:

//定义一个离线查询

DetachedCriteria query = DetachedCriteria.forClass(Student.class)

                                         .forClass(Student.class)

                                         .setProjection(Property.forName("name"));

//打开Session和事务(省略)

//执行离线查询

List l = query.getExecutableCriteria(session).list();

//执行子查询

List l = session.createCriteria(Student.class)

           .add(Property.forName("name").in(query))

           .list();

如果程序使用Session的getExecutableCriteria()方法来执行DetachedCriteria对象,则它被当成离线查询使用;如果程序使用Property的系列方法来操作DetachedCriteria对象,则它被当成子查询使用。


 

十七、事务和Session

1、Session和用户请求是一对一得关系,这是一种理想的Session管理模式。

为了达到这种效果,推荐使用一个ThreadLocal变量,把Session绑定到处理客户端请求的线程上。这种方式可以让运行在该线程上的所有程序代码轻松地访问Session。也可以在一个ThreadLocal变量中保持事务上下文环境,不过这依赖于你所选择的数据库事务划分机制。这种实现模式被称为ThreadLocal Session和Open Session in View。

工具类代码如下:
public class HibernateUtil

{

       //使用一个final变量来保存不可变的SessionFactory

       public static final SessionFactory sessionFactory;

static{

         try{

             //采用默认的Hibernate.cfg,xml来启动一个Configuration的实例

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

             //由conf实例创建一个SessionFactory实例

             sessionFactory = conf.buildSessionFactory();

             }catch(Throwable ex){

                     System.err.println("初始化SessionFactory出现异常:"+ex);

                     throw new ExceptionInitializerError(ex);

            }

         }

//ThreadLocal是隔离多个线程的数据共享

//不存在多个线程之间共享资源,因此不再需要对线程同步

          public static final ThreadLocal session = new ThreadLocal();

          public static Session currentSession() throws HibernateException

          {

                Session s = (Session)session.get();

                //如果该线程还没有Session,则创建一个新的Session

                if(s == null)

                {

                    s = sessionFactory.openSession();

                //将获得的Session变量存储在ThreadLocal变量session里

                     session.set(s);

                 }

                 return s;

           }

           public static void closeSession() throws HibernateException

           {

                Session s = (Session)session.get();

                if(s != null)

                {

                       s.close();

                       session.set(null);

                }

           }

}

在上面的代码中,Hibernate Session被绑定到当前线程。当调用currentSession方法时,如果当前线程中的Session已经创建出来,那么将返回这个已经存在的Session实例。

注意:几乎所有情况下,都不要使用每个应用对应一次Hibernate Session的模式,也不要使用每次Http Session对应一次Hibernate Session的模式。

2、对于以上的情况,Hibernate主要有如下3种模式来解决这个问题:

(1)自动版本化:Hibernate能够自动进行乐观并发控制,如果在用户思考的过程中持久化实体发生并发修改,Hibernate能够自动检测到。

(2)脱管现象:如果采用每次用户请求对应一次Session的模式,那么,前面载入的实例在用户思考的过程中,始终与Session脱离,处于脱管状态。Hibernate允许把脱管对象重新关联到Session上,并且对修改进行持久化。在这种模式下,自动版本化被用来隔离并发修改。这种模式也被称为脱管对象的每次请求对应一个Hibernate Session。

(3)长生命周期Session:Session可以在数据库事务提交之后,断开和底层的JDBC连接。当新的客户端请求到来时,它又重新连接上底层的JDBC链接。这种模式被称为每个应用程序事务对应一个Session。因为应用程序事务时相当长(跨越多个用户请求)的,所以也被称为长生命周期Session。

注意:Session缓存了处于持久化状态的每个对象(Hibernate会监视和检查脏数据),也就是说,如果程序让Session打开很长一段时间,或者载入了很多数据,Session占用的内存会一直增长,直到抛出OutOfMemoryException异常。为了解决这个问题,程序定期调用Session的clear()和evict()方法来管理Session的缓存。对于一些大批量的数据处理,推荐使用DML风格的HQL语句完成。

3、为了保证在Session关闭之前初始化代理属性或集合属性,程序可以Hibernate,initialized()静态方法来强制初始化集合或代理。只要Session处于open状态,Hibernate.initialize(teahcer)将会强制初始化teacher代理,Hibernate.initialize(teacher.getStudents())对student的集合具有同样的功能。

还有另一种选择,就是程序让Session一直处于打开状态,直到装入所有需要的集合或代理。

保证Session处于打开状态有两种方法可以解决此问题:

(1)在一个Web应用中,可以利用过滤器(Filter),在用户请求结束、页面生成结束时关闭Session。也就是保证在视图层一直打开Session,这就是所谓的Open Session in View成视图界面的过程中发生异常时,必须保证可以正确关闭Session,并结束事务。

(2)使用业务逻辑层来准备数据,在业务逻辑层返回数据之前,业务逻辑层对每个所需集合调用Hibernate.initialize()方法,或者使用带fetch子句或FetchMethod.JOIN的查询,事先取得所有数据,并将这些数据封装成VO(值对象)集合,然后程序可以关闭Session了。业务逻辑层VO集传入视图层,让视图层只负责简单的显示逻辑。在这种模式下,可以让视图层和Hibernate API彻底分离,保证视图层不会出现持久层API,从而提供更好的解耦。


 

十七、上下文相关的Session

从Hibernate3.1开始,SessionFactory.getCurrentSession()的底层实现是可插拔的,Hibernate引入了CurrentSessionContext接口,并通过hibernate_current_session_context_class参数来管理上下文相关Session的底层实现。

CurrentSessionContext接口有如下3个实现类:

org.hibernate.context.JTASessionContext:根据JTA来跟踪和界定上下文相关Session,这和最早的仅支持JTA的方法是完全一样的。

org.hibernate.context.ThreadLocalSessionContext:通过当前正在执行的线程来跟踪和界定上下文相关Session,也就是和前面的HibernateUtil的Session维护模式相似。

org.hibernate.context.ManagedSessionContext:通过当前执行的线程来跟踪和界定上下文相关的Session。但是程序需要使用这个类的静态方法将Session实例绑定、取消绑定,它并不会自动打开、flush或者关闭任何Session。

对于容器中使用Hibernate的场景而言,通常会采用第一种方式:对于独立的Hibernate应用而言,通常会采用第二种方式。

为了指定Hibernate使用哪种Session管理方式,可以在hibernate.cfg.xml文件中增加如下片段:

<property name="hibernate.current_session_context_class">thread</property>

如果在JTA事务环境中,则应增加如下配置片段:

<property name="hibernate.current_session_context_class">jta</property>

对于第三种不常用的Session管理机制,则可在配置文件中简写成:managed。

posted on 2011-11-19 14:05 小熊宝贝的每一天 阅读(4525) 评论(1)  编辑  收藏

评论:
# re: 11.19之HQL----用于获取对象的。 2013-07-07 21:18 | 拍砖
终于看完了, 自己也跟着翘了一遍, 受益匪浅, 非常感谢。  回复  更多评论
  

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


网站导航: