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类型的列上。

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