mysql字段默认值不生效的问题解决(上)

在项目中使用mybatis做为持久层框架,mysql数据库。项目上线前,DBA要求我们将每张数据库表中的字段都设置默认值和not null。之前项目中有一些insert语句是将表中所有字段都列出来,然后把它做为一个通用的插入语句来使用。举个简单的例子:假如一张数据库表blog中有如下几个字段:id,title,content,author,除id外,每个字段都设置了默认值Empty String(空字符串),写的一个insert语句是这样的: 

Java代码   收藏代码

  1. <insert id="addOneBlog" parameterType="main.Blog">
  2.     insert into blog(title,author,content)  
  3.     values(#{title},#{author},#{content})  
  4. </insert>  

    原以为有这么一个insert语句就万事大吉了,我们以为,以后做插入操作的时候,无论有多少个字段,都使用这一个insert语句,如果字段没有值,就会被赋值为mysql字段的默认值。。。 

    但事实证明,根本不是这样的。 

    当我们只给title字段赋值,然后执行一个insert语句时,mybatis马上报出这样的异常: 

Java代码   收藏代码

  1. Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column 'content' cannot be null

    显然,所有字段规定了not null,看来按照这种insert的方法,未赋值的字段并没有赋值为mysql的默认值。 

    那么如果把数据库字段的not null限制去掉呢? 

    再次执行刚才的insert操作,这次没有抛出异常,但查看数据库后,我们发现,新插入的表记录中,没有赋值的字段仍然不是mysql的默认值,而是null值。 

    所以,按照上面所谓的通用insert语句,是无法让未赋值字段的值变为mysql默认值的。这种insert语句无法做到通用。具体解决方案

 

上一篇简单介绍了一个mysql的问题:字段默认值在使用全字段insert的时候,可能并不会生效。在使用mybatis时,虽然需要自己写sql,但相比原始jdbc的方式来说,有一个很好的优势——动态sql。针对前一篇文章提出的问题,mybatis的动态sql可以很好地解决这个问题。

1.问题分析

    上一篇文章中描述的问题,是由于我们误将一个包含所有字段的insert语句做为通用的insert。那么显而易见,解决此问题的方法是,我们需要针对不同的业务需求,严格按照需要插入的字段来写不同的sql,不需要插入的字段,在insert语句中不能够出现。举例上一篇的blog表例子说明,假如我们有一个插入操作,只需要在插入时给author赋值,那么sql可以这么写:

Xml代码   收藏代码

  1. <insert id="addOneBlog" parameterType="main.Blog">
  2.     insert into blog(author)  
  3.     values (#{author})  
  4. </insert>

    这个方法虽然奏效,但在实际项目开发中,为了开发效率的需要,我们仍然希望能够有一个通用的insert语句,供所有涉及单表插入操作的业务调用。刚才说过,mybatis有一个非常强大的特色功能:动态sql,使用动态sql即可解决此问题。

2.<sql><include><trim>标签简介

    mybatis的动态sql功能包含了很多实用的标签:<sql>标签表示一个sql片段,使用此标签不仅可以重用很多sql代码,而且使sql语句更清晰;定义好<sql>标签后,在调用它的地方使用<include>标签,即可将定义好的sql片段拼接进来;<trim>标签可以在标签体内的sql片段首尾任意添加或覆盖字符。

3.问题解决

先上代码:

Xml代码   收藏代码

  1. <sql id="blogColumns">

  2.     <trim suffixOverrides=",">

  3.         <if test="title != null">title,</if>

  4.         <if test="author != null">author,</if>

  5.         <if test="content != null">content</if>

  6.     </trim>

  7. </sql>

  8. <sql id="blogValues">

  9.     <trim suffixOverrides=",">

  10.         <if test="title != null">#{title},</if>

  11.         <if test="author != null">#{author},</if>

  12.         <if test="content != null">#{content}</if>

  13.     </trim>

  14. </sql>

  15. <insert id="addOneBlog" parameterType="Blog">

  16.     insert into blog(<include refid="blogColumns"/>)

  17.     values (<include refid="blogValues"/>)

  18. </insert>

     对于blog表,上面这段代码即可实现我们想要的insert重用,不管插入的字段有多少,我们都可以使用它来实现所有单表insert操作。上面代码中,先定义两个sql片段,分别代表insert语句中的字段列表和参数列表,并使用<trim>标签去除片段首尾可能出现的多余的“,”字符。最后写一个简单的insert,并将上面的sql片段拼接进来。

4.结尾

    关于mybatis的动态sql,它有很多强大的,可高度重用sql的功能。大家如果对一些标签的作用不太清楚,请期待我后续的博文。作为一个半自动的持久层框架,我们虽然需要自己写sql语句,但mybatis的动态sql能够最大限度地减少我们的代码量,这也是在ORM横行的JavaEE世界里,mybatis能够独树一帜的原因。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

sql注入

反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Python3:sqlalchemy对mysql数据库操作,非sql语句

Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''

Twitter的分布式自增ID算法snowflake (Java版)

概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移