zoukankan      html  css  js  c++  java
  • (转)MyBatis在插入的数据有空值时,可能为空的字段都要设置jdbcType

    1 引言

    前面的所有语句中你所见到的都是简单参数的例子,实际上参数是 MyBatis 非常强大的元素,对于简单的做法, 90% 的情况参数都很少,比如:

    <select id="selectUsers" resultType="User">
      select id, username, password
      from users
      where id = #{id}
    </select>

     上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为 int,这样这个参数就可以被设置成任何内容。

    原生的类型或简单数据类型(比如整型和字符串)因为没有相关属性,它会完全用参数值来替代。然而,如果传入一个复杂的对象,行为就会有一点不同了。比如:

    <insert id="insertUser" parameterType="User">
      insert into users (id, username, password)
      values (#{id}, #{username}, #{password})
    </insert>

    如果 User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。

    这点对于向语句中传参是比较好的而且又简单,不过参数映射的功能远不止于此。

    2 Mybitis参数类型

    首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

    #{property,javaType=int,jdbcType=NUMERIC} 

    像 MyBatis 的剩余部分一样,javaType 通常可以从参数对象中来去确定,前提是只要对象不是一个 HashMap。那么 javaType 应该被确定来保证使用正确类型处理器。

    NOTE 如果 null 被当作值来传递,对于所有可能为空的列,需要设置参数的jdbcType。你可以自己通过阅读预处理语句的 setNull() 方法的 JavaDocs 文档来研究这种情况。

    为了以后定制类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

    #{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

    尽管看起来配置变得越来越繁琐,但实际上是很少去设置它们。

    对于数值类型,还有一个小数保留位数的设置,来确定小数点后保留的位数。

    #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

    最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。

    如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像你在获取输出参数时所期望的那样。如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 来映射结果集到参数类型。要注意这里的 javaType 属性是可选的,如果左边的空白是 jdbcType 的 CURSOR 类型,它会自动地被设置为结果集。

    #{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

    MyBatis 也支持很多高级的数据类型,比如结构体,但是当注册 out 参数时你必须告诉它语句类型名称。比如(再次提示,在实际中要像这样不能换行):

    #{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

    尽管所有这些强大的选项很多时候你只简单指定属性名,其他的事情 MyBatis 会自己去推断,最多你需要为可能为空的列名指定 jdbcType

    #{firstName}
    #{middleInitial,jdbcType=VARCHAR}
    #{lastName}

    3 字符串替换

    默认情况下,使用#{}格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值(比如?)。这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:

    ORDER BY ${columnName}

    这里 MyBatis 不会修改或转义字符串。

    NOTE 以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

    3.1 #{}与${}

    注意以下两个符号的使用:

    #{}(ibatis为:##):MyBatis创建预处理语句属性从而设置安全的值(比如?)。常用作查询条件的值,例如:where name=#{value}。 
    该参数可以指定一个确切的数据类型,例如: #{property,javaType=int,jdbcType=NUMERIC}. 
    ${}(ibatis为:$$): MyBatis不会修改或转义字符串,将会直接在SQL语句中插入一个不改变的字符串,常用于拼凑sql的实体部分,
    例如:select * from ${tableName}

    在执行SQL时MyBatis会自动通过对象中的属性给SQL中参数赋值,它会自动将Java类型转换成数据库的类型。而一旦传入的是null它就无法准确判断这个类型应该是什么,就有可能将类型转换错误,从而报错。
    要解决这个问题,需要针对这些可能为空的字段,手动指定其转换时用到的类型。

    一般情况下,我们没有必要按个字段去识别/判断它是否可以为空,而是将所有的字段都当做可以为空,全部手动设置转换类型。

    [java] view plain copy

    1. <insert id="save"  
    2.         parameterType="com.tarena.entity.Cost">  
    3.         insert into cost values(  
    4.             cost_seq.nextval,  
    5.             #{name,jdbcType=VARCHAR},  
    6.             #{base_duration,jdbcType=INTEGER},  
    7.             #{base_cost,jdbcType=DOUBLE},  
    8.             #{unit_cost,jdbcType=DOUBLE},  
    9.             #{status,jdbcType=CHAR},  
    10.             #{descr,jdbcType=VARCHAR},  
    11.             #{creatime,jdbcType=TIMESTAMP},  
    12.             #{startime,jdbcType=TIMESTAMP},  
    13.             #{cost_type,jdbcType=CHAR}  
    14.         )  
    15.     </insert>  

    再次插入一条空数据,测试结果,能插入数据库。

    其他数据类型参照下图表:

  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/lxl57610/p/6796411.html
Copyright © 2011-2022 走看看