欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

No Dialect mapping for JDBC type -9

程序员文章站 2022-04-13 16:02:56
...

项目使用SSHM框架,使用Oracle数据库,编写了测试类测试报:No Dialect mapping for JDBC type-9,从错误可以看出是没有方言映射到JDBC的类型,由于使用的是Hibernate映射的数据库方言,且查询数据库字段是NVARCHAR2()类型的,这样问题就比较清晰了,是NVARCHAR2()类型映射不到Java数据类型,我的Hibernate配置如下:

<!-- Hibernate 配置 -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">
					${db.Dialect.prefix}.${db.Dialect.suffix}
				</prop>
				<prop key="hibernate.query.substitutions">
					true '1', false '0'
				</prop>
				<prop key="hibernate.validator.apply_to_ddl">false</prop> 
                <prop key="hibernate.validator.autoregister_listeners">false</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.use_sql_comments">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>

				<prop key="hibernate.current_session_context_class">
					org.springframework.orm.hibernate4.SpringSessionContext
				</prop>
				<prop key="jdbc.use_scrollable_resultset">false</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.cache.use_second_level_cache">true</prop>
				<prop key="hibernate.cache.region.factory_class">
					org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
				</prop>
				<prop key="hibernate.cache.provider_class">
					org.hibernate.cache.EhCacheProvider
				</prop>
				<prop key="hibernate.cache.provider_configuration_file_resource_path">
					classpath*:/ehcache-hibernate.xml
				</prop>
			</props>
		</property>
		<property name="mappingJarLocations">
			<list>
				<value>/WEB-INF/lib/gene4.0.11120.jar</value>
				<value>/WEB-INF/lib/module4.0.jar</value-->
			</list>
		</property>
		<property name="packagesToScan">
			<list>
				<value>com.test.**.entity</value>
			</list>
		</property>
	</bean>

Hibernate使用的方言是jdbc.properties中配置的,jdbc.properties配置的方言如下:

#=========================================
# DataBase Connection Setting  Oracle
#=========================================
db.Dialect.prefix=org.hibernate.dialect
db.Dialect.suffix=OracleDialect
db.driverClassName=oracle.jdbc.driver.OracleDriver
db.url = jdbc:oracle:thin:@192.168.1.100:1521:orcl
db.username = test
db.password = test

配置中使用的方言是org.hibernate.dialect. OracleDialect,我们看看OracleDialect的源码:

/*     */ package org.hibernate.dialect;
/*     */ 
/*     */ import org.hibernate.internal.CoreMessageLogger;
/*     */ import org.hibernate.sql.CaseFragment;
/*     */ import org.hibernate.sql.DecodeCaseFragment;
/*     */ import org.hibernate.sql.JoinFragment;
/*     */ import org.hibernate.sql.OracleJoinFragment;
/*     */ import org.jboss.logging.Logger;
/*     */ 
/*     */ @Deprecated
/*     */ public class OracleDialect
/*     */   extends Oracle9Dialect
/*     */ {
/*  45 */   private static final CoreMessageLogger LOG = (CoreMessageLogger)Logger.getMessageLogger(CoreMessageLogger.class, OracleDialect.class.getName());
/*     */ 
/*     */   public OracleDialect()
/*     */   {
/*  55 */     LOG.deprecatedOracleDialect();
/*     */     
/*  58 */     registerColumnType(93, "date");
/*  59 */     registerColumnType(1, "char(1)");
/*  60 */     registerColumnType(12, 4000L, "varchar2($l)");
/*     */   }
/*     */   
/*     */   public JoinFragment createOuterJoinFragment()
/*     */   {
/*  65 */     return new OracleJoinFragment();
/*     */   }
/*     */   
/*     */   public CaseFragment createCaseFragment()
/*     */   {
/*  70 */     return new DecodeCaseFragment();
/*     */   }
/*     */   
/*     */   public String getLimitString(String sql, boolean hasOffset)
/*     */   {
/*  76 */     sql = sql.trim();
/*  77 */     boolean isForUpdate = false;
/*  78 */     if (sql.toLowerCase().endsWith(" for update")) {
/*  79 */       sql = sql.substring(0, sql.length() - 11);
/*  80 */       isForUpdate = true;
/*     */     }
/*     */     
/*  83 */     StringBuilder pagingSelect = new StringBuilder(sql.length() + 100);
/*  84 */     if (hasOffset) {
/*  85 */       pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
/*     */     }
/*     */     else {
/*  88 */       pagingSelect.append("select * from ( ");
/*     */     }
/*  90 */     pagingSelect.append(sql);
/*  91 */     if (hasOffset) {
/*  92 */       pagingSelect.append(" ) row_ ) where rownum_ <= ? and rownum_ > ?");
/*     */     }
/*     */     else {
/*  95 */       pagingSelect.append(" ) where rownum <= ?");
/*     */     }
/*     */     
/*  98 */     if (isForUpdate) {
/*  99 */       pagingSelect.append(" for update");
/*     */     }
/*     */     
/* 102 */     return pagingSelect.toString();
/*     */   }
/*     */   
/*     */   public String getSelectClauseNullString(int sqlType)
/*     */   {
/* 107 */     switch (sqlType) {
/*     */     case 1: 
/*     */     case 12: 
/* 110 */       return "to_char(null)";
/*     */     case 91: 
/*     */     case 92: 
/*     */     case 93: 
/* 114 */       return "to_date(null)";
/*     */     }
/* 116 */     return "to_number(null)";
/*     */   }
/*     */ 
/*     */   public String getCurrentTimestampSelectString()
/*     */   {
/* 122 */     return "select sysdate from dual";
/*     */   }
/*     */   
/*     */   public String getCurrentTimestampSQLFunctionName()
/*     */   {
/* 127 */     return "sysdate";
/*     */   }
/*     */ }

/* Location:           D:\Workspaces\MyEclipse Professional 2014\customerchat\WebRoot\WEB-INF\lib\hibernate-core-4.3.5.Final.jar
 * Qualified Name:     org.hibernate.dialect.OracleDialect
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.0.1
 */

可以看出,OracleDialect继承的还是Oracle9的方言的类,版本太老了,没有对NVARCHAR2()类型的处理,比较两个版本的数据类型还是有不少差异的,再观察hibernate-core-4.3.5.Final.jar包可以发现,实现的最新版本是Oracle10gDialect,且并未对数据类型处理做什么改变,因此我们只有自己动手,实现方言类,让Hibernate使用我们自定义的类了,观察Oracle10gDialect,我们可以继承这个来,在构造函数中对数据类型进行处理:

import java.sql.Types;

import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.type.StandardBasicTypes;

public class MyOracleDialect extends Oracle10gDialect
{
    public MyOracleDialect(){
        registerHibernateType(Types.CHAR, StandardBasicTypes.STRING.getName());          
        registerHibernateType(Types.NVARCHAR, StandardBasicTypes.STRING.getName());        
        registerHibernateType(Types.LONGNVARCHAR, StandardBasicTypes.STRING.getName());  
        registerHibernateType(Types.DECIMAL, StandardBasicTypes.DOUBLE.getName());        
        registerHibernateType(Types.NCLOB, StandardBasicTypes.STRING.getName());
    }
}

然后在修改jdbc.properties,使用我们自定义的类路径:

#=========================================
# DataBase Connection Setting  Oracle
#=========================================
#db.Dialect.prefix=org.hibernate.dialect
#db.Dialect.suffix=OracleDialect
db.Dialect.prefix=com.test.utils
db.Dialect.suffix=MyOracleDialect
db.driverClassName=oracle.jdbc.driver.OracleDriver
db.url = jdbc:oracle:thin:@192.168.1.222:1521:orcl
db.username = test
db.password = test

然后重启服务器执行测试代码成功。

这里在提一点测试时使用的是junit,我们知道junit是通过指定applicationContext.xml来让容器加载我们创建的类的,由于我使用的是Hibernatesession,所以报了下面的错误:

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
	at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
	at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)

从错误中也可以看出是Hibernate获取session失败,而我使用服务器页面调代码测试就是成功的,查了半天原因就在于junit是直接加载applicationContext.xml来加载其他类的,而漏掉了web.xml中配置的Hibernate打开session的过滤器。。。

<filter>
	<filter-name>hibernateOpenSessionInViewFilter</filter-name>
	<filter-class>
		org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>hibernateOpenSessionInViewFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

这也是如果使用junit测试,且用到了Hibernate中的session时需要注意的地方。