上一篇讲了StatementHandler,其中有ParameterHandler(参数处理器)是在StatementHandler被创建时被创建的。下面对ParameterHandler进行说明。其代码如下:

public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps) throws SQLException;
}

它只有两个方法,其中getParameterObject()是获取参数的,而setParameters()是设置参数的。

ParameterHandler只有一个实现类DefaultParameterHandler,在查看DefaultParameterHandler代码之前首先了解DefaultParameterHandler中的相关属性。代码如下所示:

//类型转换处理器:映射Java中数据类型与数据库中数据类型对应关系
private final TypeHandlerRegistry typeHandlerRegistry;
//映射sql语句与数据库操作对象关系以及sql关联的sql标签信息
private final MappedStatement mappedStatement;
//存储的需要进行赋值参数内容
private final Object parameterObject;
//输送的具体的sql语句
private final BoundSql boundSql;
//包含myBatis框架核心配置文件信息和sql映射文件信息
private final Configuration configuration;

下面查看DefaultParameterHandler中setParameters()的实现,代码如下所示:

  public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//// parameterMappings是对#{}里给出的参数信息的封装,即这个SQL是个参数化SQL时会存在(SQL语句中带占位符?)
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
//存储过程才存在输出参数,所以当参数不是输出参数的时候,就需要设置
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
//这里的propertyName对应的是一个additionalParameters Map对象经过封装的key值,而不是Bean的属性
String propertyName = parameterMapping.getProperty();
//判断propertyName是additionalParameters中的key
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
}
//如果在typeHandlerRegistry中已经注册了这个参数的Class对象,value直接等于Method传进来的参数
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
}
//否则是Map或Bean,List或Array被封装成了Map,通过Key得到Value;Bean是通过封装的MataObject对象,Bean通过反射得到,再用propertyName得到相应的Value。
else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
//得到parameterMapping的TypeHandler,均为IntegerTypeHandler
TypeHandler typeHandler = parameterMapping.getTypeHandler();
//得到相应parameterMapping的JdbcType,如果没有在#{}中显式的指定JdbcType,则为null
JdbcType jdbcType = parameterMapping.getJdbcType();
//当value和jdbcType都为null执行执行setNull操作时,会报OTHER的错误,因此指定JdbcType
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//具体实现ps.set***
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}

上面的的setParameter()是在BaseTypeHandler中实现的,它是IntegerTypeHandler等的父类,这里采用了模板模式。setParameter()的代码如下:

  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
//执行PreparedStatement的setNull方法
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
"Cause: " + e, e);
}
} else {
try {
//进行参数设置,是抽象方法,具体的实现在子类中
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different configuration property. " +
"Cause: " + e, e);
}
}
}

下面对上面所说的setNull()进行说名:

public void setNull(int parameterIndex, int sqlType) throws SQLException{}
//parameterIndex:整形参数,第一个为1,第二个为2...
//sqlType必须为java.sql.Types 中定义的SQL类型代码
//若parameterIndex 不对应于 SQL 语句中的参数标记;发生数据库访问错误;或在关闭的 PreparedStatement上调用此方法,会抛出SQLException异常。

由上面代码知,当SQL类型代码为1111(OTHER)时,就会出现报错:java.sql.SQLException: 无效的列类型: 1111,解决方案是在其后加上jdbcType,示例代码如下:

<insert id="insertUser" parameterType="com.luis.domain.User">
insert into t_user(s_id,name,age)
values (
#{SId,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR},
#{age,jdbcType=INTEGER}
);
</insert>

另有博主验证在ibatis2 可以正常的执行 数据库可以正常的插入数据。

参见:http://www.cnblogs.com/panxuejun/p/6163779.html

SqlSession对象之ParameterHandler的更多相关文章

  1. SqlSession对象之StatementHandler

    上一篇讲了SqlSession对象中的Executor,接下来将对SqlSession的另一个对象StatementHandler进行讲解. 一.StatementHandler介绍 Statemen ...

  2. mybatis的两个核心对象SqlSessionFactory和SqlSession对象

    mybatis的两个核心对象SqlSessionFactory和SqlSession对象 参见:https://www.cnblogs.com/wxdestiny/p/9743686.html

  3. 对 Service中sqlsession对象的优化

    在本线程中添加object数据,必须在本线程中才能获取出来..其他线程获取不到. public class Test { public static void main(String[] args) ...

  4. SqlSession对象之Executor

    Executor是Mybatis的一个核心接口,每一个SqlSession对象都会拥有一个Executor(执行器对象):这个执行对象负责[增删改查]的具体操作,我们可以简单的将它理解为JDBC中St ...

  5. 使用ThreadLocal管理Mybatis中SqlSession对象

    转自http://blog.csdn.net/qq_29227939/article/details/52029065 public class MybatisUtil { private stati ...

  6. SqlSession对象之ResultSetHandler

    ResultSetHandler是Mybatis中的另一重要接口,它的代码如下所示: public interface ResultSetHandler { <E> List<E&g ...

  7. 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。

    1,sqlsession的真实类型和数量 由于使用spring管理bean,当我们在代码中需要使用这个bean的时候,会首先去容器中找,第一次需要调用MapperFactoryBean的getObje ...

  8. MyBatis常用对象SqlSessionFactory和SqlSession介绍和运用

    学习框架一个比较好的路径阅读源码.本文介绍的SqlSessionFactory和SqlSession.可以通过了解SqlSessionFactory接口和SqlSession接口以及两个的实现类入手, ...

  9. MyBatis的2个核心对象:SqlSessionFactory、SqlSession

    SqlSessionFactory SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,主要作用是创建SqlSession. InputStream inputStream = ...

随机推荐

  1. C/C++掌握技能(一)

    1.在编译器中输入代码并将其保存为.cpp文件(C语言的文件扩展名.c,但为了使用C++中的一些好用的特性,请把文件扩展名改为C++的.cpp)2.等价头文件:#include<stdio.h& ...

  2. Dubbo启动时服务检查

    所谓启动时服务检查是指Dubbo在启动的时候会检查当前引用的服务是否可用,不可用会抛出异常,阻止程序的初始化,以便能在上线前快速的找到问题,默认的情况下check=true 通过设置check=fal ...

  3. 利用koa实现mongodb数据库的增删改查

    概述 使用koa免不了要操纵数据库,现阶段流行的数据库是mongoDB,所以我研究了一下koa里面mongoDB数据库的增删改查,记录下来,供以后开发时参考,相信对其他人也有用. 源代码请看:我的gi ...

  4. linux中jdk的安装与配置

    一.卸载系统已有的JDK 1.查看已安装的jdk rpm -qa|grep jdk 2.卸载jdk rpm -e --nodeps java-1.6.0-openjdk-1.6.0.0-1.66.1. ...

  5. js中cookie,localStorage(sessionStorage)的存取

    一.cookie (原生的不好用,自己简单封装) 1. 存cookie的方法: function setCookie(c_name,value,expiredays) { var exdate=new ...

  6. iOS开发笔记-图标和图片大小官方最新标准

    这两天开发iOS app用到了Tab bar,然后随便切了点图标放上去发现效果极差.于是乎,开始查找苹果官方给的标准.搜索一番后,看到了一篇博文,但其内容与iOS人机交互指南最新版内容不符. 故此,在 ...

  7. String、StringBuffer与StringBuilder之间区别 (转载)

    最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringBuilder的东西,现在整理一下. 关于这三个类在字符串处理中的位置不言而喻,那 ...

  8. Java模式—静态代理模式

        静态代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问,提供“真实对象”的代表,在访问对象时引入一定程度的间接性,这种间接性可以附加多种用途. 代理模式的主要作用是为其他对象 ...

  9. python中 =、copy、deepcopy的差别

    python2中,需要import copy模块 python3中,直接可以使用copy()方法,但deepcopy()还是需要导入copy模块 下面以python2为例: 对于"=&quo ...

  10. 一口一口吃掉Volley(三)

    欢迎访问我的个人博客转发请注明出处:http://www.wensibo.top/2017/02/17/一口一口吃掉Volley(三)/ 学习了一口一口吃掉Volley(二)之后,你应该已经学会了如何 ...