1. 程式人生 > >在hibernate中直接執行原生sql遇到型別轉換問題

在hibernate中直接執行原生sql遇到型別轉換問題

今天做了個用hibernate直接執行原生sql的查詢,遇到char型別的資料庫欄位查出來只能截斷成一位,後經高人指導,要用自定義的方言,如下:

public class OracleDialect extends Oracle10gDialect
{

 public OracleDialect()
 {
  registerHibernateType(91, Hibernate.TIMESTAMP.getName());
  registerHibernateType(1, Hibernate.STRING.getName());
 }
}

然後又在在網上查了一下,裡面提到很高關於自定義方言來解決一些資料庫欄位型別的問題,這裡總結一下。方便大家查詢。

第一種: No Dialect mapping for JDBC type: 3;

檢視文章
ERROR 解決記錄 - No Dialect mapping for JDBC type: 3; 2007-11-28 16:34
        今天在使用getSession().createSQLQuery("SELECT SUM(aloneIp) FROM table").list();
時出現了錯誤:No Dialect mapping for JDBC type: 3;

baidu,google了一番後,各位都說:“出現這個原因是說伺服器端的資料型別並不能和Java的BigDecimal資料型別成功對映。”;

不過我的資料庫中“aloneIp”列的型別為INTEGER,出現這個錯誤不知是何原因。

根據以下解決方法,問題得以解決,記錄之:
1、新建一個MMySQLDialect extends org.hibernate.dialect.MySQLDialect (我使用的資料庫是MYSQL)並在裡面補充註冊新的型別對映。如下:
import java.sql.Types;
import org.hibernate.Hibernate;
import org.hibernate.dialect.MySQLDialect;

public class MMySQLDialect extends MySQLDialect {
    public MMySQLDialect () {
        super();
        registerHibernateType(Types.DECIMAL, Hibernate.BIG_INTEGER.getName());
    }
}
2、把Hibernate裡的Dialect改成我們第一步新建的新的Dialect

<prop key="hibernate.dialect">[包路徑].MMySQLDialect </prop>

第二種: org.hibernate.MappingException: No Dialect mapping for JDBC type: -1

環境是:SQL Server2005 + Hibernate3.2.5

問題原因:

資料庫表中有text型別的欄位,而Hibernate在native查詢中沒有註冊這個欄位,因此發生這個錯誤。

解決方法:

寫一個類、修改hibernate配置檔案。 寫一個Dialect的子類,這裡我 extends SQLServerDialectt類:

package com.zy.util;

import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.dialect.SQLServerDialect;

public class DialectForInkfish extends SQLServerDialect {
public DialectForInkfish() {
   super();
   //registerHibernateType(Types.LONGVARCHAR, 65535, "text");//.LONGVARCHAR
   registerHibernateType(Types.DECIMAL, Hibernate.BIG_DECIMAL.getName());  
        registerHibernateType(-1, Hibernate.STRING.getName());
}

}

修改Hibernate配置檔案hibernate.cfg.xml,把

<property name="dialect">  
   org.hibernate.dialect.SQLServerDialect
</property>

修改成:

<property name="dialect">  
   com.zy.util.DialectForInkfish
</property>

說明: 如果你的資料庫是mysql,而又用了decimal型別,報錯應該是 No Dialect mapping for JDBC type: 3 . 注意這個3, 它說明hibernate不能將這種資料型別對映到你的java類中. 就需要在自定義的方言中用到:

registerHibernateType(Types.DECIMAL, Hibernate.BIG_DECIMAL.getName());  

一個比較詳細的說明:

前段時間碰到了這類錯誤,最後的問號表示不確定的數字,但是解決的方法都一樣。

首先,自定義一個方言類——Hibernate Dialect,該類需要繼承與我們使用的資料庫相應的方言類。比如:如果我們用的是MySql(版本為5.x.x),我們需要繼承“org.hibernate.dialect.MySQL5Dialect”;如果我們使用的是DB2,那麼我們應該繼承“org.hibernate.dialect.DB2Dialect”;我用的是SqlServer2008,所以我要繼承“org.hibernate.dialect.SQLServerDialect”,參考程式碼如下:

Java程式碼 複製程式碼
  1. import java.sql.Types;   
  2. import org.hibernate.Hibernate;   
  3. import org.hibernate.dialect.SQLServerDialect;   
  4. public class SqlServer2008Dialect extends SQLServerDialect {   
  5.     public SqlServer2008Dialect() {   
  6.         super();   
  7.         registerHibernateType(Types.CHAR, Hibernate.STRING.getName());   
  8.         registerHibernateType(Types.NVARCHAR, Hibernate.STRING.getName());   
  9.         registerHibernateType(Types.LONGNVARCHAR, Hibernate.STRING.getName());   
  10.         registerHibernateType(Types.DECIMAL, Hibernate.DOUBLE.getName());   
  11.     }   
  12. }  
import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.dialect.SQLServerDialect;

public class SqlServer2008Dialect extends SQLServerDialect {

	public SqlServer2008Dialect() {
		super();
		registerHibernateType(Types.CHAR, Hibernate.STRING.getName());
		registerHibernateType(Types.NVARCHAR, Hibernate.STRING.getName());
		registerHibernateType(Types.LONGNVARCHAR, Hibernate.STRING.getName());
		registerHibernateType(Types.DECIMAL, Hibernate.DOUBLE.getName());
	}
}

總之大家可以在“org.hibernate.dialect”這個package中找到與資料庫相對應的方言類。在其中,我們需要注意三點點:

a、在預設構造方法中繼承父類構造方法,同時呼叫“registerHibernateType(int code, String name)”方法將資料庫中該資料型別對映到相應的java型別。code表示資料庫中的資料型別整數表示,可以在“java.sql.Types”類中查到相應的資料庫型別。name表示我們要對映的java型別。可以從“org.hibernate.Hibernate”中查到。

b、Types類。在Types中定義了資料庫常用的欄位型別,如:

Java程式碼 複製程式碼
  1. ……   
  2. public final static int LONGVARCHAR =  -1;   
  3. public final static int TIMESTAMP =  93;   
  4. ……  
……
public final static int LONGVARCHAR =  -1;
public final static int TIMESTAMP =  93;
……

我們可以根據“No Dialect mapping for JDBC type : ”後面緊跟的數字在該類(Types)中找到相應的型別。我們也可以根據資料表中欄位的型別找到相應的值。這個值就是registerHibernateType(int code, String name)的第一個引數。

c、Hibernate類。Hibernate中定義了轉換的目的型別,如第一段程式碼所示。能夠轉化成什麼型別,可以在該類中查詢。通過呼叫“getName()”方法得到一個String型。當然,如果你記住了,我們還可以這樣寫

Java程式碼 複製程式碼
  1. import org.hibernate.dialect.SQLServerDialect;   
  2. public class SqlServer2008Dialect extends SQLServerDialect {   
  3.     public SqlServer2008Dialect() {   
  4.         super();   
  5.         registerHibernateType(1"string");   
  6.         registerHibernateType(-9"string");   
  7.         registerHibernateType(-16"string");   
  8.         registerHibernateType(3"double");   
  9.     }   
  10. }  
import org.hibernate.dialect.SQLServerDialect;

public class SqlServer2008Dialect extends SQLServerDialect {

	public SqlServer2008Dialect() {
		super();
		registerHibernateType(1, "string");
		registerHibernateType(-9, "string");
		registerHibernateType(-16, "string");
		registerHibernateType(3, "double");
	}
}

其實和上面是一樣的,只是把上面所代表的值直接寫出來了。O(∩_∩)O哈哈~。需要注意的是super()方法的呼叫,不呼叫該方法是否會出現錯誤,我這就不知道了,這個我沒有做過測試,所以最好調一下。

然後,我們還需要在配置檔案中作修改。我用的是EJB3,所以我在META-INF資料夾下的persistent.xml檔案中新增屬性“hibernate.dialect”,value值為“xxx.xxx.SqlServer2008Dialect ”,xxx表示包名,這個大家都知道。程式碼如下:

Java程式碼 複製程式碼
  1. <?xml version="1.0" encoding="UTF-8" ?>   
  2. <persistence xmlns="http://java.sun.com/xml/ns/persistence"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence   
  5.         http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"   
  6.     version="1.0">   
  7.     <persistence-unit name="DateSource">   
  8.         <jta-data-source>java:/SqlServerDS</jta-data-source>   
  9.         <properties>   
  10.             <property name="hibernate.dialect" value="xxx.xxx.SqlServer2008Dialect"/>   
  11.             <property name="hibernate.hbm2ddl.auto" value="none" />   
  12.         </properties>   
  13.     </persistence-unit>   
  14. </persistence>  
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">
	<persistence-unit name="DateSource">
		<jta-data-source>java:/SqlServerDS</jta-data-source>
		<properties>
			<property name="hibernate.dialect" value="xxx.xxx.SqlServer2008Dialect"/>
			<property name="hibernate.hbm2ddl.auto" value="none" />
		</properties>
	</persistence-unit>
</persistence>

 打包部署,OK!當然,如果你使用的是Hibernate,則修改Hibernate配置檔案hibernate.cfg.xml,將“hibernate.dialect”屬性的值改為自己的方言類“xxx.xxx.SqlServer2008Dialect ”即可。