这里讨论是基于mysql数据库,其他数据库不是很熟悉。分成两种情况来分析,第一种是数据库生成的自增主键,第二种情况是基于<selectKey>指定生成主键,分别来看下。

1:自增主键

第一种方式是使用useGeneratedKeys + keyProperty组合的方式,其中useGeneratedKeys是告诉mybatis要使用自增生成的主键,keyProperty是告诉mybatis主键字段是哪个最终通过调用KeyGenerator#processAfter设置,如下:

<insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO person(name, pswd)
    VALUE (#{name}, #{pswd})
</insert>

这样保存完毕后,保存的实体中id属性就有值了。
第二种方式是通过<selectKey>来指定sql语句获取生成的主键ID最终通过调用KeyGenerator#processAfter方法设置,如下:

<insert id="insert" parameterType="Person">
    <selectKey keyProperty="id" resultType="long" order="AFTER">
        SELECT LAST_INSERT_ID()
    </selectKey>
        
    INSERT INTO person(name, pswd)
    VALUE (#{name}, #{pswd})
</insert>

这种方式可以认为是第一种方式的手动版本,但是不清楚这种方式会不会有并发问题,没测试过。

2:selectKey生成主键

这种方式通过selectKey标签设置以sql语句方式生成主键,且目前只支持通过执行一个sql语句来生成主键值如select UUID(),可能配置如下:

<insert id="insertByQueryParamter" parameterMap="myParameterMap">
    <selectKey keyProperty="id" keyColumn="id"
               resultType="java.lang.String" order="BEFORE">
        select uuid()
    </selectKey>
    INSERT INTO `test_selectkey`
            (`id`,
            `myname`,
            `myage`)
    VALUES (#{id},
            #{myname},
            #{myage})
</insert>

注意这里是order="BEFORE"因此最终会调用KeyGenerator#processBefore方法设置主键值,如果配置为order=after则通过调用KeyGenerator#processAfter方法设置主键值。关于selectKey的使用可以参考这篇文章,关于selectKey的原理可以参考这篇文章

3:实例

3.1:mapper 接口

package cn.saytime.mapper;
 
import cn.saytime.domain.User;
import java.util.List;
 
/**
 * @author L
 * @ClassName cn.saytime.mapper.UserMapper
 * @Description
 */
public interface UserMapper {
 
    /**
     * 保存用户,返回主键,形式1
     * @param user
     */
    int saveReturnPK1(User user);
 
    /**
     * 保存用户,返回主键,形式2
     * @param user
     */
    int saveReturnPK2(User user);
 
}

3.2:mapper xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.saytime.mapper.UserMapper" >
 
    <!-- 增,返回主键 形式1 -->
    <insert id="saveReturnPK1" parameterType="cn.saytime.domain.User" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `test`.`tb_user`(`username`, age) VALUES(#{username}, #{age})
    </insert>
 
    <!-- 增,返回主键 形式2 -->
    <insert id="saveReturnPK2" parameterType="cn.saytime.domain.User">
        <selectKey keyProperty="id" resultType="int" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO `test`.`tb_user`(`username`, age) VALUES(#{username}, #{age})
    </insert>
 
</mapper>

3.3:测试类

import cn.saytime.domain.User;
import cn.saytime.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
 
/**
 * Created by L on 2018/1/3.
 */
public class TestUserMapper {
 
    SqlSessionFactory sqlSessionFactory = null;
    SqlSession sqlSession = null;
    UserMapper userMapper = null;
 
    @Before
    public void before(){
        // mybatis 配置文件地址
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 加载配置文件,并构建sqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession对象
        sqlSession = sqlSessionFactory.openSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
    }
 
    @After
    public void after(){
        if(sqlSession != null){
            // 注意这里的commit,否则提交不成功
            sqlSession.commit();
            sqlSession.close();
        }
    }
 
    /**
     * 测试保存用户返回主键,注意返回的主键塞到了插入对象user的id中
     */
    @org.junit.Test
    public void testSaveReturnPK(){
        // 形式1
        User user1 = new User();
        user1.setUsername("李四");
        user1.setAge(18);
        int c1 = userMapper.saveReturnPK1(user1);
        System.out.println("新增用户李四,返回主键:" + user1.getId() + "  操作数量:" + c1);
 
        // 形式2
        User user2 = new User();
        user2.setUsername("王五");
        user2.setAge(19);
        int c2 = userMapper.saveReturnPK1(user2);
        System.out.println("新增用户王五,返回主键:" + user2.getId() + "  操作数量:" + c2);
    }
 
}

运行testSaveReturnPK输出信息如下:

新增用户李四,返回主键:3 操作数量:1
新增用户王五,返回主键:4 操作数量:1

注意这里UserMapper.saveResultPK返回的数字是操作数量,而不是主键,一定小心不要搞错!!!主键在User对象的ID属性里,会在KeyGenerator的processBefore或processAfter方法中进行设置。

参考文章列表

Mybatis(一):插入操作返回主键
mybatis面试之编程步骤
mybatis之通过KeyGenerator生成主键

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐