2020/04/18
关于mapper中<insert>标签
其属性大部分与<select>一致,但也有独特的属性:
①keyProperty:该属性的作用是将插入或更新操作时的返回值赋给 PO 类的某个属性,通常会设置为主键对应的属性。如果是联合主键,可以将多个值用逗号隔开。
②keyColumn:该属性用于设置第几列是主键,当主键列不是表中的第 1 列时需要设置。如果是联合主键,可以将多个值用逗号隔开。
③useGeneratedKeys:该属性将使 MyBatis 使用 JDBC 的 getGeneratedKeys()方法获取由数据库内部产生的主键,例如 MySQL、SQL Server 等自动递增的字段,其默认值为 false。
使用场景为:
如果一个mapper中的insert的sql语句中并没有明显指明主键的值,但是此时也要运行不出错,则需要在<insert>标签中加上:
keyProperty="id" userGeneratedKeys="true"
此时则指明该语句所操作的数据库表的主键名为id,同时该主键是自动递增的(需要在建表的时候同时设置,如果该属性仅仅是主键而非自动递增,则程序运行时会报错。)。
这个时候可以不用在对应的参数user类中显示的setId的值(否则需要指明)。
------
对应于很多数据库表的主键并不会设置自动递增这个属性的问题,mybatis增加了<selectKey>这个标签,此标签属于<insert>标签的子标签
其属性为:keyProperty,resultType,以及order三个属性(可能还有更多,待学习了解)
其中,keyProperty属性指明所操作数据库表的主键值,与insert的keyproperty属性一样。此时该属性指明的主键可以不为自增。
resultType属性指明<selectkey>标签中语句执行后的返回值的类型。
Order属性指明<selectkey>标签中的语句是在sql语句执行之前执行还是之后执行。如果其值为BEFORE,则表示<selectkey>标签中的语句在sql操作执行之前执行;若值为AFTER,则在sql之后执行。
举例:
<insert id="insertUser" parameterType="com.po.MyUser">
<!-- 先使用selectKey元素定义主键,然后再定义SQL语句 -->
<selectKey keyProperty="uid" resultType="Integer" order="BEFORE">
select if(max(uid) is null,1,max(uid)+1) as newUid from user)
</selectKey>
insert into user (uid,uname,usex) values(#{uid},#{uname},#{usex})
</insert>
该<insert>标签所映射的接口代理方法在执行时,
首先会执行<selectkey>标签中的语句:从数据库表user中查询主键uid的最大值是否存在,若存在则返回max(uid)+1,否则返回1。
然后会执行下面的sql语句,返回sql语句影响的行数。
可以看出该sql语句中也是显示指定了主键uid的(与未使用<selectkey>标签时所固定的自增主键sql操作有所不同,自增时并不需要显示指明)。
通过三种<isnert>方法的测试可以得出结论:
//三种<insert>方法:
<insert id="insertUser1" parameterType="com.mybatis.po.User">
insert into myuser(id,user_name,password,sex,mobile,tel,email,note) values(#{id},#{userName},#{password},0,#{mobile},#{tel},#{email},#{note})
</insert>
<insert id="insertUser2" parameterType="com.mybatis.po.User" keyProperty="id" useGeneratedKeys="true">
insert into myuser(user_name,password,sex,mobile,tel,email,note) values(#{userName},#{password},0,#{mobile},#{tel},#{email},#{note})
</insert>
<insert id="insertUser3" parameterType="com.mybatis.po.User">
<selectKey keyProperty="id" resultType="Integer" order="BEFORE">
select if(max(id) is null,1,max(id)+1) as newUid from myuser
</selectKey>
insert into myuser(id,user_name,password,sex,mobile,tel,email,note) values(#{id},#{userName},#{password},0,#{mobile},#{tel},#{email},#{note})
</insert>
①在第一种<insert>方法中,如果传入的参数User类(举例)中与操作的数据库表中对应的主属性(此例中为id属性)未setId(),即未初始化该属性值,则在执行时会报错。
②在第二种方法中,可以不用在传入的user中初始化id的值,但是数据库表中的id属性必须为自动递增,否则还是会报错。
③第三种方法是最复杂但也最适宜最实用的方法,其通过<selectkey>标签中的sql操作来查询max(id)的值,可能的执行情况就是将查询到的max(id)值赋值给传入的user类中对应的id属性,从而消除第二种方法中的“必须为自动递增”的限制(但是如果<selectkey>标签中的sql语句所返回的值是后面的<insert>标签的sql语句所需要的(如未显示指定的id属性),则order属性的值必须为“before”,否则将报错)。
第三种方法通过<selectkey>标签的keyproperty属性来实现指定主键的功能,同时结合order属性来抵消第一种与第二种方法的弊端。