mybatis的一个小技巧与坑 获取数据库刚插入的主键id

本文介绍了在开发医院系统时,如何有效解决自增主键的门诊号格式化问题,避免资源浪费和并发bug。同时,针对状态字段的判断问题,提出了合理的解决方案,确保数据库操作的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在公司开发一个医院系统时,遇到这样两个问题:

第一个问题:

我的一张表主键是自增长,主键字段是病人id,还有一个字段是门诊号,门诊号需要获取主键的值,把值格式化成“00000000”这种八位数的格式。最开始想了一种方式:先把病人的其他信息存入表中,然后再读取id(此时通过比较,读取最大的那个id,也就是最近插入的一个),通过id来格式化门诊号,这样做的弊端有两个,一个是频繁的读取和插入,消耗资源,另一个是如果遇到并发的情况会出现bug(如果在相差很短的时间内生成两个挂号信息,由于时间相差很短,在取id值的时候有可能两次都取了同一个值,会导致一个门诊号分配给多人)。

基于两种情况的考虑,放弃了这种方式,后来又找到了另外一种简单的 解决方法,如图:

文档解释如下:

useGeneratedKeys (insert and update only) This tells MyBatis to use the JDBC getGeneratedKeys method to retrieve keys generated internally by the database (e.g.auto increment fields in RDBMS like MySQL or SQL Server). Default: false 
(( 仅 对 insert 和update有 用 ) 这 会 告 诉 MyBatis 使 用 JDBC 的 getGeneratedKeys 方法来取出由数据(比如:像 MySQL 和 SQL Server 这样的数据库管理系统的自动递增字段)内部生成的主键。默认值:false。) 

也就是说写了 useGeneratedKeys="true" 等于true即说明插入数据之后 可以立马使用自增的主键

keyProperty="patientId"  这个属性意思是把自增的主键赋值到patientId属性上,patientId代表的是实体类的属性,而不是数据库字段。

 

第二个问题:

我在数据库表中有有一个category_state字段用于判断挂号的是门诊还是住院,表中是int类型,由于这种基本的增删查改代码都是直接生成的,在mapper层有这样一个判断

如果categoryState!='' ,这里的categoryState是int型和空字符比较,我的状态值,一个是1,一个是0,然后在mabatis中0代表空字符,所以当我从前台传0过来时,直接判断这句话不参与添加到数据库,导致数据库中没有值而出错。

修改方案:1.把categoryState!=' '去掉

                2.状态传非0的数

               3.  数据库中把字段改为char,而不是用int

今天就写到这里,希望通过今天写这个博客,记录自己的一些错误,以后不会继续出现这样的问题。

 

2020/11/11更新:

这里更新另外一种方法,通过mysql的函数:SELECT LAST_INSERT_ID() 该函数是事物隔离的,所以就算是在高并发情况下也是可以用的。

具体用法入下图片:在insert语句中添加selectKey标签 该标签中使用SELECT LAST_INSERT_ID()函数,在标签上写好对应的属性即可。

 

 

代码:

<insert id="insert" parameterType="com.taotao.pojo.TbContentCategory" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Fri Jul 03 16:53:43 CST 2020.
    -->
    
      <!--selectKey  会将 SELECT LAST_INSERT_ID()的结果放入到传入的model的主键里面,  
        keyProperty 对应的model中的主键的属性名,这里是 user 中的id,因为它跟数据库的主键对应  
        order AFTER 表示 SELECT LAST_INSERT_ID() 在insert执行之后执行,多用与自增主键,  
              BEFORE 表示 SELECT LAST_INSERT_ID() 在insert执行之前执行,这样的话就拿不到主键了,  
                    这种适合那种主键不是自增的类型  
        resultType 主键类型 -->  
        
    <selectKey keyProperty="id" resultType="long" order="AFTER">
          SELECT LAST_INSERT_ID()
      </selectKey>
      
    insert into tb_content_category (id, parent_id, name, 
      status, sort_order, is_parent, 
      created, updated)
    values (#{id,jdbcType=BIGINT}, #{parentId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, 
      #{status,jdbcType=INTEGER}, #{sortOrder,jdbcType=INTEGER}, #{isParent,jdbcType=BIT}, 
      #{created,jdbcType=TIMESTAMP}, #{updated,jdbcType=TIMESTAMP})
  </insert>

 

然后在service实现类里面调用insert,此时在pojo对象contentCategory 中就已经有这个主键了。

 

 

两者的区别:

下面参考原文:https://blog.youkuaiyun.com/poppyCL/article/details/103347385

数据库本身具备主键自动增长的功能,才能使用useGeneratedKeys

oracle不支持true

当数据库不支持useGeneratedKeys=“true” ,则使用selectKey,例如oracle

<insert id="insert" useGeneratedKeys="true" keyProperty="idColName">
	<selectKey keyColumn="colName" keyProperty="colParamName" order="AFTER" resultType="Long">
		select currval('seq_name') from dual
	</selectKey>
    insert into tableName (colName) values (#{colVal,jdbcType=VARCHAR})
</insert>

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值