MyBatis自定義類型處理器(typeHandler)

MyBatis自定義類型處理器(typeHandler)

我們執行sql語句通過PreparedStatement語句實現,PreparedStatement會設置?值,類型處理器幫PreparedStatement找到對應的set方法,到底是選擇setIntsetStringsetDate...

注意:類型處理器默認可以處理基本的數據類型以及對應的包裝類,uitl.Date、sql.Date等,但無法默認處理自定義類型。

MyBatis將一個Java對象作爲輸入參數執行INSERT語句操作時,它會創建一個PreparedStatement對象,並且使用setXXX()方法對佔位符設置相應的參數值。這裏,XXX可以是IntStringDateJava對象屬性類型的任意一個。示例如下:

<insert id="insertStudent" parameterType="Student"> 
    INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB)  
    VALUES(#{studId},#{name},#{email},#{dob}) 
</insert> 

爲了執行這個語句,MyBatis將採取以下一系列動作:

創建一個有佔位符的PreparedStatement接口,如下:

PreparedStatement ps = connection.prepareStatement("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(?,?,?,?)"); 

檢查Student對象的屬性studId的類型,然後使用合適setXXX()方法去設置參數值。這裏studIdInteger類型,所以會使用setInt()方法:

ps.setInt(1,student.getStudId()); 

類似地,對於nameemail屬性都是String類型的,MyBatis使用setString()方法設置參數。

至於dob屬性, MyBatis會使用setDate()方法設置dob處佔位符位置的值。MyBaits會將java.util.Date類型轉換爲java.sql.Timestamp並設值:

ps.setTimestamp(4, new Timestamp((student.getDob()).getTime())); 

MyBatis是怎麼知道對於Integer類型屬性使用setInt()String類型屬性使用setString()方法呢?其實MyBatis是通過使用類型處理器typeHandlers來決定這麼做的。

MyBatis對於以下的類型使用內建的類型處理器:所有的基本數據類型、基本類型的包裝類型、byte[]java.util.Datejava.sql.Datejava,sql.Timejava.sql.Timestampjava枚舉類型等。所以當MyBatis發現屬性的類型屬於上述類型,他會使用對應的類型處理器將值設置到PreparedStatement中,同樣地,當SQL結果集封裝成java類對象的時候,也有類似的過程。

那如果有一個自定義的類型,怎麼存儲存儲到數據庫呢?示例如下:假設表STUDENTS 有一個 PHONE 字段,類型爲 VARCHAR2(15),而 Student類有一個自定義類型PhoneNumber,這個類型包括三個屬性:國家編號、區號、電話號碼。

public class PhoneNumber{ 
    private String countryCode; 
    private String stateCode; 
    private String number; 
    public PhoneNumber(){ 
    } 
    public PhoneNumber(String countryCode, String stateCode, String number) { 
        this.countryCode = countryCode; 
        this.stateCode = stateCode; 
        this.number = number; 
    } 
    public String getAsString() { 
        return countryCode + "-" + stateCode + "-" + number; 
    } 
    // Setters and getters 
} 
    
public class Student{ 
    private Integer id; 
    private String name; 
    private String email; 
    private PhoneNumber phone; 
    // Setters and getters 
} 

StudentMapper.xml配置如下:

<insert id="insertStudent" parameter Type="Student"> 
    insert into students(name,email,phone) 
    values(#{name},#{email},#{phone}) 
</insert>

這個xml文件裏面,參數對象中的屬性phone的值需要傳遞給#{phone},而參數對象的屬性phonePhoneNumber類型。但是,MyBatis 並不知道該怎樣來處理這個類型的對象。爲了讓MyBatis明白怎樣處理這個自定義的Java對象類型,如PhoneNumber,我們可以創建一個自定義的類型處理器,MyBatis提供了抽象類BaseTypeHandler<T> ,我們可以繼承此類創建自定義類型處理器。代碼如下:

package com.au.typehandlers;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import com.briup.pojo.PhoneNumber;

public class PhoneTypeHandler extends BaseTypeHandler<PhoneNumber>{

    //遇到PhoneNumber參數的時候應該如何在ps中設置值
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, PhoneNumber parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setString(i, parameter.getAsString());
    }

    //查詢中遇到PhoneNumber類型的應該如何封裝(使用列名封裝)
    @Override
    public PhoneNumber getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return new PhoneNumber(rs.getString(columnName));
    }

    //查詢中遇到PhoneNumber類型的應該如何封裝(使用列的下標)
    @Override
    public PhoneNumber getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return new PhoneNumber(rs.getString(columnIndex));
    }

    //CallableStatement使用中遇到了PhoneNumber類型的應該如何封裝
    @Override
    public PhoneNumber getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return new PhoneNumber(cs.getString(columnIndex));
    }

}

注意:使用ps.setString()rs.getString()方法是因爲在數據庫的表中phone列是VARCHAR類型。

最後需要在mybatis-config.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="application.properties" /> 
    <typeHandlers> 
        <typeHandler handler="com.au.typehandlers.PhoneTypeHandler" /> 
    </typeHandlers> 
</configuration> 

註冊PhoneTypeHandler後,MyBatis就能夠將Phone類型的對象值存儲到VARCHAR類型的列上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章