最近接手了一个要维护的项目,是用Hibernate2+Oralce8写成的,因为看到Hibernate3页出来这么久了,而且也感觉Hibernate3有它的许多新的特性,如批量删除和更新,新的HQL语法解析器AST。
升级过程大致按照孙卫琴的那篇文章 如何把Hibernate2.1升级到Hibernate3.0?来做,该替换的替换完,该设置的设置完,程序一跑,当程序执行到向下面这种查询的时候(Oracle所特有的外连接查询),报错。
语句为:(描述为类似语句,把项目中的实际表名隐去了)
session.createQuery("select t1.c1,t2.c1 from Table1 t1,Table2 t2 where t1.c1=t2.c1(+)").list();
出错信息为:
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ) near line 1, column 106 [select t1.c1,t2.c1 from Table1 t1,Table2 t2 where t1.c1=t2.c1(+)]
at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:31)
at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:24)
at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:59)
at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:258)
at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:157)
at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)
at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1623)
再回头看看孙卫琴的那篇升级注意事项中 1.3 查询语句的变化 提到Hibernate3.0 采用新的基于ANTLR的HQL/SQL查询翻译器ASTQueryTranslator,它已经不支持像Oracle8i和Sybase11那样的 THETA-STYLE 连接查询方言。
解决这一问题的办法有两种:
(1)改为使用支持ANSI-STYLE连接查询的方言,像 LEFT OUTER JOIN .. ON ..的写法
(2)也可改用 Hibernate2的查询翻译器,可在 hibernate.cfg.xml 中进行配置。
因第一种方法,需要在映射文件中配置PO 间的X 对X的关联关系才能用,如过哪位朋友在不配置 PO 间关联关系时也能用LEFT OUTER JOIN .. ON ..的写法连接查询,能告诉我怎么做的号吗?让咱也学一招,先谢了!
所以想想还是在 hibernate.cfg.xml 中配置
注:hibernate3默认的HQL语法翻译器的配置为:
使用传统的hibernat2所用的HQL语法翻译器。然后程序再跑一跑,刚刚那个(+)的地方是没有错了,可是新麻烦有冒起来了,程序执行到
session.createQuery("delete User u where u.name='Unmi'").executeUpdate();
有报错了:
org.hibernate.QueryException: query must begin with SELECT or FROM: delete [delete com.unmi.User where u.name='Unmi']
原来旧的HQL语法解析器不支持 delete User 的写法,hibernate2在删除持久化对象时必须写成
session.delete("delete User u where u.name='Unmi'");
然而新的 org.hibernate.Session 的接口方法已去除了 Session.delete(String hql)方法,看来这条路也是受阻了。正是两头受难,无奈之时暂时放弃了升级的念头,把该还原的地方都恢复旧模样了。
过了好一段时间,也就是个把月吧……
心里总也觉不甘心,觉得事情总有解决的办法,于是采用了终极办法:从原代码下手,进行单步的跟踪,看看hibernate3何时进行HQL到SQL的转换,何时取用配置的语法翻译器。
下面要解决的一个课题就是:
如何让Hibernate3既能使用新的Delete和Update语法,又能使用 Oracle Theta-Style 的 t1.c1=t2.c1(+)外连接写法
其中的语法翻译器如何把传入的一条HQL语句拆解进行分析这里就不详叙,不过最好还是要明白一点:
Classic语法翻译器会把传入的t1.c1=t2.c1(+)中的(+)作为一个整体,不拆开来,而AST语法分析器却会把其中的(+)依括号拆成 ”(” , ”+” , ”)”三部分。
我们首先来看看HQL语法翻译工厂接口 QueryTranslatorFatory 有两个接口方法:
调用以上两个方法只在类 HQLQueryPlan的构造函数中(五个参数的那个)
这个构造函数接收你写的HQL语句还有一个 SessionFactoryImplementor (extends SessionFactory),这个SessionFactory持有hibernate.cfg.xml的配置项HQL语法翻译器。
读这个构造函数的代码,我们发现有两段代码
它们的职能是获取SessionFactory (hibernate.cfg.xml)所配置的HQL语法分析器,这也就是我们的切入点,我们所希望的事情是:
当构造HQLQueryPlan时,发现传给的hql是一个Oracle 那样的THETA-STYLE 连接查询语句(即像有(+)那样的语句),我们就绕开在 hibernate.cfg.xml 所配置的AST HQL语法翻译器,而是采用能够理解这种语法的传统的语法翻译器。
因此我们只要把 HQLQueryPlan类的这个构造函数中的
if ( collectionRole == null) { …………………………… }
改为如下:
改完之后,把编译后的HQLQueryPlan.class覆盖到hibernate3.jar包中相应的目录中即可,或者把这个类放在classes下相应的目录中,在WEB应用程序中 WEB-INF/classes中的类是优先于jar包中的类先加载。
以上做法两种有些矛盾的问题也就得到解决了,org.hibernate.Session既可以执行Hibernate3 引入的 delete/update语句,还能够在 Oracle/Sybase中用(+)外连接方式而不需要配置X对X的连接关系。
下面再介绍一种折中的解决办法,不知大家注意到没有,在Hibernate3中的
org.hibernate.SessionFactory的openSession方法返回的是一个
org.hibernate.classic.Session对象,而org.hibernate.classic.Session是继承自org.hibernate.Session的。
public org.hibernate.classic.Session openSession(Connection connection);
public interface Session extends org.hibernate.Session
而通常我们顺应新潮流,是用org.hibernate.Session去引用SessionFactory的方法openSession()的返回值的,于是我们想用 session.delete(sql) 方法时,就把返回的Session实例转型为 org.hibernate.classic.Session即可。
((org.hibernate.classic.Session)session).delete("from User u where u.name='Unmi'");
如果你也想用原始Session的其他已被摈弃的方法,亦可如此这般做。
当然了,在另一方面要让Hibernate 能支持 Oracle/Sybase中用(+)外连接方式, 您还是要使
用传统的语法分析器,他将不能理解新的delete/update语句,很遗憾。
所以为了顺应新的潮流的发展,应使用第一种方法。要知道hibernate3中的delete/update语句可比2中的session.delete(hql)方法效率高,hibernate3中直接向数据库发一个delete语句,而在hibernate2中的delete(hql)方法是需要首先加载对象在删除,确有些多次一举,不过又是也有它的道理,update也类此。
在补充一个:hibernate会对 hql 对应的 HQLQueryPlan 进行缓冲的,在类 QueryPlanCache 中处理
依据queryString(hql)生成key值.
转自:http://blog.csdn.net/kypfos/article/details/1559554
分享到:
相关推荐
**Hibernate实现原理模拟** 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。本教程将通过模拟Hibernate的实现原理,帮助开发者深入理解其工作方式,以便更好地运用到实际...
本篇将详细介绍如何在Hibernate中配置这些连接池,并探讨其工作原理和优势。 **一、C3P0连接池** C3P0是较早流行的一种开源连接池实现,它提供了一套完善的数据库连接管理机制。在Hibernate中配置C3P0,我们需要在...
【标题】:“Hibernate、Spring和Struts工作原理及使用理由” 【内容】: Hibernate是一个流行的Java持久化框架,它的核心工作原理主要包括以下步骤: 1. **读取并解析配置文件**:Hibernate通过读取hibernate....
配置Hibernate连接池通常涉及到以下几个步骤: 1. **选择连接池**:首先,你需要决定使用哪个连接池实现。比如,如果你选择C3P0,你需要添加对应的依赖到项目中。 2. **配置Hibernate**:在Hibernate的配置文件...
在Java应用中,要使用Hibernate连接MySQL数据库,首先需要在`hibernate.cfg.xml`配置文件中设置数据库连接信息,包括URL、用户名、密码和驱动类名。例如: ```xml <property name="hibernate.connection.url">jdbc:...
至于 Hibernate 的缓存机制,除了第一级缓存外,还有一级集合缓存和二级缓存。一级集合缓存存储实体之间的关联,二级缓存则是一个可选的、进程范围内的缓存,可以跨多个 `SessionFactory` 实例共享。这些缓存策略有...
数据库连接池的基本原理是预先创建一定数量的数据库连接,当应用程序需要访问数据库时,可以从池中获取一个已建立的连接,使用完毕后归还给池而不是直接关闭,这样避免了频繁的创建和销毁连接带来的开销。...
### Hibernate原理深度解析 #### Hibernate为何重要? Hibernate作为一款开源的对象关系映射(ORM)框架,在Java开发领域占据着举足轻重的地位。其重要性体现在以下几个方面: 1. **资源管理**:Hibernate通过...
标题中的“hibernate数据库连接”指的是Java编程中使用Hibernate框架与数据库进行交互的技术。Hibernate是一个强大的对象关系映射(ORM)工具,它允许开发者用Java对象来操作数据库,简化了数据库操作的复杂性。 在...
在本项目中,“hibernate连接Access应用项目例子”展示了如何使用Hibernate ORM框架与Microsoft Access数据库进行集成,实现数据的增、删、改、查(CRUD)操作。Hibernate是Java开发中的一个流行ORM(对象关系映射)...
本文将深入探讨Hibernate数据库连接池的实现原理、配置方法以及其在Java命名和目录查找中的应用。 首先,我们了解下什么是数据库连接池。数据库连接池在初始化时会创建一定数量的数据库连接,这些连接在应用程序...
当使用Hibernate连接SQL Server 2000时,我们需要考虑以下几个关键点: 1. **驱动兼容性**:SQL Server 2000使用的是JDBC 3.0驱动,因此需要确保选用的Hibernate版本和JDBC驱动兼容此版本。通常,较早的Hibernate...
【Hibernate工作原理】 Hibernate是一个ORM(Object-Relational Mapping)框架,它将Java对象与关系数据库的数据进行映射,实现了对象与数据库之间的一套映射规则。其主要工作流程包括: 1. 加载并解析配置文件和...
**hibernate连接数据[Mysql]的代码实例** 在Java应用程序中,Hibernate是一个非常流行的ORM(Object-Relational Mapping)框架,它提供了强大的数据库操作能力,简化了Java与关系型数据库如MySQL之间的交互。本实例将...
Hibernate中的`Session`接口是数据操作的主要入口,它模拟了数据库连接的概念,负责管理对象的状态。`Transaction`则用于处理数据库的事务,确保数据的一致性和完整性。 3. **Entity和持久化类** 在Hibernate中,...
#### 二、Hibernate与C3P0集成的基本原理 在集成Hibernate与C3P0时,主要利用C3P0作为Hibernate的后端连接池,实现数据库连接的高效复用。这种方式可以显著提高应用程序的性能,尤其是在高并发环境下。 #### 三、...
Hibernate 工作原理及为什么要用 Hibernate 作为一个开放源代码的对象关系映射框架,对 JDBC 进行了轻量级的对象封装,使 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。下面将详细介绍 Hibernate 的...
### Hibernate 体系结构与工作原理 #### 一、概述 Hibernate 是一款开源的对象关系映射(Object Relational Mapping,简称 ORM)框架,它为 Java 应用程序提供了一种将对象模型与数据库模型进行映射的方式,使得...
在Java的持久层框架Hibernate中,数据库连接管理是至关重要的。`Proxool`是一个开源的连接池实现,它能够帮助我们有效地管理数据库连接,提高系统性能并减少资源消耗。当我们遇到数据库连接断开的情况时,`Hibernate...