在数据库(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。
- 根据需求创建表
- 根据表创建实体类
- 创建Mapper接口(编写各种增删改查接口方法)
- 创建Mapper.xml(编写各种增删改查SQL语句)
- 结合Junit单元测试框架测试
由于是介绍MyBatis中的主键生成策略,所以只需要编写新增接口方法,以及编写新增SQL语句。
SysUserMapper接口
public interface SysUserMapper {
/**
* 新增用户
* @param user
*/
int insertSysUser(SysUser user);
}
SysUserMapper.xml
mapper标签的namespace属性值需要写上面接口的全限定路径,这样MyBatis才能将Mapper接口绑定Mapper.xml。
哈哈,这里先给出Mapper.xml模板代码,具体的SQL语句在下面再给出。
接下来就是重点了,MyBatis中的主键生成策略有几种方式,我们将一 一介绍。
1.使用JDBC方式返回主键自增的值
这种方式只适用支持主键自增的数据库,比如:MySQL,SQL Server。如果数据库不支持主键自增,那么这种方式就不适用了,比如:Oracle
insert标签是让我们编写新增SQL语句。类似的还有select标签、update标签和delete标签。
下图是insert标签中的属性,红色框中是比较常用的属性。
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}
);
在上面代码中,新增数据的时候没有为主键id设置值,而是设置了一些属性,就是这些属性能帮我们自动获取主键的值(主键自增长)。
下面讲解这些属性的作用:
- insert标签的id属性就是Mapper接口方法,上面通过namespace绑定接口,这里通过id绑定接口方法。
- 上面我们将
useGeneratedKeys属性
设置为true, MyBatis会使用JDBC getGeneratedKeys方法来取出由数据库内部生成的主键。 - 获得主键值后将其赋值给
keyProperty属性
配置的id属性(实体类中的属性)。当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置 keyColumn 属性按顺序指定数据库的列,这里列的值会和 keyProperty 配置的属性一一对应。
2.使用selectKey返回主键的值
有些数据库(比如:Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给主键id ,再将数据插入数据库。对于这种情况 ,我们使用<selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。
这里分别演示MySQL和Oracle两个数据库在这种方式下的主键生成方式。
MySQL
上面接口方法不变,只是改变insert标签代码。我们可以看到useGeneratedKeys属性和keyProperty属性不用设置了。改为添加selectKey标签
。
- selectKey标签的keyColumn、keyProperty和上面useGeneratedKeys的用法含义相同。
- resultType属性用于设置返回值类型。
- order属性的设置和使用的数据库有关。MySQL数据库中,order属性设置的值是AFTER,因为当前记录的主键值在insert语句执行成功后才能获取。
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}
);
SELECT LAST_INSERT_ID ()
Oracle
我们可以看到,在Oracle数据库中,order属性设置为BEFORE,这是因为Oracle中需要先从序列获取值,然后将值作为主键插入到数据库中。
Oracle方式的insert语句中明确写出了id列和值#{id},因为执行selectKey中的语句后id就有值了,我们需要把这个序列值作为主键值插入到数据库中,所以必须指定id列,如果不指定这一列,数据库就会因为主键不能为空而抛出异常。
selectKey元素放置的位置不会影响selectKey中的方法在insert前面或者后面执行的顺序,影响执行顺序的是order属性。
SELECT SEQ_ID.nextval from dual
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}
);
假如主键是varchar类型,那么对应Java就是String类型,这个时候就不需要使用MyBatis的主键生成策略。我们在新增数据时,直接为主键赋值即可,一般是使用java.util.UUID生成32位位不规则不重复的字符串来充当主键。
这样我们就介绍了我们在使用MyBatis时,对主键的处理方式。大家觉得的话,不妨来个。