mybatis typehandler
建立TypeHandler
我們知道java有java的數(shù)據(jù)類型,數(shù)據(jù)庫有數(shù)據(jù)庫的數(shù)據(jù)類型,那么我們?cè)谕鶖?shù)據(jù)庫中插入數(shù)據(jù)的時(shí)候是如何把java類型當(dāng)做數(shù)據(jù)庫類型插入數(shù)據(jù)庫,在從數(shù)據(jù)庫讀取數(shù)據(jù)的時(shí)候又是如何把數(shù)據(jù)庫類型當(dāng)做java類型來處理呢?這中間必然要經(jīng)過一個(gè)類型轉(zhuǎn)換。在Mybatis中我們可以定義一個(gè)叫做TypeHandler類型處理器的東西,通過它可以實(shí)現(xiàn)Java類型跟數(shù)據(jù)庫類型的相互轉(zhuǎn)換。下面將就如何建立自己的TypeHandler做一個(gè)簡要介紹。
TypeHandler接口
???????在Mybatis中要實(shí)現(xiàn)自己的TypeHandler就需要實(shí)現(xiàn)Mybatis為我們提供的TypeHandler接口。在TypeHandler中定義了四個(gè)方法:
public interface TypeHandler<T> { /** * 用于定義在Mybatis設(shè)置參數(shù)時(shí)該如何把Java類型的參數(shù)轉(zhuǎn)換為對(duì)應(yīng)的數(shù)據(jù)庫類型 * @param ps 當(dāng)前的PreparedStatement對(duì)象 * @param i 當(dāng)前參數(shù)的位置 * @param parameter 當(dāng)前參數(shù)的Java對(duì)象 * @param jdbcType 當(dāng)前參數(shù)的數(shù)據(jù)庫類型 * @throws SQLException */ void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * 用于在Mybatis獲取數(shù)據(jù)結(jié)果集時(shí)如何把數(shù)據(jù)庫類型轉(zhuǎn)換為對(duì)應(yīng)的Java類型 * @param rs 當(dāng)前的結(jié)果集 * @param columnName 當(dāng)前的字段名稱 * @return 轉(zhuǎn)換后的Java對(duì)象 * @throws SQLException */ T getResult(ResultSet rs, String columnName) throws SQLException; /** * 用于在Mybatis通過字段位置獲取字段數(shù)據(jù)時(shí)把數(shù)據(jù)庫類型轉(zhuǎn)換為對(duì)應(yīng)的Java類型 * @param rs 當(dāng)前的結(jié)果集 * @param columnIndex 當(dāng)前字段的位置 * @return 轉(zhuǎn)換后的Java對(duì)象 * @throws SQLException */ T getResult(ResultSet rs, int columnIndex) throws SQLException; /** * 用于Mybatis在調(diào)用存儲(chǔ)過程后把數(shù)據(jù)庫類型的數(shù)據(jù)轉(zhuǎn)換為對(duì)應(yīng)的Java類型 * @param cs 當(dāng)前的CallableStatement執(zhí)行后的CallableStatement * @param columnIndex 當(dāng)前輸出參數(shù)的位置 * @return * @throws SQLException */ T getResult(CallableStatement cs, int columnIndex) throws SQLException; }現(xiàn)在假設(shè)我們有一個(gè)實(shí)體對(duì)象User,其中有一個(gè)屬性interests是String數(shù)組類型,如下所示:
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 + "]"; } }我們需要把它以拼接字符串的形式存到數(shù)據(jù)庫中,然后在取出來的時(shí)候又把它還原為一個(gè)String數(shù)組。這個(gè)時(shí)候我們就可以給它定義一個(gè)TypeHandler專門來處理String數(shù)組類型和數(shù)據(jù)庫VARCHAR類型的相互轉(zhuǎn)換。在這里我們建立一個(gè)名叫StringArrayTypeHandler的TypeHandler,代碼如下所示:
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(","); } }BaseTypeHandler抽象類
???????在實(shí)現(xiàn)自己的TypeHandler時(shí),除了上面提到的實(shí)現(xiàn)最原始的接口之外,Mybatis還為我們提供了一個(gè)實(shí)現(xiàn)了TypeHandler接口的抽象類BaseTypeHandler。所以我們也可以通過繼承BaseTypeHandler來實(shí)現(xiàn)自己的TypeHandler。
???????我們先來看一下BaseTypeHandler類的定義:
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對(duì)TypeHandler接口的四個(gè)方法做了一個(gè)簡單的選擇,把null值的情況都做了一個(gè)過濾,核心的取值和設(shè)值的方法還是抽象出來了供子類來實(shí)現(xiàn)。使用BaseTypeHandler還有一個(gè)好處是它繼承了另外一個(gè)叫做TypeReference的抽象類,通過TypeReference的getRawType()方法可以獲取到當(dāng)前TypeHandler所使用泛型的原始類型。這對(duì)Mybatis在注冊(cè)TypeHandler的時(shí)候是非常有好處的。在沒有指定javaType的情況下,Mybatis在注冊(cè)TypeHandler時(shí)可以通過它來獲取當(dāng)前TypeHandler所使用泛型的原始類型作為要注冊(cè)的TypeHandler的javaType類型,這個(gè)在講到Mybatis注冊(cè)TypeHandler的方式時(shí)將講到。
???????當(dāng)通過繼承BaseTypeHandler來實(shí)現(xiàn)自己的TypeHandler時(shí),我們的StringArrayTypeHandler應(yīng)該這樣寫:
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中已經(jīng)把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(","); } }?
?
?
?
?
注冊(cè)TypeHandler
???????建立了自己的TypeHandler之后就需要把它注冊(cè)到Mybatis的配置文件中,讓Mybatis能夠識(shí)別并使用它。注冊(cè)TypeHandler主要有兩種方式,一種是通過在Mybatis配置文件中定義typeHandlers元素的子元素typeHandler來注冊(cè);另一種是通過在Mybatis配置文件中定義typeHandlers元素的子元素package來注冊(cè)。使用typeHandler子元素注冊(cè)時(shí)一次只能注冊(cè)一個(gè)TypeHandler,而使用package子元素注冊(cè)時(shí),Mybatis會(huì)把指定包里面的所有TypeHandler都注冊(cè)為TypeHandler。使用typeHandler子元素注冊(cè)時(shí)我們需要通過它的handler屬性來指明當(dāng)前要注冊(cè)的TypeHandler的全名稱,這個(gè)屬性是必須要的。另外還有兩個(gè)附加屬性可以指定,一個(gè)是javaType,用以指定對(duì)應(yīng)的java類型;另一個(gè)是jdbcType,用以指定對(duì)應(yīng)的jdbc類型。使用package子元素注冊(cè)時(shí)需要我們通過它的name屬性來指定要掃描的包,如果這個(gè)時(shí)候我們也需要指定對(duì)應(yīng)TypeHandler的javaType和jdbcType的話就需要我們?cè)赥ypeHandler類上使用注解來定義了。Mybatis注冊(cè)TypeHandler最基本的方式就是建立一個(gè)javaType、jdbcType和TypeHandler的對(duì)應(yīng)關(guān)系。在使用typeHandler子元素進(jìn)行注冊(cè)的時(shí)候,有三種類型的注冊(cè)方式:
1.如果我們指定了javaType和jdbcType,那么Mybatis會(huì)注冊(cè)一個(gè)對(duì)應(yīng)javaType和jdbcType的TypeHandler。
2.如果我們只指定了javaType屬性,那么這個(gè)時(shí)候又分兩種情況:
(1)如果我們通過注解的形式在TypeHandler類上用@MappedJdbcTypes指定了對(duì)應(yīng)的jdbcType,那么Mybatis會(huì)一一注冊(cè)指定的javaType、jdbcType和TypeHandler的組合,也包括使用這種形式指定了jdbcType為null的情況?,F(xiàn)假設(shè)我們有如下這樣一個(gè)StringArrayTypeHandler:
?
@MappedJdbcTypes({JdbcType.VARCHAR}) public class StringArrayTypeHandler implements TypeHandler<String[]> { //..中間的實(shí)現(xiàn)代碼省略了 //.. }然后我們?cè)贛ybatis的配置文件中這樣注冊(cè)它:
<typeHandlers> <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/> </typeHandlers>則Mybatis在實(shí)際注冊(cè)的時(shí)候是以javaType為String數(shù)組,jdbcType為VARCHAR來注冊(cè)StringArrayTypeHandler的。
?
轉(zhuǎn)載于:https://www.cnblogs.com/Dhouse/p/5977039.html
總結(jié)
以上是生活随笔為你收集整理的mybatis typehandler的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c#之内置类型
- 下一篇: 分享三个非常适合新手的网站