Mybatis---主键回填 (*^▽^*)


业务场景

主键回填听上去很高级,不妨用一个业务场景来引入概念吧。
在增加操作中,如果设置了主键id是自增的,那么插入数据时id的值一般写null,因为存入数据库时id都会自动+1,看似操作没毛病,非常完美。
但是在购物交易的添加模块这可不兴这样,细想一下在上网买东西时,用户付完钱之后一般都会返回一个订单编号,其实这个订单编号在数据库中就是主键,但是因为在插入数据时id的值写了null,所以订单编号也为null,也就是说返回不了订单编号的数据。
那还是老老实实挨个挨个在插入数据的时候写id呗,如果是批量添加数据呢,面对千万级的插入数据,这显然是不科学滴~
那要不先插入数据再进行查询操作吧,保证能查到数据,emm…有点麻烦,可以但没必要,有需求就有解决方案,开发者早就想到了,我们只要坐享其成就行啦~

主键回填就是用来干这个的,讲完这个业务场景在来思考一下这个专有名词,“主键”+“回填”,谜底就在谜面上,作用就是把插入数据的null主键给填回去,完美实现插入数据为null主键的同时可以查询到主键信息的需求~~


主键回填是什么?

主键回填一般用于增加操作中,把插入数据时插入为null的主键id数据填回去,存入到java对象和主键对应的属性中(数据库主键字段为id则回填的是实体类的id属性),实现添加+查询主键一步到位。


主键回填的用法

有两种,一种是自增主键,一种是非自增主键。

1、自增主键(int整数类型)

最常见的一种,平常我们的主键都是设置为自增,自增为整数类型的,每添加一个数据到数据库中,数据库就会根据自增规则给主键+1

完成主键回填的过程中,映射文件使用到的标签、函数:
1、last_insert_id():mysql 中的函数,作用是获取最近一次插入语句(insert)的自增字段值,即获取最后插入的自增id值

select last_insert_id():表示查询最后一次插入语句(insert)的自增字段值

2、< selectKey > sql语句 < /selectKey >:选择主键标签,嵌套在插入语句中,内部属性如下
(1)order:sql语句在插入语句中的执行顺序,order="AFTER"在这里表示先执行完插入语句后再执行select last_insert_id()语句,因为测试类中插入id属性为null,如果不先执行插入语句,select last_insert_id()语句将查询不到最后的插入语句。

(2)resultType:sql语句执行后的结果类型,resultType="int"在这里表示结果类型为整数类型。

(3)keyProperty:sql语句执行后回填到哪个属性,keyProperty="id"在这里表示通过执行select last_insert_id()把查询到的id值回填到测试类中插入数据的那个空的id属性值。

<selectKey order="AFTER" resultType="int" keyProperty="id">
          select last_insert_id()
</selectKey>

话不多说,上代码!!!

使用步骤

1、在mybatis_shine数据库中新建一个t_user表,字段如下

 create database mybatis_shine default charset =utf8;
 create table t_user(
   id int primary key auto_increment,
   username varchar(50),
   password varchar(50),
   gender tinyint,
   regist_time datetime
 )default charset =utf8;

2、新建实体类User类

public class User {
    private Integer id;
    private String username;
    private String password;
    private Boolean gender;
    private Date registTime;

    //构造函数
    public User() {
    }

    public User(Integer id, String username, String password, Boolean gender, Date registTime) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.registTime = registTime;
    }

    //get、set方法

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Boolean getGender() {
        return gender;
    }

    public void setGender(Boolean gender) {
        this.gender = gender;
    }

    public Date getRegistTime() {
        return registTime;
    }

    public void setRegistTime(Date registTime) {
        this.registTime = registTime;
    }

    //重写toString()方法,方便测试打印

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender=" + gender +
                ", registTime=" + registTime +
                '}';
    }
}

3、新建UserDao接口

public interface UserDao {
 //添加操作接口
    Integer insertUser(User user);
}

4、新建UserMapper.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="com.xxxx.mybatis.dao.UserDao">


  <insert id="insertUser" parameterType="User">
  
      <selectKey order="AFTER" resultType="int" keyProperty="id">
          select last_insert_id()
      </selectKey>

        insert into t_user
        values (#{id} , #{username} , #{password} , #{gender} , #{registTime})

    </insert>

5、测试类

public class TestMyBatis {
     public static void main(String[] args) throws Exception{
             //mybatis
         //1、加载配置文件,获得读取配置文件的流对象
         InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

         //2、构建 SqlSessionFactory,SqlSession连接对象的工厂
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

         //3、通过SqlSessionFactory工厂获得连接对象sqlSession,
         SqlSession sqlSession = sqlSessionFactory.openSession();

         //4、通过连接对象sqlSession获得dao对应实现类的对象
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         
          //5、调用UserDao接口中的insertUser方法并打印,添加时主键为null
         User user = new User(null,"小宏","520",true,new Date());
         mapper.insertUser(user);
         System.out.println(user);
         
          //6、提交事务,增删改需要
         sqlSession.commit();
         sqlSession.rollback();
         
         //7、释放资源
         sqlSession.close();


6、检验成果
让我们康康数据库,yeah~插入数据成功了!!!
数据库
----------分割线------------

再康康打印结果,可以看到先执行插入语句再执行select last_insert_id()语句,插入时主键id为null,但是返回结果时返回了id的数据,amazing╰( ̄▽ ̄)╭
打印结果


2、非自增主键(UUID生成varchar字符串类型)

首先说一下为什么会有非自增主键吧,我们都知道自增主键唯一且自增,但是也会有亿点点小弊端的,比如说,自增主键只能保证在该系统的主键唯一,当该系统需要和新系统集成,双向同步导入数据时,很难保证原系统的id不发生主键冲突吧,那怎么办呢?不用担心,我们可以用mysql的UUID函数生成一个有效长度为32位字符串类型的全球唯一的识别码,先科普一下什么叫UUID吧。
UUID:是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。
优点:出现数据拆分,合并存储数据的时候,能达到全局的唯一性

完成主键回填的过程中,映射文件使用到的标签、函数:
1、uuid():mysql的一个函数,生成一个有效长度为32位字符串类型的全球唯一的识别码,为什么说是有效长度32位,因为它的总长度为36位,其中有4位是“-”,以“-”为区分分为五组数组,前三组数字从时间戳中生成,第四组数字暂时保持时间戳的唯一性,第五组数字是一个 IEEE 802 节点标点值,保证空间唯一。使用 UUID() 函数,可以生成时间、空间上都独一无二的值。

2、replace(uuid(),’-’,’’):可以消除UUID值的“-”,采用替代的方式,将一个空值的“”替代了“-”,从而生成总长度为32位,有效长度也为32位的UUID值。

select replace(uuid(),’-’,’’):查询生成32位字符串类型的UUID值

3、< selectKey > sql语句 < /selectKey >:选择主键标签,嵌套在插入语句中,内部属性如下

(1)order:sql语句在插入语句中的执行顺序,order="BEFORE"在这里表示先执行select replace(uuid(),’-’,’’)语句后再执行插入语句,因为非自增主键id为null时无法执行插入语句,测试类的id属性不能插入null值,必须先生成uuid主键才能进行插入语句。

(2)resultType:sql语句执行后的结果类型,resultType="string"在这里表示结果类型为字符串类型。

(3)keyProperty:sql语句执行后回填到哪个属性,keyProperty="id"在这里表示通过执行select replace(uuid(),’-’,’’)生成id值回填到测试类中插入数据的那个空的id属性值。

 <!--生成带“-”的UUID值,总长度36位,有效长度32位-->
<selectKey order="BEFORE" resultType="string" keyProperty="id">
            select uuid()
</selectKey>

 <!--把uuid的值的“-”替换成“”,总长度32位,有效长度32位-->
<selectKey order="BEFORE" resultType="string" keyProperty="id">
            select replace(uuid(),'-','')
</selectKey>

多说无益,直接上代码!!!

使用步骤

1、在mybatis_shine数据库中新建一个t_student表,字段如下

 create table t_student(
                         id varchar(32) primary key,
                         name varchar(50),
                         gender tinyint
 )default charset =utf8;

2、新建实体类Student类

public class Student {
    private String id;
    private String name;
    private Boolean gender;

    public Student() {
    }

    public Student(String id, String name, Boolean gender) {
        this.id = id;
        this.name = name;
        this.gender = gender;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Boolean getGender() {
        return gender;
    }

    public void setGender(Boolean gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                '}';
    }
}

3、新建StudentDao接口

public interface StudentDao {
    Integer insertStudent(Student student);
}

4、新建StudentMapper.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="com.xxxx.mybatis.dao.StudentDao">

    <insert id="insertStudent" parameterType="Student">

        <selectKey order="BEFORE" resultType="string" keyProperty="id">
            select replace(uuid(),'-','')
        </selectKey>
        insert into t_student
        values (#{id} , #{name} , #{gender} )
    </insert>
</mapper>

5、测试类

public class TestMyBatis {
     public static void main(String[] args) throws Exception{
             //mybatis
         //1、加载配置文件,获得读取配置文件的流对象
         InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

         //2、构建 SqlSessionFactory,SqlSession连接对象的工厂
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

         //3、通过SqlSessionFactory工厂获得连接对象sqlSession,
         SqlSession sqlSession = sqlSessionFactory.openSession();

         //4、通过连接对象sqlSession获得dao对应实现类的对象
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         
          //5、调用StudentDao接口中的insertStudent方法并打印
         Student student = new Student(null,"小伶",false);
         studentmapper.insertStudent(student);
         System.out.println(student);
         
          //6、提交事务,增删改需要
         sqlSession.commit();
         sqlSession.rollback();
         
         //7、释放资源
         sqlSession.close();

6、检验成果

先康康数据库,yeah yeah~插入数据又成功了!!!
数据库
最后一步,康康打印结果,先执行select replace(uuid(),’-’,’’)语句,再执行插入语句,数据全部都返回成功!!! \( ̄︶ ̄)/
打印结果


第一次记录,完结撒花✿✿ヽ(°▽°)ノ✿

  • 20
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lynn Lu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值