在項目中使用mybatis做為持久層框架,mysql數據庫。項目上線前,DBA要求我們將每張數據庫表中的字段都設置默認值和not null。之前項目中有一些insert語句是將表中所有字段都列出來,然后把它做為一個通用的插入語句來使用。舉個簡單的例子:假如一張數據庫表blog中有如下幾個字段:id,title,content,author,除id外,每個字段都設置了默認值Empty String(空字符串),寫的一個insert語句是這樣的:
<insert id="addOneBlog" parameterType="main.Blog">
insert into blog(title,author,content)
values(#{title},#{author},#{content})
</insert>
原以為有這么一個insert語句就萬事大吉了,我們以為,以后做插入操作的時候,無論有多少個字段,都使用這一個insert語句,如果字段沒有值,就會被賦值為mysql字段的默認值。。。
但事實證明,根本不是這樣的。
當我們只給title字段賦值,然后執行一個insert語句時,mybatis馬上報出這樣的異常:
- Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Column 'content' cannot be null
顯然,所有字段規定了not null,看來按照這種insert的方法,未賦值的字段並沒有賦值為mysql的默認值。 那么如果把數據庫字段的not null限制去掉呢?再次執行剛才的insert操作,這次沒有拋出異常,但查看數據庫后,我們發現,新插入的表記錄中,沒有賦值的字段仍然不是mysql的默認值,而是null值。
所以,按照上面所謂的通用insert語句,是無法讓未賦值字段的值變為mysql默認值的。這種insert語句無法做到通用。
1.問題分析
由於我們誤將一個包含所有字段的insert語句做為通用的insert。那么顯而易見,解決此問題的方法是,我們需要針對不同的業務需求,嚴格按照需要插入的字段來寫不同的sql,不需要插入的字段,在insert語句中不能夠出現。
那么sql可以這么寫:
<insert id="addOneBlog" parameterType="main.Blog">
insert into blog(author)
values (#{author})
</insert>
這個方法雖然奏效,但在實際項目開發中,為了開發效率的需要,我們仍然希望能夠有一個通用的insert語句,供所有涉及單表插入操作的業務調用。剛才說過,mybatis有一個非常強大的特色功能:動態sql,使用動態sql即可解決此問題。
2.問題解決
1)<sql>、<include>、<trim>標簽簡介
mybatis的動態sql功能包含了很多實用的標簽:<sql>標簽表示一個sql片段,使用此標簽不僅可以重用很多sql代碼,而且使sql語句更清晰;定義好<sql>標簽后,在調用它的地方使用<include>標簽,即可將定義好的sql片段拼接進來;<trim>標簽可以在標簽體內的sql片段首尾任意添加或覆蓋字符。
於是解決的最終方法如下:
<sql id="blogColumns">
<trim suffixOverrides=",">
<if test="title != null">title,</if>
<if test="author != null">author,</if>
<if test="content != null">content</if>
</trim>
</sql>
<sql id="blogValues">
<trim suffixOverrides=",">
<if test="title != null">#{title},</if>
<if test="author != null">#{author},</if>
<if test="content != null">#{content}</if>
</trim>
</sql>
<insert id="addOneBlog" parameterType="Blog">
insert into blog(<include refid="blogColumns"/>)
values (<include refid="blogValues"/>)
</insert>
參考:
https://www.cnblogs.com/yuhuameng/p/10703931.html
https://blog.csdn.net/c851204293/article/details/93623200
