本篇文章针对前面没有讲到的XML映射配置文件做一个补充说明。
1. selectKey自动生成主键
对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis 有另外一种方法来生成主键。
这里有一个简单(也很傻)的示例,它可以生成一个随机 ID(不建议实际使用,这里只是为了展示 MyBatis 处理问题的灵活性和宽容度):
<insert id="insert">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
SELECT FLOOR(RAND()*10000) AS id
</selectKey>
INSERT INTO `user`(`id`,`name`, `phone`, `birthday`) VALUES (#{id}, #{u.name}, #{u.phone}, #{u.birthday})
</insert>
单元测试:
@Test
void insert() throws ParseException {
User user = new User();
user.setName("啊随");
user.setPhone("11111111111");
user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1996-07-18"));
userMapper.insert(user);
}
运行结果:
并不建议这样做,毕竟绝大多数数据库都有自增主键的功能,不需要更没必要自动生成一个随机数来当作id。这里只是演示一下selectKey标签还有这种用法。
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn | 返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
resultType | 结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。 |
order | 可以设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。 |
statementType | 和前面一样,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 类型的映射语句,分别代表 Statement, PreparedStatement 和 CallableStatement 类型。 |
2. 返回主键id
在实际应用中,常常需要返回insert语句的主键id。配置起来很简单,只需:
- 指定insert标签的useGeneratedKeys属性为true
- 指定insert标签的keyProperty属性所对应的实体类的属性名
- 指定insert标签的keyColumn属性所对应的数据表的字段名
<insert id="insertAndGetId" parameterType="com.yky.springboot.entities.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO `user`(`name`, `phone`, `birthday`) VALUES (#{u.name}, #{u.phone}, #{u.birthday})
</insert>
返回的主键id会直接注入到user对象中。
@Test
void insertAndGetId() throws ParseException {
User user = new User();
user.setName("id返回");
user.setPhone("11111111111");
user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1996-07-18"));
userMapper.insertAndGetId(user);
System.out.println(user.getId());
}
3. sql标签代码重用
可以使用sql标签将多个地方会用到的代码抽取出来。
<sql id="allColumn">
`id`, `name`, `phone`, `birthday`
</sql>
直接使用include标签进行引用
<select id="selectById" resultType="User" >
SELECT
<include refid="allColumn"></include>
FROM `user` WHERE id = #{id}
</select>
4. 占位符与字符串替换
前面我们用了很多次#{}占位符,默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。这时就需要用到${}了。
比如:
ORDER BY ${columnName}
那什么时候用 ${} 呢?当SQL语句中的表名/列名需要动态生成时,则需要用到 ${}。因为表名/列名需要直接替换进SQL语句,而不能经过转义。
在这里举一个使用字符串替换的例子:
映射接口:
/**
* 根据列名和改列所对应的值匹配
* @param columnName 列名
* @param value 值
* @return
*/
List<User> selectByColumn(@Param("columnName") String columnName,@Param("value") String value);
xml映射配置:
<select id="selectByColumn" resultType="User">
SELECT
<include refid="allColumn"></include>
FROM `user`
WHERE ${columnName} = #{value}
</select>
单元测试代码:
@Test
void selectByColumn() {
List<User> users = userMapper.selectByColumn("name", "小明");
System.out.println(users);
}
Mybatis不推荐我们这样做,因为这种用法会导致潜在的SQL注入攻击。如果非要这样用,推荐对输入的参数进行校验,以防止非法SQL语句被执行。