Db2插入数据溢出报错测试

本文是测试Db2数据库插入数据报错。具体来讲,是通过命令行、JDBC、Mybatis等各种方式,尝试把一个长度为11的字符串插入到 VARCHAR(8) 的字段,查看报错信息,方便以后遇到类似的错误时,能够帮助快速定位问题。

测试环境

Db2

$ db2level
DB21085I  This instance or install (instance name, where applicable:
"db2inst1") uses "64" bits and DB2 code release "SQL11050" with level
identifier "0601010F".
Informational tokens are "DB2 v11.5.0.0", "s1906061700", "DYN1906061700AMD64",
and Fix Pack "0".
Product is installed at "/opt/ibm/db2/V11.5".

JCC driver

  • db2jcc4.jar
  • db2jcc_license_cu.jar

Mybatis

  • mybatis-3.5.9.jar

Database

  • SAMPLE
$ db2 connect to sample

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.5.0.0
 SQL authorization ID   = DB2INST1
 Local database alias   = SAMPLE

Table

  • T6
$ db2 describe table t6

                                Data type                     Column
Column name                     schema    Data type name      Length     Scale Nulls
------------------------------- --------- ------------------- ---------- ----- ------
C1                              SYSIBM    INTEGER                      4     0 Yes
C2                              SYSIBM    VARCHAR                      8     0 Yes

  2 record(s) selected.

总结

懒得看具体测试过程的同学,请直接看总结:

  • 如果是literal的值,则报错是 SQL0433N (即 SQLCODE -433 ),并且会提供导致错误的值,本例中是 abcdefghijk
  • 如果是 ? 动态绑定的值(先prepare,再set value,再执行) ,则报错是SQLCODE -302 ,并且不会提供导致错误的值或者column名字,这就很讨厌,因为如果有多个 ? ,你也不知道是哪个绑定的值出错了
  • 本例中运行SQL的方式都是dynamic SQL,验证方式是运行SQL后查看packagecache信息( select cast(stmt_text as varchar(100)), section_type from table(MON_GET_PKG_CACHE_STMT(null, null, null, -2)) ),其中section_type都是 D
  • 接上条,查看 stmt_text 可知,literal的SQL就是literal, ? 的SQL就是 ?
  • 对于batch insert,报错是SQLCODE -4229 ,但这只是一个笼统的错误码,表明batch操作中的某个操作有错误,并没有提供更详细的错误说明。另外, batch index #1 ,这里面的 1 我没搞懂是什么意思
  • 接上条,在本例中,需要通过2次 getCause() ,得到 BatchUpdateException (需要强制类型转换),再调用其 getNextException() 方法,才能获取真正的异常 SqlDataException 。同样,其具体的错误是 -302 ,但并不知道是哪个值或者column出错了
  • 接上条, batch element # 中的 值,指明是batch操作的第几个SQL出错了
  • Autocommit的设置,貌似并不影响报错
测试方式 Auto Commit Prepared stmt_text 报错位置 报错信息
Test 1 命令行 Y N insert into t6 values (1, 'abcdefghijk') insert处 SQL0433N Value "abcdefghijk" is too long. SQLSTATE=22001
Test 2 命令行 N N insert into t6 values (1, 'abcdefghijk') insert处 SQL0433N Value "abcdefghijk" is too long. SQLSTATE=22001
Test 3 JDBC Y N insert into t6 values (1, 'abcdefghijk') insert处 Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-433, SQLSTATE=22001, SQLERRMC=abcdefghijk,
Test 4 JDBC N N insert into t6 values (1, 'abcdefghijk') insert处 Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-433, SQLSTATE=22001, SQLERRMC=abcdefghijk,
Test 5 JDBC Y Y insert into t6 values (?, ?) insert处 Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null,
Test 6 JDBC N Y insert into t6 values (?, ?) insert处 Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null,
Test 7 Mybatis Y Y insert into t6 values (?, ?) insert处 ### Error updating database. Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null,
Test 8 Mybatis N Y insert into t6 values (?, ?) insert处 ### Error updating database. Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null,
Test 9 Mybatis (Batch Insert) N Y insert into t6 values (?, ?) commit处 ### Error committing transaction. Cause: org.apache.ibatis.executor.BatchExecutorException: testMybatis.Test0207Mapper.insert (batch index #1) failed. Cause: com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][4.21.29] Batch failure. The batch was submitted, but at least one exception occurred on an individual member of the batch. Use getNextException() to retrieve the exceptions for specific batched elements. ERRORCODE=-4229, SQLSTATE=null

测试过程

Test 1

直接在Db2命令行运行insert语句:

$ db2 "insert into t6 values (1, 'abcdefghijk')"
DB21034E  The command was processed as an SQL statement because it was not a
valid Command Line Processor command.  During SQL processing it returned:
SQL0433N  Value "abcdefghijk" is too long.  SQLSTATE=22001

SQL0433N 即Db2的 -433 error,其具体解释如下:

$ db2 ? sql433


SQL0433N  Value "" is too long.

Explanation:

The value "" required truncation by a system (built-in)
cast or adjustment function, which was called to transform the value in
some way. The truncation is not allowed where this value is used.

The value being transformed is one of the following:

*  an argument to a user defined function (UDF)

*  an input to the SET clause of an UPDATE statement

*  a value being INSERTed into a table

*  an input to a cast or adjustment function in some other context

*  a recursively referenced column whose data type and length is
   determined by the initialization part of recursion and may grow in
   the iterative part of the recursion

*  an XML data value being serialized to the output by XMLSERIALIZE
   function.

The statement cannot be processed.

User response:

If "" is a literal string in the SQL statement, it is
too long for its intended use.

If "" is not a literal string, examine the SQL
statement to determine where the transformation is taking place. Either
the input to the transformation is too long, or the target is too short.

Correct the problem and rerun the statement.

sqlcode: -433

sqlstate: 22001

Test 2

同上,唯一差别是把AutoCommit设置为off:

$ db2 +c "insert into t6 values (1, 'abcdefghijk')"
DB21034E  The command was processed as an SQL statement because it was not a
valid Command Line Processor command.  During SQL processing it returned:
SQL0433N  Value "abcdefghijk" is too long.  SQLSTATE=22001

注:别忘了commit或者rollback。如果在同一事务之内,在这个失败的SQL之前运行过其它SQL,则那些SQL仍然需要显式的commit/rollback。

Test 3

使用JDBC程序来做insert操作:

package testJDBC;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Test0207 {

	public static void main(String[] args) throws SQLException, ClassNotFoundException {

		Class.forName("com.ibm.db2.jcc.DB2Driver");
		
		try (Connection conn = DriverManager.getConnection("jdbc:db2://9.30.251.58:50000/sample", "db2inst1" , "N1cetest")) {
			String sql1 = "insert into t6 values (1, 'abcdefghijk')";
			
			try (Statement ps = conn.createStatement()) {
				ps.executeUpdate(sql1);
			}
		}		
	}
}

运行程序,报错如下:

Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-433, SQLSTATE=22001, SQLERRMC=abcdefghijk, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2796)
	at com.ibm.db2.jcc.am.sp.d(sp.java:2784)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2146)
	at com.ibm.db2.jcc.t4.bb.j(bb.java:233)
	at com.ibm.db2.jcc.t4.bb.c(bb.java:48)
	at com.ibm.db2.jcc.t4.p.b(p.java:38)
	at com.ibm.db2.jcc.t4.vb.h(vb.java:124)
	at com.ibm.db2.jcc.am.sp.jb(sp.java:2141)
	at com.ibm.db2.jcc.am.sp.a(sp.java:3336)
	at com.ibm.db2.jcc.am.sp.c(sp.java:768)
	at com.ibm.db2.jcc.am.sp.executeUpdate(sp.java:747)
	at testJDBC.Test0207.main(Test0207.java:18)

Test 4

相比前面的JDBC程序:

  1. Auto Commit设置为false
  2. 在有问题的insert语句前后各添加一个没问题的insert语句
  3. 通过打印语句查看程序运行过程

运行结果:

  1. 第2个insert语句出错时,程序直接抛出了异常,并不是在最后commit时才抛出异常
  2. 总体插入数量为0 (第2个insert出错,导致整个事务回滚)
package testJDBC;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Test0207 {

	public static void main(String[] args) throws SQLException, ClassNotFoundException {
		Class.forName("com.ibm.db2.jcc.DB2Driver");
		
		try (Connection conn = DriverManager.getConnection("jdbc:db2://9.30.251.58:50000/sample", "db2inst1" , "N1cetest")) {
			conn.setAutoCommit(false);
			String sql1 = "insert into t6 values (1, 'abcdefg')";
			
			try (Statement ps = conn.createStatement()) {
				ps.executeUpdate(sql1);
			}
			System.out.println(sql1);
			
			sql1 = "insert into t6 values (1, 'abcdefghijk')";
			
			try (Statement ps = conn.createStatement()) {
				ps.executeUpdate(sql1);
			}
			System.out.println(sql1);
			
			sql1 = "insert into t6 values (1, 'hijklmn')";
			
			try (Statement ps = conn.createStatement()) {
				ps.executeUpdate(sql1);
			}
			System.out.println(sql1);
			
			conn.commit();
		}	
	}
}

运行程序,报错如下:

insert into t6 values (1, 'abcdefg')
Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-433, SQLSTATE=22001, SQLERRMC=abcdefghijk, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2796)
	at com.ibm.db2.jcc.am.sp.d(sp.java:2784)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2146)
	at com.ibm.db2.jcc.t4.bb.j(bb.java:233)
	at com.ibm.db2.jcc.t4.bb.c(bb.java:48)
	at com.ibm.db2.jcc.t4.p.b(p.java:38)
	at com.ibm.db2.jcc.t4.vb.h(vb.java:124)
	at com.ibm.db2.jcc.am.sp.jb(sp.java:2141)
	at com.ibm.db2.jcc.am.sp.a(sp.java:3336)
	at com.ibm.db2.jcc.am.sp.c(sp.java:768)
	at com.ibm.db2.jcc.am.sp.executeUpdate(sp.java:747)
	at testJDBC.Test0207.main(Test0207.java:25)
	Suppressed: com.ibm.db2.jcc.am.SqlException: [jcc][t4][10251][10308][4.21.29] java.sql.Connection.close() requested while a transaction is in progress on the connection.
The transaction remains active, and the connection cannot be closed. ERRORCODE=-4471, SQLSTATE=null
		at com.ibm.db2.jcc.am.kd.a(kd.java:794)
		at com.ibm.db2.jcc.am.kd.a(kd.java:66)
		at com.ibm.db2.jcc.am.kd.a(kd.java:133)
		at com.ibm.db2.jcc.am.Connection.checkForTransactionInProgress(Connection.java:1457)
		at com.ibm.db2.jcc.t4.b.checkForTransactionInProgress(b.java:7374)
		at com.ibm.db2.jcc.am.Connection.closeResourcesX(Connection.java:1480)
		at com.ibm.db2.jcc.am.Connection.closeX(Connection.java:1466)
		at com.ibm.db2.jcc.am.Connection.close(Connection.java:1443)
		at testJDBC.Test0207.main(Test0207.java:37)

Test 5

先prepare statement,再set值,再执行:

package testJDBC;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Test0207 {

	public static void main(String[] args) throws SQLException, ClassNotFoundException {
		Class.forName("com.ibm.db2.jcc.DB2Driver");
		
		try (Connection conn = DriverManager.getConnection("jdbc:db2://9.30.251.58:50000/sample", "db2inst1" , "N1cetest")) {
			String sql1 = "insert into t6 values (?, ?)";
			
			try (PreparedStatement ps = conn.prepareStatement(sql1)) {
				
				ps.setInt(1, 1);
				ps.setString(2, "abcdefghijk");
				ps.executeUpdate();
			}
		}
	}
}

运行程序,报错如下:

Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2447)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2430)
	at com.ibm.db2.jcc.t4.bb.m(bb.java:415)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:62)
	at com.ibm.db2.jcc.t4.p.a(p.java:50)
	at com.ibm.db2.jcc.t4.wb.b(wb.java:220)
	at com.ibm.db2.jcc.am.tp.uc(tp.java:3567)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4613)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4798)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.mc(tp.java:817)
	at com.ibm.db2.jcc.am.tp.executeUpdate(tp.java:791)
	at testJDBC.Test0207.main(Test0207.java:20)

Db2的 -302 error,其具体解释如下:

$ db2 ? sql302


SQL0302N  The value of a host variable in the EXECUTE or OPEN statement
      is out of range for its corresponding use.

Explanation:

The value of an input host variable was found to be out of range for its
use in the SELECT, VALUES, or prepared statement.

One of the following occurred:

*  The corresponding host variable or parameter marker used in the SQL
   statement is defined as string, but the input host variable contains
   a string that is too long.

*  The corresponding host variable or parameter marker used in the SQL
   statement is defined as numeric, but the input host variable contains
   a numeric value that is out of range.

*  The terminating NUL character is missing from the C language
   NUL-terminated character string host variable.

*  Federated system users: in a pass-through session, a data
   source-specific restriction might have been violated.

This error occurs as a result of specifying either an incorrect host
variable or an incorrect SQLLEN value in an SQLDA on an EXECUTE or OPEN
statement.

The statement cannot be processed.

User response:

Ensure that the input host variable value is the correct type and
length.

If the input host variables supply values to parameter markers, match
values with the implied data type and length of the parameter marker.

Federated system users: for a pass-through session, determine what data
source is causing the error.

Examine the SQL dialect for that data source to determine which specific
restriction has been violated, and adjust the failing statement as
needed.

sqlcode: -302

sqlstate: 22001, 22003


   Related information:
   Troubleshooting data source connection errors

请注意:在Db2的错误信息里面,并没有提供出错的字段,也就是说,我们无法确定是哪个字段在insert时超出了范围。

Test 6

相比前面的JDBC程序:

  1. Auto Commit设置为false
  2. 在有问题的insert语句前后各添加一个没问题的insert语句

运行结果:

  1. 第2个insert语句出错时,程序直接抛出了异常,并不是在最后commit时才抛出异常
  2. 总体插入数量为0 (第2个insert出错,导致整个事务回滚)
package testJDBC;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Test0207 {

	public static void main(String[] args) throws SQLException, ClassNotFoundException {
		Class.forName("com.ibm.db2.jcc.DB2Driver");
		
		try (Connection conn = DriverManager.getConnection("jdbc:db2://9.30.251.58:50000/sample", "db2inst1" , "N1cetest")) {
			conn.setAutoCommit(false);
			String sql1 = "insert into t6 values (?, ?)";
			
			try (PreparedStatement ps = conn.prepareStatement(sql1)) {
				
				ps.setInt(1, 1);
				ps.setString(2, "abcdefg");
				ps.executeUpdate();
				System.out.println("1111111");
				
				ps.setInt(1, 1);
				ps.setString(2, "abcdefghijk");
				ps.executeUpdate();
				System.out.println("2222222");
				
				ps.setInt(1, 1);
				ps.setString(2, "hijklmn");
				ps.executeUpdate();
				System.out.println("3333333");
				
				conn.commit();
			}
		}
	}
}

运行程序,报错如下:

1111111
Exception in thread "main" com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2447)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2430)
	at com.ibm.db2.jcc.t4.bb.m(bb.java:415)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:62)
	at com.ibm.db2.jcc.t4.p.a(p.java:50)
	at com.ibm.db2.jcc.t4.wb.b(wb.java:220)
	at com.ibm.db2.jcc.am.tp.uc(tp.java:3567)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4613)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4798)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.mc(tp.java:817)
	at com.ibm.db2.jcc.am.tp.executeUpdate(tp.java:791)
	at testJDBC.Test0207.main(Test0207.java:26)
	Suppressed: com.ibm.db2.jcc.am.SqlException: [jcc][t4][10251][10308][4.21.29] java.sql.Connection.close() requested while a transaction is in progress on the connection.
The transaction remains active, and the connection cannot be closed. ERRORCODE=-4471, SQLSTATE=null
		at com.ibm.db2.jcc.am.kd.a(kd.java:794)
		at com.ibm.db2.jcc.am.kd.a(kd.java:66)
		at com.ibm.db2.jcc.am.kd.a(kd.java:133)
		at com.ibm.db2.jcc.am.Connection.checkForTransactionInProgress(Connection.java:1457)
		at com.ibm.db2.jcc.t4.b.checkForTransactionInProgress(b.java:7374)
		at com.ibm.db2.jcc.am.Connection.closeResourcesX(Connection.java:1480)
		at com.ibm.db2.jcc.am.Connection.closeX(Connection.java:1466)
		at com.ibm.db2.jcc.am.Connection.close(Connection.java:1443)
		at testJDBC.Test0207.main(Test0207.java:36)

Test 7

使用Mybatis框架来做insert操作:

package testMybatis;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test0207 {

	public static void main(String[] args) throws Exception {
		MyObject obj = new MyObject();
		
		obj.setC1(1);
		obj.setC2("abcdefghijk");
		
		String resource = "mybatis-config.xml";
		
		InputStream inputStream = Resources.getResourceAsStream(resource);
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		SqlSession sqlSession = sqlSessionFactory.openSession(true);
		
		Test0207Mapper mapper = sqlSession.getMapper(Test0207Mapper.class);
		
		mapper.insert(obj);
		
		sqlSession.close();
	}
}

运行程序,报错如下:

Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
### The error may exist in testMybatis/Test0207Mapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: insert into t6 values (?, ?)
### Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:196)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
	at com.sun.proxy.$Proxy4.insert(Unknown Source)
	at testMybatis.Test0207.main(Test0207.java:28)
Caused by: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2447)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2430)
	at com.ibm.db2.jcc.t4.bb.m(bb.java:415)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:62)
	at com.ibm.db2.jcc.t4.p.a(p.java:50)
	at com.ibm.db2.jcc.t4.wb.b(wb.java:220)
	at com.ibm.db2.jcc.am.tp.uc(tp.java:3567)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4613)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4798)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.oc(tp.java:2870)
	at com.ibm.db2.jcc.am.tp.execute(tp.java:2845)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194)
	... 6 more

Test 8

相比前面的JDBC程序:

  1. Auto Commit设置为false
  2. 在有问题的insert语句前后各添加一个没问题的insert语句
  3. 通过打印语句查看程序运行过程

运行结果:

  1. 第2个insert语句出错时,程序直接抛出了异常,并不是在最后commit时才抛出异常
  2. 总体插入数量为2(因为每个insert操作都捕获了异常,第2个insert出错,不影响第1个和第3个insert操作)
package testMybatis;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test0207_2 {

	public static void main(String[] args) throws Exception {
		MyObject obj = new MyObject();
		
		obj.setC1(1);
		obj.setC2("abcdefg");
		
		MyObject obj2 = new MyObject();
		
		obj2.setC1(1);
		obj2.setC2("abcdefghijk");
		
		MyObject obj3 = new MyObject();
		
		obj3.setC1(1);
		obj3.setC2("hijklmn");
		
		String resource = "mybatis-config.xml";
		
		InputStream inputStream = Resources.getResourceAsStream(resource);
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		SqlSession sqlSession = sqlSessionFactory.openSession(false);
		
		Test0207Mapper mapper = sqlSession.getMapper(Test0207Mapper.class);
		
		try {
			mapper.insert(obj);
			System.out.println("1111111");
		} catch (Exception e) {
			e.printStackTrace();
		}

		try {
			mapper.insert(obj2);
			System.out.println("2222222");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			mapper.insert(obj3);
			System.out.println("3333333");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		sqlSession.commit();
		
		sqlSession.close();
	}
}

运行程序,报错如下:

1111111
org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
### The error may exist in testMybatis/Test0207Mapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: insert into t6 values (?, ?)
### Cause: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:196)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
	at com.sun.proxy.$Proxy4.insert(Unknown Source)
	at testMybatis.Test0207_2.main(Test0207_2.java:46)
Caused by: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.am.sp.b(sp.java:2447)
	at com.ibm.db2.jcc.am.sp.c(sp.java:2430)
	at com.ibm.db2.jcc.t4.bb.m(bb.java:415)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:62)
	at com.ibm.db2.jcc.t4.p.a(p.java:50)
	at com.ibm.db2.jcc.t4.wb.b(wb.java:220)
	at com.ibm.db2.jcc.am.tp.uc(tp.java:3567)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4613)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.a(tp.java:4798)
	at com.ibm.db2.jcc.am.tp.b(tp.java:4173)
	at com.ibm.db2.jcc.am.tp.oc(tp.java:2870)
	at com.ibm.db2.jcc.am.tp.execute(tp.java:2845)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194)
	... 6 more
3333333

Test 9

使用Mybatis的batch insert:

  1. insert处没有报错,直到最后commit时才报错
  2. 报错是 org.apache.ibatis.exceptions.PersistenceException ,它并不包含具体的错误信息,只是说提交事务出错了。其cause( org.apache.ibatis.executor.BatchExecutorException )提示 testMybatis.Test0207Mapper.insert (即mapper里所定义的接口方法)操作有错。它的cause( com.ibm.db2.jcc.am.BatchUpdateException )提示说batch操作中有异常,使用 getNextException() 方法来获取具体异常。所以:
    1. 这里并没有给出具体的错误信息,在log里只能看到batch操作有错误,根本没法定位错误原因
    2. PersistenceException.getCause() -> BatchExecutorException.getCause() -> BatchUpdateException.getNextException() -> SqlDataException 此处才有真正的错误原因
    3. 因为我知道异常是这样的结构,所以在程序里hard code,直接用上述方法找到真正的异常,并打印出了异常信息。注意log里 ================ 所分隔的信息
  3. log testMybatis.Test0207Mapper.insert (batch index #1) failed 这句话里的 batch index #1 我没有理解是什么意思。本来我以为它指示了batch操作中的第几条SQL有错,但经过试验发现,不管第几条SQL有错,log里始终显示 #1 。此处待查
  4. log Error for batch element #2 原先我以为是insert操作的第2个元素有问题,但经过试验发现,这个 #2 才是表明了batch操作中的第几条SQL有错,此处的 2 表明是第2个SQL有错
  5. 内嵌的具体异常跟上面非batch操作时的异常完全一样(Db2 -302 error)。参考上面的总结,我们无法确定是第几个元素有问题
package testMybatis;

import java.io.InputStream;
import java.sql.SQLException;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.ibm.db2.jcc.am.BatchUpdateException;

public class Test0207_3 {

	public static void main(String[] args) throws Exception {
		MyObject obj = new MyObject();
		
		obj.setC1(1);
		obj.setC2("abcdefg");
		
		MyObject obj2 = new MyObject();
		
		obj2.setC1(1);
		obj2.setC2("abcdefghijk");
		
		MyObject obj3 = new MyObject();
		
		obj3.setC1(1);
		obj3.setC2("hijklmn");
		
		String resource = "mybatis-config.xml";
		
		InputStream inputStream = Resources.getResourceAsStream(resource);
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
		
		Test0207Mapper mapper = sqlSession.getMapper(Test0207Mapper.class);
		
		try {
			mapper.insert(obj);
			System.out.println("1111111");
		} catch (Exception e) {
			e.printStackTrace();
		}

		try {
			mapper.insert(obj2);
			System.out.println("2222222");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			mapper.insert(obj3);
			System.out.println("3333333");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			sqlSession.commit();
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("================");
			Throwable cause = e.getCause().getCause();
			if (cause instanceof BatchUpdateException) {
				SQLException e2 = ((BatchUpdateException)cause).getNextException();
				e2.printStackTrace();
			}
		}
		
		sqlSession.close();
	}
}

运行程序,报错如下:

1111111
2222222
3333333
org.apache.ibatis.exceptions.PersistenceException: 
### Error committing transaction.  Cause: org.apache.ibatis.executor.BatchExecutorException: testMybatis.Test0207Mapper.insert (batch index #1) failed. Cause: com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][4.21.29] Batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch.
Use getNextException() to retrieve the exceptions for specific batched elements. ERRORCODE=-4229, SQLSTATE=null
### Cause: org.apache.ibatis.executor.BatchExecutorException: testMybatis.Test0207Mapper.insert (batch index #1) failed. Cause: com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][4.21.29] Batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch.
Use getNextException() to retrieve the exceptions for specific batched elements. ERRORCODE=-4229, SQLSTATE=null
================
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:223)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:214)
	at testMybatis.Test0207_3.main(Test0207_3.java:64)
Caused by: org.apache.ibatis.executor.BatchExecutorException: testMybatis.Test0207Mapper.insert (batch index #1) failed. Cause: com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][4.21.29] Batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch.
Use getNextException() to retrieve the exceptions for specific batched elements. ERRORCODE=-4229, SQLSTATE=null
	at org.apache.ibatis.executor.BatchExecutor.doFlushStatements(BatchExecutor.java:149)
	at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:129)
	at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:122)
	at org.apache.ibatis.executor.BaseExecutor.commit(BaseExecutor.java:242)
	at org.apache.ibatis.executor.CachingExecutor.commit(CachingExecutor.java:119)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:220)
	... 2 more
Caused by: com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][4.21.29] Batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch.
Use getNextException() to retrieve the exceptions for specific batched elements. ERRORCODE=-4229, SQLSTATE=null
	at com.ibm.db2.jcc.am.kd.a(kd.java:502)
	at com.ibm.db2.jcc.am.Agent.endBatchedReadChain(Agent.java:416)
	at com.ibm.db2.jcc.am.tp.a(tp.java:5328)
	at com.ibm.db2.jcc.am.tp.c(tp.java:4915)
	at com.ibm.db2.jcc.am.tp.executeBatch(tp.java:3048)
	at org.apache.ibatis.executor.BatchExecutor.doFlushStatements(BatchExecutor.java:123)
	... 7 more
com.ibm.db2.jcc.am.SqlDataException: Error for batch element #2: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.21.29
	at com.ibm.db2.jcc.am.kd.a(kd.java:802)
	at com.ibm.db2.jcc.am.kd.a(kd.java:66)
	at com.ibm.db2.jcc.am.kd.a(kd.java:140)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:574)
	at com.ibm.db2.jcc.t4.bb.a(bb.java:70)
	at com.ibm.db2.jcc.t4.p.a(p.java:57)
	at com.ibm.db2.jcc.t4.wb.a(wb.java:225)
	at com.ibm.db2.jcc.am.tp.a(tp.java:3573)
	at com.ibm.db2.jcc.am.tp.d(tp.java:5825)
	at com.ibm.db2.jcc.am.tp.a(tp.java:5259)
	at com.ibm.db2.jcc.am.tp.c(tp.java:4915)
	at com.ibm.db2.jcc.am.tp.executeBatch(tp.java:3048)
	at org.apache.ibatis.executor.BatchExecutor.doFlushStatements(BatchExecutor.java:123)
	at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:129)
	at org.apache.ibatis.executor.BaseExecutor.flushStatements(BaseExecutor.java:122)
	at org.apache.ibatis.executor.BaseExecutor.commit(BaseExecutor.java:242)
	at org.apache.ibatis.executor.CachingExecutor.commit(CachingExecutor.java:119)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:220)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession.java:214)
	at testMybatis.Test0207_3.main(Test0207_3.java:64)

你可能感兴趣的:(DB,Java,数据库,db2,mybatis,jdbc)