• mybatis xml文件中 是否需要指定jdbcType


    本人偷懒,不想写jdbcType,又怕不写导致问题,所以就对这个研究了一下。网上很多说不设置jdbcType会导致报错,我试了一下发现都没有报错。
    当前环境:jdk 1.8,mybatis3.2.6,mysql 8.0.19。

    官方文档说明

    mybatis 官方文档
    和 MyBatis 的其它部分一样,几乎总是可以根据参数对象的类型确定 javaType,除非该对象是一个 HashMap。这个时候,你需要显式指定 javaType 来确保正确的类型处理器(TypeHandler)被使用。
    提示 JDBC 要求,如果一个列允许使用 null 值,并且会使用值为 null 的参数,就必须要指定 JDBC 类型(jdbcType)。阅读 PreparedStatement.setNull()的 JavaDoc 来获取更多信息。

    我编写了相关的 使用对象,HashMap 传递参数,值为null,不设置jdbcType 的情况,但是都没有抛出异常。

    既然文档提到了PreparedStatement.setNull()方法,我们看一下。

    PreparedStatement.setNull() 方法

     /**
         * Sets the designated parameter to SQL <code>NULL</code>.
         *
         * <P><B>Note:</B> You must specify the parameter's SQL type.
         *
         * @param parameterIndex the first parameter is 1, the second is 2, ...
         * @param sqlType the SQL type code defined in <code>java.sql.Types</code>
         * @exception SQLException if parameterIndex does not correspond to a parameter
         * marker in the SQL statement; if a database access error occurs or
         * this method is called on a closed <code>PreparedStatement</code>
         * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
         * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
         * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
         * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
         *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
         * or  <code>STRUCT</code> data type and the JDBC driver does not support
         * this data type
         */
        void setNull(int parameterIndex, int sqlType) throws SQLException;
    

    如果 sqlType 是 java.sql.Types中的 ARRAY,BLOB ... 等类型或JDBC driver 不支持的数据类型,会抛出SQLFeatureNotSupportedException 异常。

    网上搜 如果jdbcType未设置并且值传的是空的,会导致执行这段代码 throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");相关的方法如下

    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);
        }
      }
    

    我debug了一下,发现是由org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters 这个方法调用的。

    org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters

     public void setParameters(PreparedStatement ps) throws SQLException {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
          for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            if (parameterMapping.getMode() != ParameterMode.OUT) {
              Object value;
              String propertyName = parameterMapping.getProperty();
              if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                value = boundSql.getAdditionalParameter(propertyName);
              } else if (parameterObject == null) {
                value = null;
              } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                value = parameterObject;
              } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                value = metaObject.getValue(propertyName);
              }
              TypeHandler typeHandler = parameterMapping.getTypeHandler();
              JdbcType jdbcType = parameterMapping.getJdbcType();
             
              if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
              typeHandler.setParameter(ps, i + 1, value, jdbcType);
            }
          }
        }
      }
    

    从setParameters方法我们可以这段代码 jdbcType = configuration.getJdbcTypeForNull(); 可以看出value和jdbcType为空的话,会使用默认的jdbcType,也就是JdbcType.OTHER。所以导致抛出上面提到的TypeException只有可能有两种情况。

    1. configuration.getJdbcTypeForNull()为空。
    2. 其他方法调用 org.apache.ibatis.type.BaseTypeHandler#setParameter 方法,传入的parameter,jdbcType都为null。(目前没找到)

    我猜想是mybatis 版本的问题的导致的,我又使用了mybatis 3.0.1版本,发现还是不会抛出异常。

    所以暂时我还是不写jdbcType。

  • 相关阅读:
    分布式哈希和一致性哈希算法
    消息队列rabbitmq的五种工作模式(go语言版本)
    Mysql查询缓存
    数据库的三大设计范式
    二叉树的常见算法
    消息队列选型分析
    Mysql防止索引失效原则
    Mysql索引优化单表、两表、三表实践
    数据结构 【栈与队列】
    谷歌实用插件
  • 原文地址:https://www.cnblogs.com/alway-july/p/14111011.html
Copyright © 2020-2023  润新知