1. 程式人生 > >Mybatis型別轉換介紹

Mybatis型別轉換介紹

1.1     目錄

1.2建立TypeHandler

1.2.1TypeHandler介面

1.2.2BaseTypeHandler抽象類

1.3註冊TypeHandler

1.4Mybatis自動獲取TypeHandler

1.5Mybatis中自動註冊的TypeHandler


1.2     建立TypeHandler

我們知道java有java的資料型別,資料庫有資料庫的資料型別,那麼我們在往資料庫中插入資料的時候是如何把java型別當做資料庫型別插入資料庫,在從資料庫讀取資料的時候又是如何把資料庫型別當做java型別來處理呢?這中間必然要經過一個型別轉換。在Mybatis中我們可以定義一個叫做TypeHandler型別處理器的東西,通過它可以實現Java型別跟資料庫型別的相互轉換。下面將就如何建立自己的TypeHandler做一個簡要介紹。

1.2.1  TypeHandler介面

       在Mybatis中要實現自己的TypeHandler就需要實現Mybatis為我們提供的TypeHandler介面。在TypeHandler中定義了四個方法:

Java程式碼  收藏程式碼
    public interface TypeHandler<T> {  
       
        /** 
         * 用於定義在Mybatis設定引數時該如何把Java型別的引數轉換為對應的資料庫型別 
         * @param ps 當前的PreparedStatement物件 
         * @param i 當前引數的位置 
         * @param parameter 當前引數的Java物件 
         * @param jdbcType 當前引數的資料庫型別 
         * @throws SQLException 
         */  
        void setParameter(PreparedStatement ps, int i, T parameter,  
               JdbcType jdbcType) throws SQLException;  
       
        /** 
         * 用於在Mybatis獲取資料結果集時如何把資料庫型別轉換為對應的Java型別 
         * @param rs 當前的結果集 
         * @param columnName 當前的欄位名稱 
         * @return 轉換後的Java物件 
         * @throws SQLException 
         */  
        T getResult(ResultSet rs, String columnName) throws SQLException;  
       
        /** 
         * 用於在Mybatis通過欄位位置獲取欄位資料時把資料庫型別轉換為對應的Java型別 
         * @param rs 當前的結果集 
         * @param columnIndex 當前欄位的位置 
         * @return 轉換後的Java物件 
         * @throws SQLException 
         */  
        T getResult(ResultSet rs, int columnIndex) throws SQLException;  
       
        /** 
         * 用於Mybatis在呼叫儲存過程後把資料庫型別的資料轉換為對應的Java型別 
         * @param cs 當前的CallableStatement執行後的CallableStatement 
         * @param columnIndex 當前輸出引數的位置 
         * @return 
         * @throws SQLException 
         */  
        T getResult(CallableStatement cs, int columnIndex) throws SQLException;  
       
    }  </span>
現在假設我們有一個實體物件User,其中有一個屬性interestsString陣列型別,如下所示: Java程式碼  收藏程式碼
public class User {  
   
    private int id;  
    private String name;  
    private int age;  
    private String[] interests;  
   
    public int getId() {  
       return id;  
    }  
   
    public void setId(int id) {  
       this.id = id;  
    }  
   
    public String getName() {  
       return name;  
    }  
   
    public void setName(String name) {  
       this.name = name;  
    }  
   
    public int getAge() {  
       return age;  
    }  
   
    public void setAge(int age) {  
       this.age = age;  
    }  
   
    public String[] getInterests() {  
       return interests;  
    }  
   
    public void setInterests(String[] interests) {  
       this.interests = interests;  
    }  
   
    @Override  
    public String toString() {  
       return "User [age=" + age + ", id=" + id + ", interests="  
              + Arrays.toString(interests) + ", name=" + name + "]";  
    }  
     
}  


我們需要把它以拼接字串的形式存到資料庫中,然後在取出來的時候又把它還原為一個String陣列。這個時候我們就可以給它定義一個TypeHandler專門來處理String陣列型別和資料庫VARCHAR型別的相互轉換。在這裡我們建立一個名叫StringArrayTypeHandler的TypeHandler,程式碼如下所示:

Java程式碼  收藏程式碼
<span style="font-size:14px;">package com.tiantian.mybatis.handler;
 
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
 
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
 
public class StringArrayTypeHandler implements TypeHandler<String[]> {
 
       public String[] getResult(ResultSet rs, String columnName)
                     throws SQLException {
              String columnValue = rs.getString(columnName);
              return this.getStringArray(columnValue);
       }
 
       public String[] getResult(ResultSet rs, int columnIndex)
                     throws SQLException {
              String columnValue = rs.getString(columnIndex);
              return this.getStringArray(columnValue);
       }
 
       public String[] getResult(CallableStatement cs, int columnIndex)
                     throws SQLException {
              // TODO Auto-generated method stub
              String columnValue = cs.getString(columnIndex);
              return this.getStringArray(columnValue);
       }
 
       public void setParameter(PreparedStatement ps, int i, String[] parameter,
                     JdbcType jdbcType) throws SQLException {
              if (parameter == null)
                     ps.setNull(i, Types.VARCHAR);
              else {
                     StringBuffer result = new StringBuffer();
                     for (String value : parameter)
                            result.append(value).append(",");
                     result.deleteCharAt(result.length()-1);
                     ps.setString(i, result.toString());
              }
       }
 
       private String[] getStringArray(String columnValue) {
              if (columnValue == null)
                     return null;
              return columnValue.split(",");
       }
 
}</span>

1.2.2  BaseTypeHandler抽象類

       在實現自己的TypeHandler時,除了上面提到的實現最原始的介面之外,Mybatis還為我們提供了一個實現了TypeHandler介面的抽象類BaseTypeHandler。所以我們也可以通過繼承BaseTypeHandler來實現自己的TypeHandler。

       我們先來看一下BaseTypeHandler類的定義:

Java程式碼  收藏程式碼   
 
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
 
  protected Configuration configuration;
 
  public void setConfiguration(Configuration c) {
    this.configuration = c;
  }
 
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
             "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
             "Cause: " + e, e);
      }
    } else {
      setNonNullParameter(ps, i, parameter, jdbcType);
    }
  }
 
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    T result = getNullableResult(rs, columnName);
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
 
  public T getResult(ResultSet rs, int columnIndex) throws SQLException {
    T result = getNullableResult(rs, columnIndex);
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
 
  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    T result = getNullableResult(cs, columnIndex);
    if (cs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
 
  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
 
  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
 
  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
 
  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
 
}
 

       我們可以看到BaseTypeHandler對TypeHandler介面的四個方法做了一個簡單的選擇,把null值的情況都做了一個過濾,核心的取值和設值的方法還是抽象出來了供子類來實現。使用BaseTypeHandler還有一個好處是它繼承了另外一個叫做TypeReference的抽象類,通過TypeReference的getRawType()方法可以獲取到當前TypeHandler所使用泛型的原始型別。這對Mybatis在註冊TypeHandler的時候是非常有好處的。在沒有指定javaType的情況下,Mybatis在註冊TypeHandler時可以通過它來獲取當前TypeHandler所使用泛型的原始型別作為要註冊的TypeHandler的javaType型別,這個在講到Mybatis註冊TypeHandler的方式時將講到。

       當通過繼承BaseTypeHandler來實現自己的TypeHandler時,我們的StringArrayTypeHandler應該這樣寫:

Java程式碼  收藏程式碼
public class StringArrayTypeHandler extends BaseTypeHandler<String[]> {
 
    @Override
    public String[] getNullableResult(ResultSet rs, String columnName)
           throws SQLException {
       return getStringArray(rs.getString(columnName));
    }
 
    @Override
    public String[] getNullableResult(ResultSet rs, int columnIndex)
           throws SQLException {
       return this.getStringArray(rs.getString(columnIndex));
    }
 
    @Override
    public String[] getNullableResult(CallableStatement cs, int columnIndex)
           throws SQLException {
       return this.getStringArray(cs.getString(columnIndex));
    }
 
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
           String[] parameter, JdbcType jdbcType) throws SQLException {
       //由於BaseTypeHandler中已經把parameter為null的情況做了處理,所以這裡我們就不用再判斷parameter是否為空了,直接用就可以了
       StringBuffer result = new StringBuffer();
       for (String value : parameter)
           result.append(value).append(",");
       result.deleteCharAt(result.length()-1);
       ps.setString(i, result.toString());
    }
   
    private String[] getStringArray(String columnValue) {
       if (columnValue == null)
           return null;
       return columnValue.split(",");
    }
}

1.3     註冊TypeHandler

       建立了自己的TypeHandler之後就需要把它註冊到Mybatis的配置檔案中,讓Mybatis能夠識別並使用它。註冊TypeHandler主要有兩種方式,一種是通過在Mybatis配置檔案中定義typeHandlers元素的子元素typeHandler來註冊;另一種是通過在Mybatis配置檔案中定義typeHandlers元素的子元素package來註冊。使用typeHandler子元素註冊時一次只能註冊一個TypeHandler,而使用package子元素註冊時,Mybatis會把指定包裡面的所有TypeHandler都註冊為TypeHandler。使用typeHandler子元素註冊時我們需要通過它的handler屬性來指明當前要註冊的TypeHandler的全名稱,這個屬性是必須要的。另外還有兩個附加屬性可以指定,一個是javaType,用以指定對應的java型別;另一個是jdbcType,用以指定對應的jdbc型別。使用package子元素註冊時需要我們通過它的name屬性來指定要掃描的包,如果這個時候我們也需要指定對應TypeHandler的javaType和jdbcType的話就需要我們在TypeHandler類上使用註解來定義了。Mybatis註冊TypeHandler最基本的方式就是建立一個javaType、jdbcType和TypeHandler的對應關係。在使用typeHandler子元素進行註冊的時候,有三種類型的註冊方式:

1.如果我們指定了javaType和jdbcType,那麼Mybatis會註冊一個對應javaType和jdbcType的TypeHandler。

2.如果我們只指定了javaType屬性,那麼這個時候又分兩種情況:

(1)如果我們通過註解的形式在TypeHandler類上用@MappedJdbcTypes指定了對應的jdbcType,那麼Mybatis會一一註冊指定的javaType、jdbcType和TypeHandler的組合,也包括使用這種形式指定了jdbcType為null的情況。現假設我們有如下這樣一個StringArrayTypeHandler:

Java程式碼  收藏程式碼

@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler implements TypeHandler<String[]> {
    //..中間的實現程式碼省略了
    //..
}

@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler implements TypeHandler<String[]> {
    //..中間的實現程式碼省略了
    //..
}

       然後我們在Mybatis的配置檔案中這樣註冊它:

Xml程式碼  收藏程式碼
    <typeHandlers>  
       <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  
    </typeHandlers>  

       則Mybatis在實際註冊的時候是以javaType為String陣列,jdbcType為VARCHAR來註冊StringArrayTypeHandler的。

(2)如果沒有使用@MappedJdbcTypes註解指定對應的jdbcType,那麼這個時候Mybatis會把jdbcType置為null,然後註冊一個javaType、null和TypeHandler的組合。

3.既沒有指定javaType屬性,又沒有指定jdbcType屬性,或者只指定了jdbcType屬性。這種情況又分三種類型:

(1)如果TypeHandler類上使用了註解@MappedTypes指定了對應的javaType,那麼Mybatis將一一利用對應的javaType和TypeHandler去以2的方式進行註冊。現假設我們定義了這樣一個StringArrayTypeHandler:

Java程式碼  收藏程式碼

@MappedTypes({String[].class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler implements TypeHandler<String[]> {
 
   
 
}

       然後,在Mybatis的配置檔案中註冊它時既不指定它的javaType屬性也不指定它的jdbcType屬性,程式碼如下:

Xml程式碼  收藏程式碼
    <typeHandlers>  
       <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler"/>  
    </typeHandlers>  

     則這個時候Mybatis在註冊該StringArrayTypeHandler的時候首先會判斷它上面有沒有標註@MappedTypes,如果有則把它的MappedTypes一一拿出來作為javaType,然後以方式2進行註冊。所以這裡實際上Mybatis註冊的還是javaType為String陣列,jdbcType為VARCHAR這樣一個組合的TypeHandler。

(2)TypeHandler類上沒有使用@MappedTypes指定對應的javaType時,如果當前的TypeHandler繼承了TypeReference抽象類,Mybatis會利用TypeReference的getRawType()方法取到當前TypeHandler泛型對應的javaType型別,然後利用取得的javaType和TypeHandler以2的方式進行註冊,同時還包括一個javaType為null以方式2進行的註冊。TypeReference是Mybatis中定義的一個抽象類,主要是用來獲取對應的泛型型別。

(3)TypeHandler類上既沒有標註@MappedTypes,又沒有繼承TypeReference抽象類。這種情況Mybatis會以null和null的組合註冊該TypeHandler。

使用package子元素註冊的TypeHandler會以上面的方式3進行註冊。

這裡我們如下注冊我們的TypeHandler:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE configuration  
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-config.dtd">  
    <configuration>  
       
        <properties resource="config/jdbc.properties"></properties>  
        <typeAliases>  
           <package name="com.tiantian.mybatis.model"/>  
        </typeAliases>  
        <typeHandlers>  
           <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
        </typeHandlers>  
        <environments default="development">  
           <environment id="development">  
               <transactionManager type="JDBC" />  
               <dataSource type="POOLED">  
                  <property name="driver" value="${jdbc.driver}" />  
                  <property name="url" value="${jdbc.url}" />  
                  <property name="username" value="${jdbc.username}" />  
                  <property name="password" value="${jdbc.password}" />  
               </dataSource>  
           </environment>  
        </environments>  
        <mappers>  
           <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  
           <package name="com.tiantian.mybatis.mapperinterface"/>  
        </mappers>  
    </configuration>  

       注意String陣列的全類名稱是“[Ljava.lang.String;”,所以上面在註冊StringArrayTypeHandler時定義的javaType屬性為“[Ljava.lang.String;”。

1.4     Mybatis自動獲取TypeHandler

       在介紹了Mybatis是如何註冊TypeHandler之後就介紹一下Mybatis是如何獲取對應的TypeHandler進行型別轉換的。

       如果我們在Mapper.xml檔案中配置某一個屬性或變數的對映關係時指定了該屬性對應的javaType和jdbcType,則Mybatis會從註冊好的TypeHandler中尋找對應的javaType和jdbcType組合的TypeHandler進行處理,這也是Mybatis最基本的獲取TypeHandler進行型別轉換的方式。假設Mybatis配置檔案中有這麼一段TypeHandler的註冊資訊:

Xml程式碼  收藏程式碼
    <typeHandlers>  
       <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
    </typeHandlers>  

看這樣一個UserMapper.xml定義:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper  
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
       
    <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  
       
        <resultMap id="UserResult" type="User">  
           <id column="id" property="id"/>  
           <result column="interests" property="interests" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
        </resultMap>  
       
        <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id">  
           insert into t_user(name, age, interests) values(#{name}, #{age}, #{interests, javaType=[Ljava.lang.String;, jdbcType=VARCHAR})  
        </insert>  
         
        <update id="updateUser" parameterType="User">  
           update t_user set name=#{name}, age=#{age}, interests=#{interests} where id=#{id}  
        </update>  
         
        <select id="findById" parameterType="int" resultMap="UserResult">  
           select * from t_user where id=#{id}  
        </select>  
         
        <delete id="deleteUser" parameterType="int">  
           delete from t_user where id=#{id}  
        </delete>  
    </mapper>  

       我們可以看到在id為UserResult的resultMap中,我們定義了一個對應欄位interests的對映關係,並且定義了其javaType為“[Ljava.lang.String;”,jdbcType為VARCHAR,這個時候Mybatis就會到已經註冊了的TypeHandler中尋找到能處理javaType和jdbcType對應的型別轉換的TypeHandler來進行處理。在這裡就會找到我們註冊的StringArrayTypeHandler。在上面id為insertUser的insert語句中,我們也為變數interests指定了它的javaType和jdbcType屬性,這時候Mybatis也會尋找javaType和jdbcType對應的TypeHandler。上面這樣定義是Mybatis最基本也是最完整地獲取到對應的TypeHandler的方法。這裡我們來對UserMapper(它的程式碼我就不貼出來了,有Mybatis基礎的都應該知道它的程式碼)的findById來做一個測試:

Java程式碼  收藏程式碼
    @Test  
    public void testFind() {  
       SqlSession sqlSession = sqlSessionFactory.openSession();  
       try {  
           UserMapper userMapper = sqlSession.getMapper(UserMapper.class);  
           User user = userMapper.findById(20);  
           System.out.println(user);  
       } finally {  
           sqlSession.close();  
       }  
    }  

 

       其輸出結果如下:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=[Music, Movie, NBA], name=張三]  

我們可以看到Mybatis已經把我們存放在資料庫中VARCHAR型別的欄位interests轉換為User類字串陣列型別的interests屬性,這說明我們定義的StringArrayTypeHandler發生作用了。

除了上面的完整指定一個變數對應的javaType和jdbcType,讓Mybatis能夠完美的找到對應的TypeHandler之外。我們平常在使用的時候可能還有以下方式:

       1.只指定變數對應的javaType型別。這個時候Mybatis會拿著這個javaType和jdbcType為null的組合到註冊的TypeHandler中尋找對應的TypeHandler。這裡我們同樣來做一個測試:

       (1)不動StringArrayTypeHandler的註冊資訊,把我們的UserMapper.xml改為如下形式:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper  
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
    <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  
        <resultMap id="UserResult" type="User">  
           <id column="id" property="id"/>  
           <result column="interests" property="interests" javaType="[Ljava.lang.String;"/>  
        </resultMap>  
       
        <select id="findById" parameterType="int" resultMap="UserResult">  
           select * from t_user where id=#{id}  
        </select>  
    </mapper>   

       這時候再執行上面的測試程式,輸出結果如下:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=null, name=張三]  

       我們可以看到輸出的interests為null,這說明Mybatis沒有使用我們定義的StringArrayTypeHandler來轉換interests。

       (2)UserMapper.xml還像上面那樣定義,但是也只指定javaType屬性來註冊我們的StringArrayTypeHandler,程式碼如下:

Xml程式碼  收藏程式碼

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
    <properties resource="config/jdbc.properties"></properties>  
    <typeAliases>  
       <package name="com.tiantian.mybatis.model"/>  
    </typeAliases>  
    <typeHandlers>  
       <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  
    </typeHandlers>  
    <environments default="development">  
       <environment id="development">  
           <transactionManager type="JDBC" />  
           <dataSource type="POOLED">  
              <property name="driver" value="${jdbc.driver}" />  
              <property name="url" value="${jdbc.url}" />  
              <property name="username" value="${jdbc.username}" />  
              <property name="password" value="${jdbc.password}" />  
           </dataSource>  
       </environment>  
    </environments>  
    <mappers>  
       <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  
    </mappers>  
</configuration> 
 

       這個時候再執行上面的測試程式碼,輸出結果如下:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=[Music, Movie, NBA], name=張三]  

       這是因為我們是以javaType和null註冊的StringArrayTypeHandler,然後在需要轉換interests時又是以相同的javaType和null來尋找的,所以就會找到我們註冊的StringArrayTypeHandler來進行型別轉換。

       2.只指定變數對應的jdbcType型別。這個時候Mybatis會利用我們指定的返回型別和對應的屬性取該屬性在返回型別中對應的javaType,之後再拿著該javaType和我們指定的jdbcType到註冊的TypeHandler中獲取對應的TypeHandler。這裡我們來看這樣一個測試:

       保持之前指定javaType和jdbcType的方式註冊StringArrayTypeHandler,然後在定義interests變數的時候不指定javaType,只指定jdbcType,這個時候UserMapper.xml如下所示:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper  
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
    <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  
        <resultMap id="UserResult" type="User">  
           <id column="id" property="id"/>  
           <result column="interests" property="interests" jdbcType="VARCHAR"/>  
        </resultMap>  
        <select id="findById" parameterType="int" resultMap="UserResult">  
           select * from t_user where id=#{id}  
        </select>  
    </mapper>  

       這個時候繼續執行上面的測試程式碼,輸出結果如下:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=[Music, Movie, NBA], name=張三]   

       這個時候Mybatis是這樣獲取TypeHandler的:首先它發現我們的interests沒有指定javaType,這個時候它就會通過我們指定的型別User和屬性interests獲取User類的interests屬性對應的java型別,即String陣列,再拿著獲取到的javaType和我們指定的jdbcType即VARCHAR去尋找對應的TypeHandler,這個時候就找到了我們之前以String陣列和VARCHAR註冊好的StringArrayTypeHandler來處理interests的型別轉換。

       3.javaType型別和jdbcType型別都不指定。這個時候Mybatis會以方式2中的方式獲取到對應的javaType型別,然後再以方式1獲取到對應的TypeHandler。這裡我們也來做一個測試:

       (1)首先,註冊一個javaType為String陣列,jdbcType不指定即為null的TypeHandler—StringArrayTypeHandler,程式碼如下:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE configuration  
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-config.dtd">  
    <configuration>  
        <properties resource="config/jdbc.properties"></properties>  
        <typeAliases>  
           <package name="com.tiantian.mybatis.model"/>  
        </typeAliases>  
        <typeHandlers>  
           <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/>  
        </typeHandlers>  
        <environments default="development">  
           <environment id="development">  
               <transactionManager type="JDBC" />  
               <dataSource type="POOLED">  
                  <property name="driver" value="${jdbc.driver}" />  
                  <property name="url" value="${jdbc.url}" />  
                  <property name="username" value="${jdbc.username}" />  
                  <property name="password" value="${jdbc.password}" />  
               </dataSource>  
           </environment>  
        </environments>  
        <mappers>  
           <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  
        </mappers>  
    </configuration>  

       (2)然後,定義我們的interests欄位的對映關係時既不指定javaType,又不指定jdbcType,程式碼如下:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper  
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
    <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  
        <resultMap id="UserResult" type="User">  
           <id column="id" property="id"/>  
           <result column="interests" property="interests"/>  
        </resultMap>  
        <select id="findById" parameterType="int" resultMap="UserResult">  
           select * from t_user where id=#{id}  
        </select>  
    </mapper>  

       這個時候再執行上面的測試程式碼,輸出如下:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=[Music, Movie, NBA], name=張三]  

       這種情況是這樣的:我們以javaType為String陣列和jdbcType為null註冊了一個StringArrayTypeHandler,然後在定義interests欄位的對映關係時我們沒有指明其對應的javaType和jdbcType,這個時候Mybatis會利用我們指定的User型別和interests屬性獲取到User類的interests屬性對應的java型別,即String陣列,然後結合jdbcType為null去尋找註冊的TypeHandler,這樣就找到了StringArrayTypeHandler。經StringArrayTypeHandler的處理就把jdbcType為VARCHAR的資料轉換為javaType為String陣列的資料,所以輸出結果如上所示。

       4.還有一種形式是我們直接通過變數的typeHandler屬性指定其對應的TypeHandler,這個時候Mybatis就會使用該使用者自己指定的TypeHandler來進行型別轉換,而不再以javaType和jdbcType組合的方式獲取對應的TypeHandler。這裡我們也來做一個測試:

       (1)首先在Mybatis的配置檔案中以javaType和jdbcType配套的方式註冊一個StringArrayTypeHandler,程式碼如下:

Xml程式碼  收藏程式碼

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
    <properties resource="config/jdbc.properties"></properties>  
    <typeAliases>  
       <package name="com.tiantian.mybatis.model"/>  
    </typeAliases>  
    <typeHandlers>  
       <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>  
    </typeHandlers>  
    <environments default="development">  
       <environment id="development">  
           <transactionManager type="JDBC" />  
           <dataSource type="POOLED">  
              <property name="driver" value="${jdbc.driver}" />  
              <property name="url" value="${jdbc.url}" />  
              <property name="username" value="${jdbc.username}" />  
              <property name="password" value="${jdbc.password}" />  
           </dataSource>  
       </environment>  
    </environments>  
    <mappers>  
       <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/>  
    </mappers>  
</configuration> 

       按照前面說的Mybatis按照變數的javaType和jdbcType來取對應的TypeHandler的話,這裡註冊的StringArrayTypeHandler只有在指定變數的javaType為字串陣列而jdbcType為VARCHAR的情況下才能被獲取到。

       (2)然後我們在UserMapper.xml檔案中不指定interests欄位對應的javaType和jdbcType,但是通過typeHandler屬性指定將以StringArrayTypeHandler來進行型別轉換,程式碼如下:

Xml程式碼  收藏程式碼
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper  
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
    <mapper namespace="com.tiantian.mybatis.mapper.UserMapper">  
        <resultMap id="UserResult" type="User">  
           <id column="id" property="id"/>  
           <result column="interests" property="interests" typeHandler="com.tiantian.mybatis.handler.StringArrayTypeHandler"/>  
        </resultMap>  
        <select id="findById" parameterType="int" resultMap="UserResult">  
           select * from t_user where id=#{id}  
        </select>  
    </mapper>  

       執行上面的測試程式碼,輸出結果:

Text程式碼  收藏程式碼

User [age=30, id=20, interests=[Music, Movie, NBA], name=張三]  

       這是因為我們指定了進行interests欄位的對映關係時使用StringArrayTypeHandler來進行型別轉換。當指定了某一個欄位或變數進行對映關係時所使用的TypeHandler時,Mybatis在需要進行型別轉換時就使用給定的TypeHandler進行型別轉換,而不會再通過javaType和jdbcType的組合去註冊好的TypeHandler中尋找對應的TypeHandler。

1.5     Mybatis中自動註冊的TypeHandler

       對於一些常用型別的自動轉換Mybatis已經為我們建立了相關的TypeHandler,並且會自動註冊它們,這主要包括:

Java程式碼  收藏程式碼

register(Boolean.class, new BooleanTypeHandler());  
register(boolean.class, new BooleanTypeHandler());  
register(Byte.class, new ByteTypeHandler());  
register(byte.class, new ByteTypeHandler());  
register(Short.class, new ShortTypeHandler());  
register(short.class, new ShortTypeHandler());  
register(Integer.class, new IntegerTypeHandler());  
register(int.class, new IntegerTypeHandler());  
register(Long.class, new LongTypeHandler());  
register(long.class, new LongTypeHandler());  
register(Float.class, new FloatTypeHandler());  
register(float.class, new FloatTypeHandler());  
register(Double.class, new DoubleTypeHandler());  
register(double.class, new DoubleTypeHandler());  
register(String.class, new StringTypeHandler());  
register(String.class, JdbcType.CHAR, new StringTypeHandler());  
register(String.class, JdbcType.CLOB, new ClobTypeHandler());  
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());  
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());  
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());  
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());  
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());  
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());  
register(BigInteger.class, new BigIntegerTypeHandler());  
register(BigDecimal.class, new BigDecimalTypeHandler());  
register(Byte[].class, new ByteObjectArrayTypeHandler());  
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());  
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());  
register(byte[].class, new ByteArrayTypeHandler());  
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());  
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());  
register(Object.class, UNKNOWN_TYPE_HANDLER);  
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);  
register(Date.class, new DateTypeHandler());  
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());  
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());  
register(java.sql.Date.class, new SqlDateTypeHandler());  
register(java.sql.Time.class, new SqlTimeTypeHandler());  
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());  
register(Character.class, new CharacterTypeHandler());  
register(char.class, new CharacterTypeHandler());  


相關推薦

Mybatis型別轉換介紹

1.1     目錄 1.2建立TypeHandler 1.2.1TypeHandler介面 1.2.2BaseTypeHandler抽象類 1.3註冊TypeHandler 1.4Mybatis自動獲取TypeHandler 1.5Mybatis中自動註冊的TypeHan

mybatis型別轉換錯誤

不僅要看下當前查詢條件,還要看下級聯查詢條件對引數的處理。  大家注意這三種情況的區別,第一個會把傳遞過來的引數轉換成字串型別和“2”做比較,第二個會轉換成 字元型別,第三個會轉換成 數字型

MyBatis配置typeHandler型別轉換器 (自定義型別轉換器)

MyBatis配置のtypeHandler型別轉換器 - 簡書 https://www.jianshu.com/p/8e0a2d06892c     初始typeHandler 在JDBC中,需要在PreparedStatement物件中設定那些已經預編譯過的

Util應用程式框架公共操作類(一):資料型別轉換公共操作類(介紹篇)

  本系列文章將介紹一些對初學者有幫助的輔助類,這些輔助類本身並沒有什麼稀奇之處,如何能發現需要封裝它們可能更加重要,所謂授之以魚不如授之以漁,掌握封裝公共操作類的技巧才是關鍵,我會詳細說明建立這些類的動機和思考過程,以幫助初學者發現和封裝自己需要的東西。建立公共操作類的技巧,大家可以參考我的這篇文章——應用

JS(五)簡要介紹陣列或物件 typeof、型別轉換

寫在最前面 初始引用值 陣列 物件 陣列 陣列物件用來在單獨的變數名中儲存一系列的值。形式是一箇中括號,裡面可以寫很多東西,中間用逗號隔開,每個逗號類似可以隔開兩個倉庫,每個倉

mybatis typeHandler自定義型別轉換

Mybatis預設不支援Calendar 解決辦法: mybatis提供了對自定義的型別轉換器(typeHandler)的支援,因此我們可以自己編寫型別轉換器來實現這一自動轉換的功能。 實現步驟: 第一步:編寫自定義型別轉換器 public

mybatis -- 自定義enum型別轉換

           mybatis提供了EnumTypeHandler和EnumOrdinalTypeHandler完成列舉型別的轉換,兩者的功能已經基本滿足了日常的使用。但是可能有這樣的需求:由於某種原因,我們不想使用列舉的name和ordinal作為資料儲存欄位。mybatis的自定義轉換類出現了。

mybatis-generator程式碼生成(支援自定義型別轉換

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

分頁查詢Mybatis報JDBC型別轉換錯誤

Mapper.xml<select id="selectPanelByNetworkCodeL" parameterType="java.lang.String" resultMap="BaseR

JNI資料型別轉換和JNIEnv的介紹、操作jobject,以及jstring的介紹

摘錄、參考文件: 1.深入理解Android:卷1 作者:鄧凡平 上一章,講了關於JNI註冊的相關知識; 這一章講的內容比較多,主要是以下幾方面的內容: 1)java與JNI之間的資料型別轉換; 2)JNIEnv的介紹; 3)JNIEnv的使用,如何操作jobject;

Mybatis實現自定義的型別轉換器TypeHandler

此文其實是java操作Oracle型別XMLType總結二:使用Mybatis附帶的一篇小結。 Mybatis實現自定義的轉換器,十分的簡單,其主要步驟分為三步,這裡以操作XMLType型別為例。 第一步 新建一個轉換類,實現TypeHandler介面,介面的泛型指定引數型別,不指定則為Object:

springboot中mybatis定義型別轉換

import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.Pre

myBatis表單Date資料型別轉換

異常再現 :      提交資料後異常 : 如果是新手,這種異常是最煩的了,什麼錯誤資訊都沒有,改個腿子...........但是老江湖就不一樣了,一瞄到400就知道是資料型別轉換異常,就能準確到異常大概位置了,,,,,, 話不多說, 這和異常有倆種解決方案 1. 使用註

MyBatis配置のtypeHandler型別轉換

初始typeHandler 在JDBC中,需要在PreparedStatement物件中設定那些已經預編譯過的SQL語句 引數。 執行SQL後,會通過ResultSet物件獲取得到資料庫的資料,而這些MyBatis是根據資料的型別通過typeHandler來實

mybatis使用generator自動生成程式碼時的型別轉換

使用mybatis的generator自動生成程式碼,但是oracle資料庫中number(6,2)總是自動轉成BigDecimal,我想要轉成的是float型別 這樣就寫了一個型別轉換器,需要繼承JavaTypeResolver介面 然後在mybaties配置檔案gene

玩轉mybatis中的型別轉換

1.場景 日常java開發中經常有這種需求,用0或者1這些程式碼(不侷限於數字)來表示某種狀態。比如用0表示女性,用1來表示男性。

Mybatis與SQL Server型別轉換遇到的坑

一. MyBatis SQL語句遇到的效能問題 1. 場景還原   假設我們有一張User表,其中包含userId、userName、gender欄位,其中userId的資料型別為char(20),此時我們想通過userId獲得這個人的姓名,   這段SQL很簡單: SELECT userName FR

Mybatis自定義TypeHandler解決特殊型別轉換問題

我們知道,Java和MySQL中的資料型別是不同的,Java中除了基本資料型別,還有物件。 有時候使用MySQL儲存資料,或者從MySQL中讀取資料時,會有一些特殊需求

基本資料型別介紹轉換,基本資料型別與字串之間轉換,字串與字元陣列之間轉換以及字串與位元組陣列之間轉換

目錄 一.Java的基本資料型別介紹 二.各類基本資料之間的轉換 三.基本資料型別和String之間轉換(附:物件包裝類及所對應的基本資料型別) 四.String與字元陣列轉換 五.Strin

myBatis原始碼解析-型別轉換篇(5)

前言 開始分析Type包前,說明下使用場景。資料構建語句使用PreparedStatement,需要輸入的是jdbc型別,但我們一般寫的是java型別。同理,資料庫結果集返回的是jdbc型別,而我們需要java型別。這就涉及到一個型別轉換問題,Type包就是解決這個問題。下面是Type包類圖所在結構: &nb