MyBatis中的主键生成策略

在数据库(MySQL,Oracle…)中,我们都会为每张表设置主键。主键也是一个字段,只不过为其赋予非空唯一的特性。
主键的作用是保证一张表中的数据唯一性。

这次我们使用用户表介绍在使用MyBatis向数据库表新增数据(一条或者多条)时,主键该怎么设置?
在Java项目中,主键对应的Java类型一般是Integer,Long或者String。

建表及插值SQL语句

CREATE TABLE `sys_user` (
  `id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` varchar(255) DEFAULT NULL COMMENT '用户名',
  `user_password` varchar(255) DEFAULT NULL COMMENT '密码',
  `user_email` varchar(255) COMMENT '邮箱',
  `user_info` text COMMENT '简介',
  `head_img` blob COMMENT '头像',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

-- 这里我们先手动插入6条数据,default表示为创建该表时每个字段的默认值,now()获取当前时间
INSERT INTO `sys_user` VALUES (DEFAULT, 'admin', 'admin', default, '管理员', "", NOW());
INSERT INTO `sys_user` VALUES (DEFAULT, 'xq', 'xq', default, '开发者', "", NOW());
INSERT INTO `sys_user` VALUES (DEFAULT, 'zs', 'zs', default, '开发者', "", NOW());
INSERT INTO `sys_user` VALUES (DEFAULT, 'ls', 'ls', default, '运维人员', "", NOW());
INSERT INTO `sys_user` VALUES (DEFAULT, 'ww', 'ww', default, '运维人员', "", NOW());
INSERT INTO `sys_user` VALUES (DEFAULT, 'zl', 'zl', default, '运维人员', "", NOW());

用户实体类

创建用户表对应的实体类,我们可以使用MyBatis逆向工程生成或者MyBatis-Plus自动代码生成。

/**
 * 用户实体类
 */
@Data
public class SysUser{
     
	/**
	 * ID
	 */
	private Long id;
	/**
	 * 用户名
	 */
	private String userName;
	/**
	 * 密码
	 */
	private String userPassword;
	/**
	 * 邮箱
	 */
	private String userEmail;
	/**
	 * 简介
	 */
	private String userInfo;
	/**
	 * 头像
	 */
	private byte[] headImg;
	/**
	 * 创建时间
	 */
	private Date createTime;
}

这里单独使用MyBatis,没有结合其他框架来使用。简单介绍我们在开发中如何使用MyBatis。

  1. 根据需求创建表
  2. 根据表创建实体类
  3. 创建Mapper接口(编写各种增删改查接口方法)
  4. 创建Mapper.xml(编写各种增删改查SQL语句)
  5. 结合Junit单元测试框架测试

由于是介绍MyBatis中的主键生成策略,所以只需要编写新增接口方法,以及编写新增SQL语句。

SysUserMapper接口

public interface SysUserMapper {
     
    /**
     * 新增用户
     * @param user
     */
    int insertSysUser(SysUser user);
}

SysUserMapper.xml

mapper标签的namespace属性值需要写上面接口的全限定路径,这样MyBatis才能将Mapper接口绑定Mapper.xml。
哈哈,这里先给出Mapper.xml模板代码,具体的SQL语句在下面再给出。



<mapper namespace="cn.zwq.mybatis.mapper.SysUserMapper">
	

接下来就是重点了,MyBatis中的主键生成策略有几种方式,我们将一 一介绍。

1.使用JDBC方式返回主键自增的值

这种方式只适用支持主键自增的数据库,比如:MySQL,SQL Server。如果数据库不支持主键自增,那么这种方式就不适用了,比如:Oracle
insert标签是让我们编写新增SQL语句。类似的还有select标签、update标签和delete标签。
下图是insert标签中的属性,红色框中是比较常用的属性。
MyBatis中的主键生成策略_第1张图片

<insert id="insertSysUser" useGeneratedKeys="true" keyProperty="id" >
    insert into sys_user(user_name,user_password,user_email,user_info,head_img,create_time) 
    values (
	    #{
     userName},
	    #{
     userPassword},
	    default,
	    #{
     userInfo},
	    #{
     headImg,jdbcType=BLOB},
	    #{
     createTime,jdbcType=TIMESTAMP}
    );
</insert>

在上面代码中,新增数据的时候没有为主键id设置值,而是设置了一些属性,就是这些属性能帮我们自动获取主键的值(主键自增长)。
下面讲解这些属性的作用:

  1. insert标签的id属性就是Mapper接口方法,上面通过namespace绑定接口,这里通过id绑定接口方法。
  2. 上面我们将useGeneratedKeys属性设置为true, MyBatis会使用JDBC getGeneratedKeys方法来取出由数据库内部生成的主键。
  3. 获得主键值后将其赋值给keyProperty属性配置的id属性(实体类中的属性)。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置 keyColumn 属性按顺序指定数据库的列,这里列的值会和 keyProperty 配置的属性一一对应。

2.使用selectKey返回主键的值

有些数据库(比如:Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给主键id ,再将数据插入数据库。对于这种情况 ,我们使用<selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

这里分别演示MySQL和Oracle两个数据库在这种方式下的主键生成方式。

MySQL

上面接口方法不变,只是改变insert标签代码。我们可以看到useGeneratedKeys属性和keyProperty属性不用设置了。改为添加selectKey标签

  1. selectKey标签的keyColumn、keyProperty和上面useGeneratedKeys的用法含义相同。
  2. resultType属性用于设置返回值类型。
  3. order属性的设置和使用的数据库有关。MySQL数据库中,order属性设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取。
<insert id="insertSysUser">
    insert into sys_user(user_name,user_password,user_email,user_info,head_img,create_time)
    values (
        #{userName},
        #{userPassword},
        default,
        #{userInfo},
        #{headImg,jdbcType=BLOB},
        #{createTime,jdbcType=TIMESTAMP}
    );
    <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
        SELECT LAST_INSERT_ID ()
    selectKey>
insert>

Oracle

我们可以看到,在Oracle数据库中,order属性设置为BEFORE,这是因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中。

Oracle方式的insert语句中明确写出了id列和值#{id},因为执行selectKey中的语句后id就有值了,我们需要把这个序列值作为主键值插入到数据库中,所以必须指定id列,如果不指定这一列,数据库就会因为主键不能为空而抛出异常。

selectKey元素放置的位置不会影响selectKey中的方法在insert前面或者后面执行的顺序,影响执行顺序的是order属性。

<insert id="insertSysUser">
    <selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
        SELECT SEQ_ID.nextval from dual
    selectKey>
    insert into sys_user(id,user_name,user_password,user_email,user_info,head_img,create_time)
    values (
        #{id},
        #{userName},
        #{userPassword},
        default,
        #{userInfo},
        #{headImg,jdbcType=BLOB},
        #{createTime,jdbcType=TIMESTAMP}
    );
insert>

假如主键是varchar类型,那么对应Java就是String类型,这个时候就不需要使用MyBatis的主键生成策略。我们在新增数据时,直接为主键赋值即可,一般是使用java.util.UUID生成32位位不规则不重复的字符串来充当主键。

这样我们就介绍了我们在使用MyBatis时,对主键的处理方式。大家觉得的话,不妨来个。

你可能感兴趣的:(MyBatis)