简单介绍:
在某些时候,我们在插入完成一条语句之后,我们会想要返回之前插入的这条语句的主键列的数据,进行下一步的展示或者修改,我们就可以使用MyBatis的主键回写功能,帮助我们获取插入成功的一条数据的主键列。不同的数据库获取主键列的方式不同,主要针对两种情况:一种是主键支持自增的情况,一种是主键不支持自增的情况。我们会针对这两种情况分别进行说明。
前期准备:
在数据库方面,我们需要准备一个数据库,并在里面提前存放一些数据:
注意这里我们并没有设置主键,我们先演示没有主键或主键不支持自增的时候的情况,之后再添加主键演示当支持主键自增时候的情况。然后就是MyBatis环境的基本准备,如果之前有一个可以运行的MyBatis的基础环境这一步就可以省略了。
实现原理:
如果这个表支持主键自增的情况,在我们使用<insert>进行插入的时候,可以使用几个特殊的属性:
keyProperty:这个属性用来设置返回的主键复制给POJO实体类的那一个属性。
keyColumn:这个属性用来设置第几列是主键,当主键不是数据表中的第一列的时候需要设置。
useGeneratedKeys:该属性会使MyBatis调用JDBC的getGeneratedKeys()方法来获取由数据库内部生产的主键,比如MySQL中的自动递增的字段,默认值使false。说人话就是MySQL支持逐渐自增,也就是说如果这个表里有一个列自增了,那么这个自增的列就是主键。因为在MySQL中只有主键是支持自增的,其他的列不会自增,所以MyBatis就会捕捉到这个现象,并将自增的数据返回到我们的POJO实体类中,这样就可以获取到这个自增的主键列。
但是当这个表中的主键不支持自增的时候,就需要使用特殊的规则获取我们插入的主键,或者我们自定义规则插入一个主键然后获取,这时候就需要我们的另一个标签:selectKey
这个标签用来配置我们的主键规则,因为在有些时候,我们不会插入主键,但是主键是必须的,所以我们会设定一个规则来帮助我们在没有主键自增长的时候还能自动插入主键:
这个标签有几个常用的属性:
keyProperty,resultType,order,statementType。其中其他几个属性的作用和上面的一样,order属性的值有两个:BAFORE和AFTER。BEFORE表示在执行插入语句之前先执行selectKey中配置的SQL语句,一般用于无法手动插入主键的时候使用。AFTER表示在插入语句之后再执行selectKey中配置的SQL语句,一般用于手动插入主键时使用。
1.当数据库的主键不支持自动增长或者主键没有设置自动增长的时候:
代码实现:
我们首先来看当不支持主键自增的时候我们如何使用Java代码帮助我们自动插入主键:
SQL语句映射文件:
<!-- 测试主键回写-->
<insert id="insertAuto" parameterType="student">
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
# 设置自动添加主键的规则,表示当主键列的最大值为空,表示这是第一条数据的时候,返回1,如果这条主键列最大的值不是null,则返回最大的值再加一
# 使用这种方法也可以达到主键自增的效果
select if(max(id) is null ,1,max(id) + 1) as idNum from student;
</selectKey>
insert into student values (#{id},#{name},#{password});
</insert>
接口映射文件:
package Mappers;
import com.mybatis.POJO.student;
import com.mybatis.POJO.user;
import java.util.List;
public interface select {
public student selectOne(int i);
public List<student> selectAll();
public student selectName();
public void insertInto(student s);
public int deleteOne(int i);
public void insertAuto(student s);
}
测试类:
package Mappers;
import com.mybatis.POJO.Tools.createSqlSession;
import com.mybatis.POJO.student;
import org.apache.ibatis.session.SqlSession;
public class TestInsertAuto {
select mapper = null;
SqlSession session = null;
@org.junit.Test
public void insertNotAuto(){
// 使用工具类获取连接
mapper = new createSqlSession().createMapper();
// 测试接口中映射的方法
// 创建插入表中的对应的POJO类的对象
// 注意我们并不设置主键列也就是id的值,主要是为了查看能否达到自动填充并增加的效果
student s = new student();
s.setName("赵六");
s.setPassword("1234556");
mapper.insertAuto(s);
// 遍历数据库中的数据
for (student student : mapper.selectAll()) {
System.out.println(student);
}
// 然后我们再获取一次看能不能获取的对象的id的值
System.out.println("插入的数据的id值是:"+s.getId());
}
}
运行结果:
可以看到,在我们没有设置id的值的时候,我们依然完成了主键的自增和获取,这就说明我们之前的配置是正确的。
注意点:
整个的运行流程是当我们插入一条数据的时候,因为我们selectKey的order属性配置的是BEFORE,所以我们首先会执行selectKey中的语句,然后他会判断我们数据表的主键列是否有数据,如果有数据,则获取最大的数据加一得到一个新的数据。这个过程就是我们在selectKey中配置的SQL语句来帮我们完成的。然后selectKey的另外两个属性,keyProperty的值表示将得到的数据插入到POJO实体类的哪一个属性中,resultType的值表示这个值的类型。然后执行insert标签中的SQL语句,最后将数据插入完成之后,会将我们刚才设置的值返回给student类,我们就可以通过getId的方法得到我们刚才自动生成的值。
需要注意的是我们要明确selectKey中配置的SQL语句是帮助我们自动生成主键的值的,这个值会被复制给POJO类的id属性。然后就是SQL语句中的if语句的使用方法。
1.当数据库的主键支持自动增长并且设置了自动增长的时候:
实现原理:
当主键设置了自动增长的时候,就不需要我们手动填充主键,MyBatis会自动的帮我们去检测某一列的值是否自动增加了,如果在我们没有填充的情况下自动填充了,那么这个列就是主键,MyBatis会自动帮我们把填充后的值获取到,我们只需要正确的配置即可。
代码实现:
SQL映射文件:
<!-- 当支持主键自增时候的主键回写-->
<insert id="insertAuto" parameterType="student" keyProperty="id" useGeneratedKeys="true">
insert into student values (#{id},#{name},#{password});
</insert>
接口文件:
package Mappers;
import com.mybatis.POJO.student;
import com.mybatis.POJO.user;
import java.util.List;
public interface select {
public student selectOne(int i);
public List<student> selectAll();
public student selectName();
public void insertInto(student s);
public int deleteOne(int i);
public void insertNotAuto(student s);
public void insertIntoAuto(student s);
}
测试类:
@org.junit.Test
public void insertIntoAuto(){
// 使用工具类获取连接
mapper = new createSqlSession().createMapper();
// 测试接口中映射的方法,这次测试的是带有主键自增的数据表
student s = new student();
s.setName("赵六");
s.setPassword("1234556");
mapper.insertIntoAuto(s);
// 遍历数据库中的数据
for (student student : mapper.selectAll()) {
System.out.println(student);
}
// 然后我们再获取一次看能不能获取的对象的id的值
System.out.println("插入的数据的id值是:"+s.getId());
}
运行结果:
可以看到,在我们没有设置id主键值的时候,自动填充主键值的操作是由数据库完成的,而MyBatis负责监控那一列的值自动填充了,并返回这一列的值让我们可以通过对象查询到
注意点:
唯一的注意点就是当我们需要区分我们具体是操作何种情况,合理的使用这两种方法返回的结果