(二)MyBatis源码解析之配置文件

原创 2016年05月31日 20:05:30

上篇文章我们分析了properties、environmets、typeAliases三个标签,这篇文章我们来看一下typeHandlers标签。

其实不用typeHandlers标签完全不影响对mybatis的使用。但是mybatis内部却大量使用了typeHandlers标签。

当MyBatis将一个Java对象作为输入参数执行Insert语句操作时,它会创建一个PreparedStatment对象,并且使用setxxx(...)方式对占位符设置相应的参数值。

这里,xxx可以使Int,String,Double等Java对象属性类型的任意一个,示例如下:

<insert id="insertStudent" parameterType="Student">
 INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(#{studId},#{name},#{email},#{dob}) 
</insert>
为执行这个语句,MyBatis将采用以下一系列动作:

1.创建一个有占位符的PreparedStatement接口,如下:

PreparedStatement pstmt = connection.prepareStatement ("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(?,?,?,?)");
检查Student对象的属性studId的类型然后使用setXXX(...)方法去设置参数值,这里studId是integer类型,所以会使用setInt(...)方法

pstmt.setInt(1,student.getStudId());
类似地,对于name和email属性都是String类型,Mybatis使用setString(...)设置参数

pstmt.setString(2, student.getName());
pstmt.setString(3, student.getEmail());
但问题是Mybatis是怎么知道对于Integer类型属性使用setInt(...)和String类型属性使用setString(...)方法呢?Mybatis其实就是使用类型处理器typeHandler来决定怎么做的


那如果我们给了一个自定义的对象类型,来存储到数据库呢?示例如下:

假设表STUDENTS有一个PHONE字段,类型为VARCHAR(15),而JavaBean Student 有一个PhoneNumber类定义类型的phoneNumber类

package net.klq.bean;

public class PhoneNumber {
	private String countryCode;
	private String stateCode;
	private String number;

	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 > 0)
				this.stateCode = parts[1];
			if (parts.length > 0)
				this.number = parts[2];
		}
	}

	public String getAsString() {
		return countryCode + "-" + stateCode + "-" + number;
	}
}
class Student{
	private Integer id;
	private String name;
	private String email;
	private PhoneNumber phone;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = 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 PhoneNumber getPhone() {
		return phone;
	}
	public void setPhone(PhoneNumber phone) {
		this.phone = phone;
	}
	
}
<insert id="insertStudent" parameterType="Student"> 
    insert into students(name,email,phone) 
    values(#{name},#{email},#{phone}) 
</insert>

这里,phone参数需要传递给#{phone};而phone对象时PhoneNuber类型。但是,Mybatis并不知道该怎么处理这个对象

为了让MyBatis知道该怎样处理这个自定义的Java对象类型,如PhoneNumber,我们可以创建一个自定义的类型处理器,如下所示:

Mybatis提供了抽象类BaseTypeHandler<T> ,我们可以继承此类创建自定义的类型处理器。

package net.klq.bean;

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;

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());
	}

	@Override
	public PhoneNumber getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return new PhoneNumber(rs.getString(columnName));
	}

	@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));
	}

}
一旦我们实现了自定义的类型处理器,我们需要在总的配置文件中注册它

	<typeHandlers>
		<typeHandler handler="net.klq.typehandler.PhoneTypeHandler"/>
	</typeHandlers>
注册PhoneTypeHandler后,Mybatis能够将Phone类型的对象储存到varchar类型的列上

============================================上面就是typehandler的使用方法=============================================

typeHandler的解析很简单,就是将类的全路径名和和handler属性中指定的类存储到typeHandlerRegistry中,typeHandlerRegistry同样是configuration中的一个属性,mybatis默认已经帮我们初始化了很多typeHandler,所以我们才可以向数据库中直接插入普通类型的还有Date类型的等等的数据,项目是创建typeHandlerRegistry对象时Mybatis为我们初始化的typeHandler

public TypeHandlerRegistry() {
    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());

    register(Byte.class, new ByteTypeHandler());
    register(byte.class, new ByteTypeHandler());
    register(JdbcType.TINYINT, new ByteTypeHandler());

    register(Short.class, new ShortTypeHandler());
    register(short.class, new ShortTypeHandler());
    register(JdbcType.SMALLINT, new ShortTypeHandler());

    register(Integer.class, new IntegerTypeHandler());
    register(int.class, new IntegerTypeHandler());
    register(JdbcType.INTEGER, new IntegerTypeHandler());

    register(Long.class, new LongTypeHandler());
    register(long.class, new LongTypeHandler());

    register(Float.class, new FloatTypeHandler());
    register(float.class, new FloatTypeHandler());
    register(JdbcType.FLOAT, new FloatTypeHandler());

    register(Double.class, new DoubleTypeHandler());
    register(double.class, new DoubleTypeHandler());
    register(JdbcType.DOUBLE, new DoubleTypeHandler());

    register(String.class, new StringTypeHandler());
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
    register(JdbcType.CHAR, new StringTypeHandler());
    register(JdbcType.VARCHAR, new StringTypeHandler());
    register(JdbcType.CLOB, new ClobTypeHandler());
    register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
    register(JdbcType.NCHAR, new NStringTypeHandler());
    register(JdbcType.NCLOB, new NClobTypeHandler());

    register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
    register(JdbcType.ARRAY, new ArrayTypeHandler());

    register(BigInteger.class, new BigIntegerTypeHandler());
    register(JdbcType.BIGINT, new LongTypeHandler());

    register(BigDecimal.class, new BigDecimalTypeHandler());
    register(JdbcType.REAL, new BigDecimalTypeHandler());
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
    register(byte[].class, new ByteArrayTypeHandler());
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.BLOB, new BlobTypeHandler());

    register(Object.class, UNKNOWN_TYPE_HANDLER);
    register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
    register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);

    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    register(java.sql.Date.class, new SqlDateTypeHandler());
    register(java.sql.Time.class, new SqlTimeTypeHandler());
    register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

    // mybatis-typehandlers-jsr310
    try {
      register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler");
      register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler");
      register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler");
      register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler");
      register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler");
      register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler");
      register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler");
    } catch (ClassNotFoundException e) {
      // no JSR-310 handlers
    }

    // issue #273
    register(Character.class, new CharacterTypeHandler());
    register(char.class, new CharacterTypeHandler());
  }

参考文献:

Java Persistence with MyBatis3

下载链接

http://download.csdn.net/detail/u010031673/9462976


版权声明:本文为博主原创文章,未经博主允许不得转载。

(三)MyBatis源码解析之配置文件

这篇文章我们来看看最重要的mappers标签是怎样解析的,Mybatis在mappers标签中引入所有的***Mapper.xml Mybatis支持通过包和具体的xml文件来引入...

Hessian源码分析之设计模式篇(八)

Hessian源码已经分析完了,在Hessian中主要使用到了两个设计模式,一个是策略模式,一个是模板方法模式,还有在Hessian中使用到了递归 我们先来看看策略模式 在Hessian中向流中写数据...

Mybatis工作机制源码分析—初始化—mapper配置文件解析

本文以源码分析的形式讲解Mybatis是如何进行mapper配置文件的解析工作的。 时序图 相关源码 /** XMLMapperBuilder.java */ // 构造XMLMappe...

(一)MyBatis源码解析之配置文件

使用mybatis进行数据库查询的代码如下: public class MessageDaoDemo { @Test public void queryMessageList() throws ...

Mybatis3源码分析(三):解析mapper的xml配置文件

这一章我们来看看mybatis是怎么读取mapper的xml配置文件并解析其中的sql语句。     我们还记得是这样配置sqlSessionFactory的: [java] vi...

mybatis源码学习之执行过程分析(2)——config.xml配置文件和mapper.xml映射文件解析过程

在上一篇中跟踪了SqlSessionFactory及SqlSession的创建过程。这一篇,主要跟踪Mapper接口和XML文件映射及获取。1.Mapper文件的解析1.1Mybatis-config...

mybatis源码学习之执行过程分析(0)——配置文件加载(io包)

在不使用Spring容器进行管理的情况下,我们通常使用Resources来加载配置文件。主要用到了io包中的Resources和ClassLoaderWrapper两个类。 Reader rea...

Spring源码分析-配置文件的解析(二)

上一节介绍了资源的定位,既然资源已经定位了,本章将进入具体的解析工作,具体的解析工作是从XmlBeanDefinitionReader类的loadBeanDefinitions(Resource re...

ibatis源码学习(二)初始化和配置文件解析

在ibatis整体设计和核心流程一文中,我们提到了ibatis框架的初始化过程,本文将深入分析ibatis框架的初始化和配置文件解析过程。本文使用的ibatis版本为2.3.4,不同版本间会略有差异。...

Mybatis配置文件(mybatis-config.xml )源码分析

Mybatis配置文件mybatis-config.xmlsettings,Mybatis配置文件解析源码分析
  • dalinsi
  • dalinsi
  • 2016年09月12日 10:47
  • 284
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:(二)MyBatis源码解析之配置文件
举报原因:
原因补充:

(最多只允许输入30个字)