什么是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); }