美文网首页
2020-03-03-MyBatis插入记录id增长同时获得方法

2020-03-03-MyBatis插入记录id增长同时获得方法

作者: 华清居士 | 来源:发表于2020-03-03 15:54 被阅读0次

    MyBatis insert 声明使用

    1、一般的insert

    //一般的insert,会返回成功插入的条数

    <insert id="insertEntity" parameterType="Entity">

    insert into.....

    </insert>

    2、使用生成的键值之 useGeneratedKeys=”true”

    <insert id="insertEntity" useGeneratedKeys="true"

        keyProperty="id" parameterType="Entity">

      insert into.....

    </insert>

    class Entity{

      private Long id;

      //other fields

    }

    keyProperty指定了需要生成的目标字段, jdbc生成键值的getGenereatedKeys方法会用keyProperty的值。

    一般来说,都是主键ID自增, insert后会赋值Entity中的id字段。

    mapper生成器常命名这种方式的id 为 "insertSelective"

    3、自助生成键值之 selectKey

    对于不支持自动生成类型的数据库或可能不支持自动生成主键的JDBC,2中的getGenereatedKeys方法肯定不可用,自然 useGeneratedKeys=”true”就不起作用了

    \\官网提供的一个说是很傻的生成id的方式

    <insert id="insertEntity">

      <selectKey keyProperty="id" resultType="int" order="BEFORE">

        select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1

      </selectKey>

      insert into...

    </insert>

    keyProperty selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

    keyColumn 匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

    resultType 结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。

    order 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。

    statementType 与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。

    4、 不属于mybatis范畴, 全局一致性递增,并获得当前所递增的值

    //业务场景, 按访问序号抽奖

    4.1 记录插入递增

    如果是自增的字段,插入记录后返回的id值就是当前操作的全局id值。 这是借助了数据库的自增,实现全局同步递增。

    4.2 单记录,值++ ,值递增

    多线程,多点的状况下,递增操作肯定要保证同步的。

    简单的业务,不需借助redis,zookeeper等服务实现锁时,就尽量借用DB支持的方式实现同步。

    mysql的Innodb是行锁的, 所以update一条记录是同步的。

    当update之后,紧接着进行select操作,却不能保证获取到的是刚递增后的值(两条语句不是业务块, 非原子)。有解决办法吗?

    4.3 LAST_INSERT_ID()

    LAST_INSERT_ID() 能够很好的保留当前操作的现场数据。

    LAST_INSERT_ID()是存在于连接对象里的,可以对其进行存取。

    update gobal_table set value=LAST_INSERT_ID(value+1) where name='keyName';select LAST_INSERT_ID();

    只要保证这两条语句是同一个连接连续执行的即可。使用的连接池是没有问题的。

    mybatis里就可以写到mapper文件中的一个<select></select>中

    再者,加入初始化的value

    insert into global (name, value) values (#{keyName}, LAST_INSERT_ID(1)) ON DUPLICATE KEY UPDATE value=LAST_INSERT_ID(value+1) ; select LAST_INSERT_ID();

    虽然两条语句不会保证是原子的,但是select返回的是是前一条插入的value的值,这是由同一个连接保证的,不会被其他线程的其他数据库连接的操作所污染。

    验证: 可以借助java.util.concurrent.CountDownLatch 创建几百个线程进行测试。

    4.4 mysql 连接会话变量

    其实上边的LAST_INSERT_ID(),对应的就是一个连接的变量last_insert_id,可以通过SHOW VARIABLES看到

    上边的语句也可以替换成用用户变量定义的形式

    insert into global (name, value) values (#{keyName}, (@InsertedId:=1)) ON DUPLICATE KEY UPDATE value=@InsertedId:=value+1 ; select @InsertedId

    相关文章

      网友评论

          本文标题:2020-03-03-MyBatis插入记录id增长同时获得方法

          本文链接:https://www.haomeiwen.com/subject/jgjhlhtx.html