zoukankan      html  css  js  c++  java
  • MyBatis+Oracle在执行insert时空值报错之从源码寻找解决办法

    为了便于测试,先给出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     <environments default="dev">
    11         <environment id="dev">        
    12             <transactionManager type="JDBC" />
    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 
    12 </mapper>

    main()入口方法

    public static void main(String[] args) throws Exception{  
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory=builder.build(Resources.getResourceAsStream("mybatis-oracle-config.xml"),"dev");
            SqlSession sqlSession=sqlSessionFactory.openSession(true);
            IUserMapper userMapper=sqlSession.getMapper(IUserMapper.class);
            User user=new User();
            //user.setName("a");//故意注释,不设置。模拟空值
            user.setAge(20);
            int count=userMapper.insertUser(user);
            System.out.println(count == 1 ? "插入成功" : "插入失败");
            List<User> list=userMapper.getUserList();
            for (User user1 : list) {
                System.out.println(user1.toString());
            }
            sqlSession.close();
        }

    源码分析请参考这篇博客:Mybatis+Oracle搭配insert空值报错之myBatis+mysql驱动+oracle驱动的源码分析

    总结一下空值报错的原因:

    mybatis在build阶段,不知道这个参数的具体jdbcType类型,mybatis会给他一个默认的1111编号;

    在mybatis运行阶段,空值 +111编号条件就使得MyBatis去调用了Oracle驱动中预编译器的setNull()方法;

    因为oracle不识别1111编号,所以直接就抛出了异常。

    方法1:构建时办法

    在user.xml的sql中,给参数指明具体的jdbcType类型,让oracle预编译器能够知道以varchar或者NUMERIC方式处理这种空值。

    修改后的代码如下红色地方。 

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

     方法2:运行时办法 

    编写自定义的typeHandler。

    当MyBatis不知道具体的jdbcType类型时,在自定义typeHandler中指定jdbcType。

    数据库中常用的就两种字段,一个VARCHAR字段,一个NUMBERIC字段。所以定义两个typeHandler。

    public class MyNumberNullTypeHandler extends IntegerTypeHandler {
        @Override
        public void setParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) throws SQLException {
            super.setParameter(ps, i, parameter, JdbcType.NUMERIC);
        }
    }
    public class MyStringNullTypeHandler extends StringTypeHandler {
        @Override
        public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {       
            super.setParameter(ps,i,parameter,JdbcType.VARCHAR);
        }
    }

    mybatis-oracle-config.xml中的properties后面添加如下配置

      <typeHandlers>
           <typeHandler handler="handler.oracle.MyStringNullTypeHandler" />
            <typeHandler handler="handler.oracle.MyIntegerNullTypeHandler" />
        </typeHandlers>

    综合比较后感觉方法2是一个一劳永逸的方法。

  • 相关阅读:
    ElasticSearch-03-远行、停止
    ElasticSearch-02-elasticsearch.yaml
    Go-31-杂序
    Go-30-main包
    SpringBoot 初入门
    Spring 事务管理
    JDBC Template
    Spring 基于 AspectJ 的 AOP 开发
    Spring AOP 代理
    Spring 的 AOP 概述和底层实现
  • 原文地址:https://www.cnblogs.com/guoyansi19900907/p/12703701.html
Copyright © 2011-2022 走看看