Hibernate类型映射

官方文档参照的是:

[plain] view plain copy
  1. hibernate-distribution-3.6.0.Final\documentation\manual\zh-CN\pdf\hibernate_reference.pdf  

源代码参照的是:

[plain] view plain copy
  1. hibernate-3.3.1.GA-src\core\src\main\java\org\hibernate\...  

在配置hibernate的时候,虽然配置项很多,但是看似只有方言和hibernate类型映射有些关联,那么就先从方言入手

先来看个时间类型的,以Oracle9iDialect类为例,其中有如下方法:

  1. public class Oracle9iDialect extends Oracle8iDialect {  
  2.         ...  
  3.     protected void registerDateTimeTypeMappings() {  
  4.         registerColumnType( Types.DATE, "date" );  
  5.         registerColumnType( Types.TIME, "date" );  
  6.         registerColumnType( Types.TIMESTAMP, "timestamp" );  
  7.     }  

然后再来看看Oracle8iDialect类:

  1. public class Oracle8iDialect extends Dialect {  
  2.         ...  
  3.     protected void registerDateTimeTypeMappings() {  
  4.         registerColumnType( Types.DATE, "date" );  
  5.         registerColumnType( Types.TIME, "date" );  
  6.         registerColumnType( Types.TIMESTAMP, "date" );  
  7.     }  

经过观察,这些方言都引入了一个类:

  1. import java.sql.Types;  

来看看jdk是怎么描述这个类的:

[plain] view plain copy
  1. 定义用于标识一般 SQL 类型(称为 JDBC 类型)的常量的类。  
  2.           ...  
  3. static int DATE   
  4.           标识一般 SQL 类型 DATE 的 Java 编程语言中的常量(有时称为类型代码)。   

说明hibernate维护了一个java类型到jdbc类型的对应关系,以此类推

接下来看看registerDateTimeTypeMappings这个方法,Dialect类中并没有这个方法,该方法是在Oracle8iDialect类初始化时加入的,Oracle9iDialect类重写了该方法

(估计是应为每个数据库的日期类型都不一样,所有不会放到共同父类Dialect中):

  1. public class Oracle8iDialect extends Dialect {  
  2.          public Oracle8iDialect() {  
  3.         super();  
  4.         registerCharacterTypeMappings();  
  5.         registerNumericTypeMappings();  
  6.         <span style="color:#ff0000;">registerDateTimeTypeMappings();  
  7. </span>                ...  
  8.          }  

但是Oracle8iDialect类和Oracle9iDialect类中都没有重写该方法调用的registerColumnType方法,那么我们看看Dialect类中该方法是如何实现的:

  1. private final TypeNames hibernateTypeNames = new TypeNames();  
  2. ...  
  3. protected void registerColumnType(int code, String name) {  
  4.     typeNames.put( code, name );  
  5. }  

我们再来看看这个typeNames是个什么东西(没有import该类,那么说明和方言是在同一个包路径下):

  1. public class TypeNames {  
  2.     private HashMap weighted = new HashMap();  
  3.     private HashMap defaults = new HashMap();  
  4.   
  5.     /** 
  6.      * get default type name for specified type 
  7.      * @param typecode the type key 
  8.      * @return the default type name associated with specified key 
  9.      */  
  10.     public String get(int typecode) throws MappingException {  
  11.         String result = (String) defaults.get( new Integer(typecode) );  
  12.         if (result==nullthrow new MappingException("<span style="color:#ff0000;">No Dialect mapping for JDBC type: " + typecode</span>);  
  13.         return result;  
  14.     }  
  15.   
  16.     /** 
  17.      * get type name for specified type and size 
  18.      * @param typecode the type key 
  19.      * @param size the SQL length 
  20.      * @param scale the SQL scale 
  21.      * @param precision the SQL precision 
  22.      * @return the associated name with smallest capacity >= size, 
  23.      * if available and the default type name otherwise 
  24.      */  
  25.     public String get(int typecode, int size, int precision, int scale) throws MappingException {  
  26.         Map map = (Map) weighted.get( new Integer(typecode) );  
  27.         if ( map!=null && map.size()>0 ) {  
  28.             // iterate entries ordered by capacity to find first fit  
  29.             Iterator entries = map.entrySet().iterator();  
  30.             while ( entries.hasNext() ) {  
  31.                 Map.Entry entry = (Map.Entry)entries.next();  
  32.                 if ( size <= ( (Integer) entry.getKey() ).intValue() ) {  
  33.                     return replace( (String) entry.getValue(), size, precision, scale );  
  34.                 }  
  35.             }  
  36.         }  
  37.         return replace( get(typecode), size, precision, scale );  
  38.     }  
  39.       
  40.     private static String replace(String type, int size, int precision, int scale) {  
  41.         type = StringHelper.replaceOnce(type, "$s", Integer.toString(scale) );  
  42.         type = StringHelper.replaceOnce(type, "$l", Integer.toString(size) );  
  43.         return StringHelper.replaceOnce(type, "$p", Integer.toString(precision) );  
  44.     }  
  45.   
  46.     /** 
  47.      * set a type name for specified type key and capacity 
  48.      * @param typecode the type key 
  49.      */  
  50.     public void put(int typecode, int capacity, String value) {  
  51.         TreeMap map = (TreeMap)weighted.get( new Integer(typecode) );  
  52.         if (map == null) {// add new ordered map  
  53.             map = new TreeMap();  
  54.             weighted.put( new Integer(typecode), map );  
  55.         }  
  56.         map.put(new Integer(capacity), value);  
  57.     }  
  58.   
  59.     /** 
  60.      * set a default type name for specified type key 
  61.      * @param typecode the type key 
  62.      */  
  63.     public void put(int typecode, String value) {  
  64.         defaults.put( new Integer(typecode), value );  
  65.     }  
  66. }  

说明hibernate就是依靠TypeNames类中的2个map来维护上面提到的对应关系。

再来看一个Integer类型的:

Oracle9iDialect类中没有该方法的描述,来看下Oracle8iDialect类

  1. protected void registerNumericTypeMappings() {  
  2.     registerColumnType( Types.BIT, "number(1,0)" );  
  3.     registerColumnType( Types.BIGINT, "number(19,0)" );  
  4.     registerColumnType( Types.SMALLINT, "number(5,0)" );  
  5.     registerColumnType( Types.TINYINT, "number(3,0)" );  
  6.     registerColumnType( Types.INTEGER, "number(10,0)" );  
  7.     ...  
  8. }  

虽然整体的设计难窥其一二,但是通过这个"number(10,0)",基本确定了:

hibernate通过TypeNames类中的HashMap维护了java数据类型和jdbc类型之间的对应关系(使用不同的方言或是jdbc驱动,对应关系会略有不同)。

 

java程序通过hibernate访问数据库(数据库的特殊sql类型对java程序来说是不可见的,oracle的varchar2类型或是mysql的varchar类型对java程序来说都是String类型),而hibernate通过jdbc驱动访问数据库。jdbc驱动则对底层数据库使用的sql类型进行了封装,向上为hibernate提供jdbc类型接口,hibernate通过jdbc类型接口得到返回的jdbc类型后,根据自身维护的java类型与jdbc类型之间的对应关系,返回java类型。

也即对同一个数据库的相同数据库类型,取到的值是和使用的数据库方言以及jdbc驱动有很大关系的。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值