在线文档:
  动态SQL  http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

1. Error setting null for parameter #19 with JdbcType OTHER

问题:

org.springframework.jdbc.UncategorizedSQLException: Error setting null for parameter #19 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型
; uncategorized SQLException for SQL []; SQL state [null]; error code [17004]; 无效的列类型; nested exception is java.sql.SQLException: 无效的列类型
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
at com.sun.proxy.$Proxy49.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:240)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:51)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
at com.sun.proxy.$Proxy94.add(Unknown Source)
at com.ihome.basicbiz.tforder.dao.IPurchaseOrderDaoTest.testAdd(IPurchaseOrderDaoTest.java:59)

...................

完整堆栈:

org.springframework.jdbc.UncategorizedSQLException: Error setting null for parameter #19 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型
; uncategorized SQLException for SQL []; SQL state [null]; error code [17004]; 无效的列类型; nested exception is java.sql.SQLException: 无效的列类型
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
at com.sun.proxy.$Proxy49.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:240)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:51)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
at com.sun.proxy.$Proxy94.add(Unknown Source)
at com.ihome.basicbiz.tforder.dao.IPurchaseOrderDaoTest.testAdd(IPurchaseOrderDaoTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.sql.SQLException: 无效的列类型
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:113)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:147)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:209)
at oracle.jdbc.driver.OracleStatement.getInternalType(OracleStatement.java:3462)
at oracle.jdbc.driver.OraclePreparedStatement.setNullCritical(OraclePreparedStatement.java:4337)
at oracle.jdbc.driver.OraclePreparedStatement.setNull(OraclePreparedStatement.java:4326)
at org.apache.commons.dbcp.DelegatingPreparedStatement.setNull(DelegatingPreparedStatement.java:108)
at org.apache.commons.dbcp.DelegatingPreparedStatement.setNull(DelegatingPreparedStatement.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:70)
at com.sun.proxy.$Proxy103.setNull(Unknown Source)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:43)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:81)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:80)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:61)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:74)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:47)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:105)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:71)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:152)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358)
... 35 more

异常出处:
org.apache.ibatis.type.BaseTypeHandler#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 {
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 {
setNonNullParameter(ps, i, parameter, jdbcType);
}
}

异常原因:
在做插入的时候,有一个参数(即parameter) 的值为null,而在sqlMap里面又没有给对应的字段设置 jdbcType。
MyBatis在处理这种没有指定jdbcType的字段时,会默认使用org.apache.ibatis.type.JdbcType#OTHER(Types.OTHER)来处理,这样的话ps.setNull(i, jdbcType.TYPE_CODE);就会报java.sql.SQLException: 无效的列类型

怎样定位是哪个字段的问题:

我们从异常中可以看到是第19个参数出了问题(Error setting null for parameter #19 with JdbcType OTHER),怎么去数是哪个字段呢?

 insert into XXX_ORDER
(TRADE_NO,
UUID,
ACCOUNT_INFO_NO,
TRADE_ACCOUNT_NO,
OUT_TRADE_NO,
OUT_ORDER_NO,
FUND_ORDER_NO,
CUSTOMER_ID,
CUSTOMER_NAME,
BENEFIT_CODE,
BIZ_PRODUCT_CODE,
PROJECT_CODE,
TRUST_NO,
TRUST_NAME,
MERCHANT_NO,
AMOUNT,
CLEAR_DATE,
OPEN_DATE,
APPLY_TIME,
CREATE_TIME,
UPDATE_TIME,
IOU_NO)
values
(get_order_no('PCS', 'SEQ_PURCHASE_ORDER'),
#{uuid, jdbcType = VARCHAR},
#{accountInfoNo, jdbcType = VARCHAR},
#{tradeAccountNo, jdbcType = VARCHAR},
#{outTradeNo, jdbcType = VARCHAR},
#{outOrderNo, jdbcType = VARCHAR},
#{fundOrderNo, jdbcType = VARCHAR},
#{customerId, jdbcType = INTEGER},
#{customerName, jdbcType = VARCHAR},
#{benefitCode, jdbcType = VARCHAR},
#{bizProductCode, jdbcType = VARCHAR},
#{projectCode, jdbcType = VARCHAR},
#{trustNo, jdbcType = VARCHAR},
#{trustName, jdbcType = VARCHAR},
#{merchantNo, jdbcType = VARCHAR},
#{amount},
#{clearDate, jdbcType = DATE},
#{openDate, jdbcType = DATE},
#{applyTime, jdbcType = TIMESTAMP},
#{iouNo})

由于我们是用PreparedStatement去绑定参数的,需要把不需要绑定的字段剔除,剔除后的结果如下:

    UUID,
ACCOUNT_INFO_NO,
TRADE_ACCOUNT_NO,
OUT_TRADE_NO,
OUT_ORDER_NO,
FUND_ORDER_NO,
CUSTOMER_ID,
CUSTOMER_NAME,
BENEFIT_CODE,
BIZ_PRODUCT_CODE,
PROJECT_CODE,
TRUST_NO,
TRUST_NAME,
MERCHANT_NO,
AMOUNT,
CLEAR_DATE,
OPEN_DATE,
APPLY_TIME,
IOU_NO)
values
(get_order_no('PCS', 'SEQ_PURCHASE_ORDER'),
#{uuid, jdbcType = VARCHAR},
#{accountInfoNo, jdbcType = VARCHAR},
#{tradeAccountNo, jdbcType = VARCHAR},
#{outTradeNo, jdbcType = VARCHAR},
#{outOrderNo, jdbcType = VARCHAR},
#{fundOrderNo, jdbcType = VARCHAR},
#{customerId, jdbcType = INTEGER},
#{customerName, jdbcType = VARCHAR},
#{benefitCode, jdbcType = VARCHAR},
#{bizProductCode, jdbcType = VARCHAR},
#{projectCode, jdbcType = VARCHAR},
#{trustNo, jdbcType = VARCHAR},
#{trustName, jdbcType = VARCHAR},
#{merchantNo, jdbcType = VARCHAR},
#{amount},
#{clearDate, jdbcType = DATE},
#{openDate, jdbcType = DATE},
#{applyTime, jdbcType = TIMESTAMP},
#{iouNo})

可以清楚的看到出问题的第19个参数是iouNo,问题找到!

解决办法:

将iouNo加上jdbcType就可以了,即 #{iouNo, jdbcType=VARCHAR}

2. MyBatis中在<if>标签中使用enum和String做equals比较

mybatis version:3.2.4
mybatis-spring version:1.2.2
<if>标签中使用Enum和String做equals比较,始终不成功,尝试了如下几种,都是失败告终:
1. <if test="enumItem == 'xxStr'">
2. <if test='enumItem == "xxStr"'>
3. <if test="enumItem == 'xxStr'.toString()">

mybatis version:3.4.4
mybatis-spring version:1.3.0
<if>标签中使用Enum和String做equals比较,使用如下方式,得到解决:
1. <if test="enumItem.toString() == 'xxStr'">

如果是简单的String与String做比较的话,使用<if test="strParam == 'xxStr'">即可

3. MyBatis中insert返回主键

MySQL:

<insert id="add" parameterType="xxx.Foo" useGeneratedKeys="true" keyProperty="id">
  insert into user(id, name) values((#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR})
</insert>

或者:

<insert id="add" parameterType="xxx.Foo" >
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(id, name) values((#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR})
</insert>

Oracle:

<insert id="add" parameterType="xxx.Foo">
  <selectKey resultType="java.lang.Long" order="BEFORE" keyProperty="id">
  SELECT SEQ_TEST.NEXTVAL FROM DUAL
  </selectKey>
  insert into user(id, name) values((#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR})
</insert>

4. Mybatis批量插入返回主键
参考:http://blog.csdn.net/u014336799/article/details/52023887
实例:

 Dao : int batchAdd(List<JobLog> list);
Mapper: <insert id="batchAdd" parameterType="com.kvn.dal.core.pojo.JobLog" useGeneratedKeys="true"
keyProperty="id">
insert into job_log (code, cron, description,
start_time, job_status, execute_type, global_single,
count, remark) values
<foreach item="item" collection="list" separator=",">
(#{item.code,jdbcType=VARCHAR}, #{item.cron,jdbcType=VARCHAR}, #{item.description,jdbcType=VARCHAR},
now(), 'PROCESSING', #{item.executeType,jdbcType=VARCHAR}, #{item.globalSingle,jdbcType=BOOLEAN},
0, #{item.remark,jdbcType=VARCHAR})
</foreach>
</insert>
测试:
jobLogDao.batchAdd(list);
System.out.println("=====>" + JSON.toJSONString(list));
结果: =====>[{"code":"x","count":0,"cron":"q","description":"d","executeType":"s","globalSingle":false,"id":42},{"code":"x","count":0,"cron":"q","description":"d","executeType":"s","globalSingle":false,"id":43}]

注意:

1、升级Mybatis版本到3.3.1。
2、在Dao中不能使用@param注解。
3、Mapper.xml中使用list变量接受Dao中的集合。

5. Spring-MyBatis Mapper文件默认扫描路径

Spring-MyBatis自动扫描com.a.b.XXMapper.java接口时,还会自动扫描相应的Mapper文件。
扫描路径为:路径为com/a/b/XXMapper.xml
即:与XXMapper.java路径相同,名字相同的xml文件

这样,可以省去mapper.xml扫描的配置

MyBatis踩坑记录的更多相关文章

  1. unionId突然不能获取的踩坑记录

    昨天(2016-2-2日),突然发现系统的一个微信接口使用不了了.后来经查发现,是在网页授权获取用户基本信息的时候,unionid获取失败导致的. 在网页授权获取用户基本信息的介绍中(http://m ...

  2. CentOS7.4安装MySQL踩坑记录

    CentOS7.4安装MySQL踩坑记录 time: 2018.3.19 CentOS7.4安装MySQL时网上的文档虽然多但是不靠谱的也多, 可能因为版本与时间的问题, 所以记录下自己踩坑的过程, ...

  3. ubuntu 下安装docker 踩坑记录

    ubuntu 下安装docker 踩坑记录 # Setp : 移除旧版本Docker sudo apt-get remove docker docker-engine docker.io # Step ...

  4. SpringBoot + Shiro + shiro.ini 的踩坑记录

    0.写在前面的话 好久没写博客了,诶,好多时候偷懒直接就抓网上的资料丢笔记里了,也就没有自己提炼,偷懒偷懒.然后最近参加了一个网络课程,要交作业的那种,为了能方便看下其他同学的作业,就写了个爬虫把作业 ...

  5. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  6. google nmt 实验踩坑记录

       最近因为要做一个title压缩的任务,所以调研了一些text summary的方法.    text summary 一般分为抽取式和生成式两种.前者一般是从原始的文本中抽取出重要的word o ...

  7. ABP框架踩坑记录

    ABP框架踩坑记录 ASP.NET Boilerplate是一个专用于现代Web应用程序的通用应用程序框架. 它使用了你已经熟悉的工具,并根据它们实现最佳实践. 文章目录 使用MySQL 配置User ...

  8. SpringBoot+SpringSecurity+Thymeleaf认证失败返回错误信息踩坑记录

    Spring boot +Spring Security + Thymeleaf认证失败返回错误信息踩坑记录 步入8102年,现在企业开发追求快速,Springboot以多种优秀特性引领潮流,在众多使 ...

  9. IDFA踩坑记录

    IDFA踩坑记录: 1.iOS10.0 以下,即使打开“限制广告跟踪”,依然可以读取idfa: 2.打开“限制广告跟踪”,然后再关闭“限制广告跟踪”,idfa会改变: 3.越狱机器安装开发证书打的包, ...

随机推荐

  1. Sahi (1) —— 快速入门(101 Tutorial)

    Sahi (1) -- 快速入门(101 Tutorial) jvm版本: 1.8.0_65 sahi版本: Sahi Pro 6.1.0 参考来源: Sahi官网 Sahi Quick Tutori ...

  2. Django添加防跨站请求伪造中间件

    第一步: 在全局设置中打开此中间件: MIDDLEWARE_CLASSES = [ ... 'django.middleware.csrf.CsrfViewMiddleware', ... ]     ...

  3. 【jquery】邮箱自动补全 + 上下翻动

    最近在做通行证项目,里面注册模块有邮箱注册,需求方想要在输入 @ 后触发下拉框显示各个邮箱,效果如下: html 代码: <!DOCTYPE HTML> <html lang=&qu ...

  4. PHP也玩并发,巧用curl 并发减少后端访问时间

    首先,先了解下 php中的curl多线程函数: # curl_multi_add_handle# curl_multi_close# curl_multi_exec# curl_multi_getco ...

  5. Sword STL容器分类介绍

    标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容器slist和rope.slist是一个单 ...

  6. MinGW32和64位交叉编译环境的安装和使用

    原文出处: CompileGraphics Magick, Boost, Botan and QT with MinGW64 under Windows 7 64 http://www.kinetic ...

  7. I2C上拉电阻

    在一些PCB的layout中,大家往往会看到在I2C通信的接口处,往往会接入一个4.7K的电阻,有的datasheet上面明确有要求,需要接入,有的则没有要求.   I2C接口 对于单片机来讲,有些I ...

  8. Socket心跳包机制

    心跳包的发送,通常有两种技术方法1:应用层自己实现的心跳包 由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个 ...

  9. 第三百四十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—通过downloadmiddleware中间件全局随机更换user-agent浏览器用户代理

    第三百四十七节,Python分布式爬虫打造搜索引擎Scrapy精讲—通过downloadmiddleware随机更换user-agent浏览器用户代理 downloadmiddleware介绍中间件是 ...

  10. Lambda动态排序

    private static IList<T> IListOrderBy<T>(IList<T> list, string propertyName) where ...