什么是typeHandler?
typeHandler用于将某个类型的数据映射到表的某一列上,以完成MyBatis列跟某个属性的映射
内置typeHandler
MyBatis内置了很多typeHandler,这写typeHandler通过org.apache.ibatis.type.TypeHandlerRegistry进行注册,比如对于日期型数据的typeHandler,
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
SqlDateTypeHandler的定义
/*
* Copyright 2009-2012 The MyBatis Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SqlDateTypeHandler extends BaseTypeHandler<Date> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType)
throws SQLException {
ps.setDate(i, parameter); //将指定类型设置到PreparedStatement
}
@Override
public Date getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getDate(columnName);//返回结果
}
@Override
public Date getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
return rs.getDate(columnIndex);
}
@Override
public Date getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getDate(columnIndex);
}
}
举例:
package com.mybatis3.domain;
import java.io.Serializable;
/**
* @author Siva
*
*/
public class PhoneNumber implements Serializable
{
private static final long serialVersionUID = 1L;
private String countryCode;
private String stateCode;
private String number;
public PhoneNumber() {
}
public PhoneNumber(String countryCode, String stateCode, String number) {
super();
this.countryCode = countryCode;
this.stateCode = stateCode;
this.number = number;
}
public PhoneNumber(String string) {
if(string != null){
String[] parts = string.split("-");
if(parts.length>0) this.countryCode=parts[0];
if(parts.length>1) this.stateCode=parts[1];
if(parts.length>2) this.number=parts[2];
}
}
@Override
public String toString() {
return this.getAsString();
}
public String getAsString() {
return countryCode+"-"+stateCode+"-"+number;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getStateCode() {
return stateCode;
}
public void setStateCode(String stateCode) {
this.stateCode = stateCode;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
package com.mybatis3.domain;
import java.io.Serializable;
/**
* @author Siva
*
*/
public class Student implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer studId;
private String name;
private String email;
private PhoneNumber phone;
private Address address;
@Override
public String toString() {
return "Student [studId=" + studId + ", name=" + name + ", email=" + email
+ ", phone=" + (phone==null?null:phone.getAsString()) + ", address=" + address + "]";
}
public Student()
{
}
public Student(Integer id)
{
this.studId = id;
}
public Integer getStudId()
{
return studId;
}
public void setStudId(Integer id)
{
this.studId = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public PhoneNumber getPhone() {
return phone;
}
public void setPhone(PhoneNumber phone) {
this.phone = phone;
}
}
Student的phone属性是PhoneNumber类型,而在数据表中,phone属性对应的字段是String类型,这就需要注册一个typeHandler,实现Student对象持久化到数据库表中时,将PhoneNumber对象转换为字符串,而在读取数据库时,将String类型的phone信息反序列化为PhoneNumber对象
PhoneNumberTypeHandler
package com.mybatis3.typehandlers;
import com.mybatis3.domain.PhoneNumber;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Siva
*
*/
public class PhoneTypeHandler extends BaseTypeHandler<PhoneNumber>{
@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));
}
@Override
public PhoneNumber getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return new PhoneNumber(cs.getString(columnIndex));///根据列的序号,从数据库中读取字符串,反序列化为PhoneNumber对象
}
}
主配置文件
<typeHandlers> <typeHandler handler="com.mybatis3.typehandlers.PhoneTypeHandler" /> </typeHandlers>
SQL映射
<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="studId"> insert into STUDENTS(name,email,addr_id, phone) values(#{name},#{email},#{address.addrId},#{phone})<!--#{phone}是字符串类型,根据typeHandler的转换规则,提供符合规则的phone字符串--> </insert>
测试代码
public void testCreateStudentWithMap()
{
Map<String, Object> studMap = new HashMap<String, Object>();
long ts = System.currentTimeMillis();
studMap.put("name","stud_"+ts);
studMap.put("email","stud_"+ts+"@gmail.com");
studMap.put("phone","123-456-789");
studentService.createStudentWithMap(studMap);
}