今天在公司开发一个医院系统时,遇到这样两个问题:
第一个问题:
我的一张表主键是自增长,主键字段是病人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>