在数据库(MySQL,Oracle…)中,我们都会为每张表设置主键。主键也是一个字段,只不过为其赋予非空唯一
的特性。
主键的作用是保证一张表中的数据唯一性。
这次我们使用用户表
介绍在使用MyBatis向数据库表新增数据(一条或者多条)时,主键该怎么设置?
在Java项目中,主键对应的Java类型一般是Integer,Long或者String。
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。
由于是介绍MyBatis中的主键生成策略,所以只需要编写新增接口方法,以及编写新增SQL语句。
public interface SysUserMapper {
/**
* 新增用户
* @param user
*/
int insertSysUser(SysUser user);
}
mapper标签的namespace属性值需要写上面接口的全限定路径,这样MyBatis才能将Mapper接口绑定Mapper.xml。
哈哈,这里先给出Mapper.xml模板代码,具体的SQL语句在下面再给出。
<mapper namespace="cn.zwq.mybatis.mapper.SysUserMapper">
接下来就是重点了,MyBatis中的主键生成策略有几种方式,我们将一 一介绍。
这种方式只适用支持主键自增的数据库,比如:MySQL,SQL Server。如果数据库不支持主键自增,那么这种方式就不适用了,比如:Oracle
insert标签是让我们编写新增SQL语句。类似的还有select标签、update标签和delete标签。
下图是insert标签中的属性,红色框中是比较常用的属性。
<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设置值,而是设置了一些属性,就是这些属性能帮我们自动获取主键的值(主键自增长)。
下面讲解这些属性的作用:
useGeneratedKeys属性
设置为true, MyBatis会使用JDBC getGeneratedKeys方法来取出由数据库内部生成的主键。keyProperty属性
配置的id属性(实体类中的属性)。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置 keyColumn 属性按顺序指定数据库的列,这里列的值会和 keyProperty 配置的属性一一对应。有些数据库(比如:Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给主键id ,再将数据插入数据库。对于这种情况 ,我们使用<selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。
这里分别演示MySQL和Oracle两个数据库在这种方式下的主键生成方式。
上面接口方法不变,只是改变insert标签代码。我们可以看到useGeneratedKeys属性和keyProperty属性不用设置了。改为添加selectKey标签
。
<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数据库中,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时,对主键的处理方式。大家觉得的话,不妨来个。