最近的项目打算用SPRINGMVC+HIBERNATE来实现,因为我们打算把这个项目做成一个产品,所以使用HIBERNATE希望
可以部署在不同的数据库服务器上。
但是使用HQL调用自定义函数的时候却出现了问题。比如 select user.id, my_function(user.id) from USER u,执行这个HQL
会报如下的错误:
java.lang.IllegalStateException: No data type for node: org.hibernate.hql.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: '('
+-[METHOD_NAME] IdentNode: 'my_function' {originalText=my_function}
在网上找了下,解决方法是重写对应的数据库方言,然后配置到hibernate.dialect上,但是考虑到以后切换到不同的数据库,
需要重写对应的方言,反而影响程序的跨平台性。因为如果我的函数采用标准SQL,HIERNATE调用本地SQL的时候并不影响跨平台
性(我想的没问题吧?)。
所以我打算直接用HIBERNATE调用本地SQL,这个方法有很多,我用的是采用NAMED-SQL方式,把SQL写在配置文件里,
这样也方便维护。
<bean id="sessionFactoryCzyw" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSourceCzyw" />
<property name="mappingLocations">
<list>
<value>classpath:com/wei/liu/springmvc/czyw/**/*.hbm.xml</value><!-- 加载hibernate的映射文件*.hbm.xml -->
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
</props>
</property>
<property name="packagesToScan">
<value>com.xxx.xxx..</value>
</property>
</bean>
因为我采用的是注解的方式映射的实体类,所以XXX.hbm.xml只有SQL语句,如下:
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xxx.xxx.xxx.xxx">
<sql-query name="selectXXX">
<return alias="t" class="xxx.xxx.xxx.xxx.User"></return>
<![CDATA[
SELECT id,my_function(id) from user
]]>
</sql-query>
</hibernate-mapping>
这样在java中就可以直接通过session来调用这条语句了
session.getNamedQuery("selectXXX").setFirstResult(begin).setMaxResults(pageSize).list();
这里要注意的是,select后面要把所有的字段都写出来,不然的话会报如下的错误:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query
Caused by: org.hibernate.exception.SQLGrammarException: could not execute query
Caused by: java.sql.SQLException: Invalid column name XXXX(少的那个列名).
如果不想写映射文件,也可以把SQL写在对应的实体类中,如下:
@Entity
@Table(name = "XXX", schema = "XXX", catalog = "XXX")
@NamedNativeQuery(name = "XXX", query = "XXX")
public class XXXimplements java.io.Serializable {
把对应的XXX替换掉即可。