MyBatis踩坑記錄


在線文檔:
  動態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
View Code

 

異常出處:
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),怎么去數是哪個字段呢?

 1 insert into XXX_ORDER
 2   (TRADE_NO,
 3    UUID,
 4    ACCOUNT_INFO_NO,
 5    TRADE_ACCOUNT_NO,
 6    OUT_TRADE_NO,
 7    OUT_ORDER_NO,
 8    FUND_ORDER_NO,
 9    CUSTOMER_ID,
10    CUSTOMER_NAME,
11    BENEFIT_CODE,
12    BIZ_PRODUCT_CODE,
13    PROJECT_CODE,
14    TRUST_NO,
15    TRUST_NAME,
16    MERCHANT_NO,
17    AMOUNT,
18    CLEAR_DATE,
19    OPEN_DATE,
20    APPLY_TIME,
21    CREATE_TIME,
22    UPDATE_TIME,
23    IOU_NO)
24 values
25   (get_order_no('PCS', 'SEQ_PURCHASE_ORDER'),
26    #{uuid,   jdbcType = VARCHAR},
27    #{accountInfoNo,   jdbcType = VARCHAR},
28    #{tradeAccountNo,   jdbcType = VARCHAR},
29    #{outTradeNo,   jdbcType = VARCHAR},
30    #{outOrderNo,   jdbcType = VARCHAR},
31    #{fundOrderNo,   jdbcType = VARCHAR},
32    #{customerId,   jdbcType = INTEGER},
33    #{customerName,   jdbcType = VARCHAR},
34    #{benefitCode,   jdbcType = VARCHAR},
35    #{bizProductCode,   jdbcType = VARCHAR},
36    #{projectCode,   jdbcType = VARCHAR},
37    #{trustNo,   jdbcType = VARCHAR},
38    #{trustName,   jdbcType = VARCHAR},
39    #{merchantNo,   jdbcType = VARCHAR},
40    #{amount},
41    #{clearDate,   jdbcType = DATE},
42    #{openDate,   jdbcType = DATE},
43    #{applyTime,   jdbcType = TIMESTAMP},
44    #{iouNo})
View Code

由於我們是用PreparedStatement去綁定參數的,需要把不需要綁定的字段剔除,剔除后的結果如下:

 1    UUID,
 2    ACCOUNT_INFO_NO,
 3    TRADE_ACCOUNT_NO,
 4    OUT_TRADE_NO,
 5    OUT_ORDER_NO,
 6    FUND_ORDER_NO,
 7    CUSTOMER_ID,
 8    CUSTOMER_NAME,
 9    BENEFIT_CODE,
10    BIZ_PRODUCT_CODE,
11    PROJECT_CODE,
12    TRUST_NO,
13    TRUST_NAME,
14    MERCHANT_NO,
15    AMOUNT,
16    CLEAR_DATE,
17    OPEN_DATE,
18    APPLY_TIME,
19    IOU_NO)
20 values
21   (get_order_no('PCS', 'SEQ_PURCHASE_ORDER'),
22    #{uuid,   jdbcType = VARCHAR},
23    #{accountInfoNo,   jdbcType = VARCHAR},
24    #{tradeAccountNo,   jdbcType = VARCHAR},
25    #{outTradeNo,   jdbcType = VARCHAR},
26    #{outOrderNo,   jdbcType = VARCHAR},
27    #{fundOrderNo,   jdbcType = VARCHAR},
28    #{customerId,   jdbcType = INTEGER},
29    #{customerName,   jdbcType = VARCHAR},
30    #{benefitCode,   jdbcType = VARCHAR},
31    #{bizProductCode,   jdbcType = VARCHAR},
32    #{projectCode,   jdbcType = VARCHAR},
33    #{trustNo,   jdbcType = VARCHAR},
34    #{trustName,   jdbcType = VARCHAR},
35    #{merchantNo,   jdbcType = VARCHAR},
36    #{amount},
37    #{clearDate,   jdbcType = DATE},
38    #{openDate,   jdbcType = DATE},
39    #{applyTime,   jdbcType = TIMESTAMP},
40    #{iouNo})
View Code

可以清楚的看到出問題的第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掃描的配置

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM