Mybatis類型轉換介紹 java
1.1 目錄
1.2 創建TypeHandler sql
1.2.1 TypeHandler接口 數據庫
1.2.2 BaseTypeHandler抽象類 apache
1.3 註冊TypeHandler 數組
1.4 Mybatis自動獲取TypeHandler mybatis
1.5 Mybatis中自動註冊的TypeHandler app
1.2 創建TypeHandler
咱們知道java有java的數據類型,數據庫有數據庫的數據類型,那麼咱們在往數據庫中插入數據的時候是如何把java類型當作數據庫類型插入數據庫,在從數據庫讀取數據的時候又是如何把數據庫類型當作java類型來處理呢?這中間必然要通過一個類型轉換。在Mybatis中咱們能夠定義一個叫作TypeHandler類型處理器的東西,經過它能夠實現Java類型跟數據庫類型的相互轉換。下面將就如何創建本身的TypeHandler作一個簡要介紹。 ide
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;
-
- }
如今假設咱們有一個實體對象User,其中有一個屬性interests是String數組類型,以下所示: ui
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代碼
- 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(",");
- }
-
- }
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[]> {
- //..中間的實現代碼省略了
- //..
- }
而後咱們在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的基礎部分能夠看這裏(基於Mybatis3.0.6的基本操做介紹)