Mybatis+Oracle搭配insert空值报错问题

为了便于SEO搜索到,首先把报错内容贴出来吧

不同版本的Oracle驱动会报不同的错

1 <dependency>
2     <groupId>com.oracle</groupId>
3     <artifactId>ojdbc6</artifactId>
4     <version>1.0</version>
5 </dependency>

报错如下:

Error updating database.  Cause: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property=‘name‘, mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId=‘null‘, jdbcTypeName=‘null‘, expression=‘null‘}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #1 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型: 1111

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc4</artifactId>
    <version>1.0</version>
</dependency>

报错如下:

Error updating database.  Cause: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property=‘name‘, mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId=‘null‘, jdbcTypeName=‘null‘, expression=‘null‘}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #1 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型

有异常那就一点一点的对着MyBatis调试追踪吧。避免啰嗦,就用ojdbc6调试吧;因为ojbc6与mybatis的最新版本搭配更稳定。

至于为什么不稳定可以看看我的这篇博客:MyBatis+Oracle时出现的错误: Method oracle/jdbc/driver/OracleResultSetImpl.isClosed()Z is abstract

便于源码分析,还是先上Demo吧。

mybatis-oracle-config.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 3         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 4
 5 <configuration>
 6     <properties>
 7         <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
 8         <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521/orcl"/>
 9     </properties>
10
11     <environments default="dev">
12         <environment id="dev">
13             <dataSource type="POOLED">
14                 <property name="driver" value="${driver}"></property>
15                 <property name="url" value="${url}"></property>
16                 <property name="username" value="gys"></property>
17                 <property name="password" value="gys"></property>
18             </dataSource>
19         </environment>
20
21     </environments>
22     <mappers>
23         <mapper resource="mapper/oracle/user.xml"></mapper>
24     </mappers>
25 </configuration>

user.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 3         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 4 <mapper namespace="dao.oracle.IUserMapper">
 5     <insert id="insertUser" parameterType="model.oracle.User">
 6         insert into users
 7         (name,age)
 8         values
 9         (#{name},#{age})
10     </insert>
11 </mapper>

Main方法入口:

 1  public static void main(String[] args) throws Exception{
 2         SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
 3         SqlSessionFactory sqlSessionFactory=builder.build(Resources.getResourceAsStream("mybatis-oracle-config.xml"),"dev");
 4         SqlSession sqlSession=sqlSessionFactory.openSession(true);
 5         IUserMapper userMapper=sqlSession.getMapper(IUserMapper.class);
 6         User user=new User();
 7    //此处不设置,故意插入null数据
 8         //user.setName("gggg");
 9         user.setAge(20);
10         int count=userMapper.insertUser(user);
11         System.out.println(count == 1 ? "插入成功" : "插入失败");
12         sqlSession.close();
13     }

运行结果就是上面的报错内容了。

我们直接从SimpleExecutor.java执行器开始分析吧。

不了解执行器的可以看看我的这篇博客:MyBatis中Executor源码解析之BatchExecutor搞不懂

这个地方的stmt是指向OraclePreparedStatementWrapper.java这个类的;

看来这个是Oracle驱动提供的类,继承了JDBC的Statement接口

同时这个handler是指向RoutingStatementHandler类

第88行代码是开始进行sql参数进行设置的方法。我们追踪进去看看是如何实现的。

直接去PreparedStatementHandler类吧;因为RoutingStatmentHandler继承自PreparedStatmentHandler类。

 继续看setParameters()源码:

 1 @Override
 2 public void setParameters(PreparedStatement ps) {
 3 //获取该sql中所有的参数映射对象
 4  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
 5   if (parameterMappings != null) {
 6    for (int i = 0; i < parameterMappings.size(); i++) {
 7       ParameterMapping parameterMapping = parameterMappings.get(i);
 8       //如果不是出参
 9       if (parameterMapping.getMode() != ParameterMode.OUT) {
10        Object value;
11       //获取参数的属性名,比如name,age
12        String propertyName = parameterMapping.getProperty();
13          MetaObject metaObject = configuration.newMetaObject(parameterObject);
14          //获取参数的预设值,比如name=5,这里value就是5
15          value = metaObject.getValue(propertyName);
16          //根据参数获取类型转换器
17        TypeHandler typeHandler = parameterMapping.getTypeHandler();
18          //获取jdbc类型,这里是枚举;如果是空着,返回other枚举值,并且枚举的code属性值是1111
19        JdbcType jdbcType = parameterMapping.getJdbcType();
20        //这行条件基本不会执行,因为jdbcType在build时候,始终都会有值,空值的话默认是other枚举
21        if (value == null && jdbcType == null) {
22          jdbcType = configuration.getJdbcTypeForNull();
23        }
24        //参数设置开始交给类型转换器进行赋值
25        typeHandler.setParameter(ps, i + 1, value, jdbcType);
26      }
27    }
28  }
29 }   

去除了干扰的代码,添加了注释,继续想下追踪

typeHandler指向StringTypeHandler类,这里面没有seParameter()方法,直接去父级BaseTypeHandler类中找吧。

setParameter()源码

去除多余干扰的代码

 1  @Override
 2   public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
 3       //参数值为空
 4     if (parameter == null) {
 5         //jdbcType为空,这里不可能为空,最起码是默认枚举other
 6       if (jdbcType == null) {
 7         throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
 8       }
 9       try {
10           /**
11           i是参数位置,第一个参数这里就是1
12         jdbcType.TYPE_CODE是枚举的编码值,这里空值是1111·
13           **/
14         ps.setNull(i, jdbcType.TYPE_CODE);
15       } catch (SQLException e) {
16           //这里的异常内容是不是很熟悉,就是我们在控制台看到的内容。看来异常就是上面setNull方法抛出的了
17         throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
18               + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
19               + "Cause: " + e, e);
20       }
21     }    //如果不是空值,就直接走这里了    else{setNonNullParameter(ps, i, parameter, jdbcType);} 22 }

继续查看

setNull()方法源码

继续去T4CPreparedStatement中查看setNull()源码

继续追踪setNullCritical()源码

继续追踪到getInternalType()源码

  1 int getInternalType(int var1) throws SQLException {
  2         boolean var2 = false;
  3         short var4;
  4         switch(var1) {
  5         case -104:
  6             var4 = 183;
  7             break;
  8         case -103:
  9             var4 = 182;
 10             break;
 11         case -102:
 12             var4 = 231;
 13             break;
 14         case -101:
 15             var4 = 181;
 16             break;
 17         case -100:
 18         case 93:
 19             var4 = 180;
 20             break;
 21         case -16:
 22         case -1:
 23             var4 = 8;
 24             break;
 25         case -15:
 26         case -9:
 27         case 12:
 28             var4 = 1;
 29             break;
 30         case -14:
 31             var4 = 998;
 32             break;
 33         case -13:
 34             var4 = 114;
 35             break;
 36         case -10:
 37             var4 = 102;
 38             break;
 39         case -8:
 40             var4 = 104;
 41             break;
 42         case -7:
 43         case -6:
 44         case -5:
 45         case 2:
 46         case 3:
 47         case 4:
 48         case 5:
 49         case 6:
 50         case 7:
 51         case 8:
 52             var4 = 6;
 53             break;
 54         case -4:
 55             var4 = 24;
 56             break;
 57         case -3:
 58         case -2:
 59             var4 = 23;
 60             break;
 61         case 0:
 62             var4 = 995;
 63             break;
 64         case 1:
 65             var4 = 96;
 66             break;
 67         case 70:
 68             var4 = 1;
 69             break;
 70         case 91:
 71         case 92:
 72             var4 = 12;
 73             break;
 74         case 100:
 75             var4 = 100;
 76             break;
 77         case 101:
 78             var4 = 101;
 79             break;
 80         case 999:
 81             var4 = 999;
 82             break;
 83         case 2002:
 84         case 2003:
 85         case 2007:
 86         case 2008:
 87         case 2009:
 88             var4 = 109;
 89             break;
 90         case 2004:
 91             var4 = 113;
 92             break;
 93         case 2005:
 94         case 2011:
 95             var4 = 112;
 96             break;
 97         case 2006:
 98             var4 = 111;
 99             break;
100         default:
101             SQLException var3 = DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), 4, Integer.toString(var1));
102             var3.fillInStackTrace();
103             throw var3;
104         }
105
106         return var4;
107     }

因为case中没有1111匹配项,所以只能进入default中了。

default中定义了一个异常类,并在最后义无反顾的throw掉了。一个空值的赋值处理总算告一段落了。

这个地方不是太明白什么意思,这些case 后面的数值都代表什么意思,我看只有oracle驱动开发的人才能明白了。

这个地方的设计好奇怪啊;

原文地址:https://www.cnblogs.com/guoyansi19900907/p/12696023.html

时间: 2024-10-06 00:24:18

Mybatis+Oracle搭配insert空值报错问题的相关文章

Android开发时,sqlite创建表成功,insert不报错,但没有数据插入的原因

在android开发过程中,经常要通过sqlite来存储一些数据,这种应用应该是再平常不过了,但是有时难免一时疏忽,就会出现sqlite创建表成功,insert不报错,但没有数据插入. 具体问题详见如下代码: Context ctx;        SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); // 开启事务        db.beginTransaction();        try{                // 数

Oracle启动监听报错:The listener supports no services解决

Oracle启动监听报错:The listener supports no services解决 及ora-12514 未注册上服务问题. Oracle11g服务器重启系统之后,出现了几个莫名的报错,下面是其中一个,已解决. $ lsnrctl start 报错提示: The listener supports no servicesThe command completed successfully 这样启动后远程连接会报错:oracle ORA-12514:TNS:listener does

Loadrunner参数化连接oracle、mysql数据源报错及解决办法

Loadrunner参数化连接oracle.mysql数据源报错及解决办法 (本人系统是Win7 64,  两位小伙伴因为是默认安装lr,安装在 最终参数化的时候,出现连接字符串无法自动加载出来: 最后通过安装在,问题到此解决 1.通过数据库连接参数化大量数据,电脑本地已经成功安装了数据库驱动,且本地可以配置数据源成功,在loadrunner 中配置数据源却找不到对应的数据库驱动. ----A:检查当前loadrunner工具的版本,是32位还是64位(目前还没有64位的),32位是不能安装64

Mybatis 传入List类型参数,报错:There is no getter for property named &#39;__frch_item_0&#39; in

错误如下: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named '__frch_item_0' in 'class com.asiacloud.core.model.PageModel' at org.mybatis.spring.MyBatisEx

VC++ 通过ADO连接数据库查询时返回空值报错的解决方案

当数据库的字段值允许为空时, 而且此时内容也为空时,则执行查询会出错,例如 CString str = pRecordset->GetFields()->GetItem((long)0)->GetValue(); 或者 str= pRecordset->GetCollect("posInfo"); 会弹出如下窗口提示出错! 更加奇怪的是  catch(...)也抓不到异常 今天碰着个问题算是头弄大了  最后终于弄好了 报错的原因:   在GetCollct返回了

Oracle:dump文件导入报错:只有DBA才能导入由其他DBA导出的文件

从SchemaA(DBA权限)导出一个表的dump文件,导入到SchemaB(非DBA权限),报错. 用OB工具设定SchemaA为DBA不管用(以前的表和视图都不见了), 上网查了一下以下两句执行后OK: grant dba to SchemaA; alter user  SchemaAdefault role DBA: 然后dump导入OK,利用OB工具取消SchemaA的DBA权限后, 又报错"ora-01045 :user system lacks create session priv

MySql数据库执行insert时候报错:Column count doesn&#39;t match value count at row 1

遇到这个问题之后,第一反应就是前后列数不等造成的,但是我检查SQL之后,发现列数是相同得,但是插入还是有问题,然后又写了简单得SQL只插入不为空得字段,执行还是报这个错,最后请教了高人,指点之后,大概是因为当前插入得表被锁住了,然后执行下面得SQL后,之前得SQL就可以正常插入了 LOCK TABLES `system_function_info` WRITE;  UNLOCK TABLES; MySql数据库执行insert时候报错:Column count doesn't match val

IDEA中写MyBatis的xml配置文件编译报错的坑

IDEA中写MyBatis的xml配置文件编译报错的坑 说明:用IDEA编译工具在项目中使用Mybatis框架,编写mybatis-config.xml和Mapper.xml配置文件时,编译项目出现错误,错误提示为: xml中1字节的UTF-8序列的字节1无效 The cause of this is a file that is not UTF-8 is being parsed as UTF-8. It is likely that the parser is encountering a

mybatis学习 -每天一记 mybatis insert null 报错

mybatis 插入数据,model的属性存在null,插入报错 在使用mybatis 进行insert时,如果字段值存在null的情况,会出现插入失败的情况,解决方案: 如果使用spring boot: @Bean ConfigurationCustomizer mybatisConfigurationCustomizer() { return new ConfigurationCustomizer() { @Override public void customize(org.apache.