文章目录
1、唯一索引自增长
useGeneratedKeys=“true” keyProperty=“id” keyColumn=“id”
<insert useGeneratedKeys="true" keyProperty="id" keyColumn="id">
</insert>
useGeneratedKeys: 告诉Mybatis这个逐主键是否使用数据库的内置规则生成
keyProperty:指定id为主键字段
keyColumn:指定id为数据对应的字段
补充:数据库表需要设置该自增长字段的自增规则
正常使用方法如下:
<!-- 批量插入列表遇到名字重复的就跳过-->
<insert id="insertPerson" paramterType="list" useGeneratedKeys="true" keyProperty="idP" keyColumn="id_p">
INSERT INTO t_persons (LastName, FirstName, Address, City)
VALUES
<foreach collection="personList" item="item" index="index" separator=",">
(
#{item.lastName}, #{item.firstName}, #{address}, #{city}
)
</foreach>
</insert>
useGeneratedKeys的两个易踩的“坑”:
1.1 使用useGeneratedKeys的时候,如果在插入数据的同事又进行更新或跳过插入操作的话,会导致返回数据错位
如下代码:
<!-- 批量插入列表遇到名字重复的就跳过-->
<insert id="batchInsertPerson" parameterType="list" useGeneratedKeys="true" keyProperty="idP" keyColumn="id_p">
INSERT INTO t_persons (LastName, FirstName, Address, City)
VALUES
<foreach collection="personList" item="item" index="index" separator=",">
(
#{item.lastName}, #{item.firstName}, #{item.address}, #{item.city}
)
</foreach>
on conflict (LastName, FirstName) DO nothing;
</insert>
有可能的异常如下:
数据库表中已经有个wang five 了,批量插入数据([zhang、three]、[wang、five]、[li、four]),预期如下
id(生成的字段) FirstName LastName
2 zhang three
null wang five
3 li four
真实的返回对象如下:
id(生成的字段) FirstName LastName
2 zhang three
3 wang five
null li four
1.2 使用useGeneratedKeys批量更新时用多条sql进行拼接
如下错误代码:
<insert id="batchInsertPerson" parameterType="list" useGeneratedKeys="true" keyProperty="idP" keyColumn="id_p">
<foreach collection="personList" item="item" index="index" separator=";">
INSERT INTO t_persons (LastName, FirstName, Address, City)
VALUES
(
#{item.lastName}, #{item.firstName}, #{item.address}, #{item.city}
)
</foreach>
</insert>
如何又更新又插入并且还能返回唯一索引值?
方法也是有的,可以使用, 如下示例,不过这种不支持批量返回
<insert id="insertUpdatePerson" parameterType="com.dreamkite.pg.entity.Person">
<selectKey keyProperty='idP' resultType='java.lang.String' order='AFTER'>
select Id_P from t_persons
where LastName = #{lastName} and FirstName = #{firstName}
</selectKey>
with "temp" as (
update t_persons set Address = #{address}, City = #{city}
where LastName = #{lastName} and FirstName = #{firstName}
returning *
)
INSERT INTO t_persons (LastName, FirstName, Address, City)
select #{lastName}, #{firstName}, #{address}, #{city}
where (select count (*) from temp) = 0
</insert>
2、使用<![CDATA[ ]]>减少转义字符的使用
写的sql中有一些特殊的字符的话,在解析xml文件的时候会被转义,但我们不希望他被转义,所以我们要使用<![CDATA[ ]]>
来解决
应用场景:如果文本包含了很多的"<“字符 <=和”&"字符——就象程序代码一样,那么最好把他们都放到CDATA部件中
如下:
<select id="getId" parameterType="java.util.HashMap" resultMap="userInfo1">
<![CDATA[
SELECT * FROM t_persons WHERE 1=1 AND birthDay > #{startTime} AND birthDay <= #{endTime}
]]>
<if test="etidName!=''">
AND newsEdit=#{etidName}
</if>
</select>
相反,如果少量包含则可以使用对应的转义符号进行替代,如下
HTML 原始码 | 显示结果 |
---|---|
< | < |
> | > |
& | & |
" | " |
≤ | < = |
≥ | >= |
3、使用对象替代繁杂的入参
当mybatis对应的mapper操作的入参有多个时候,如下:
@Repository
public interface PersonDao {
void insertPerson(@Param("id") int id, @Param("lastName") String lastName, @Param("firstName") String firstName,
@Param("address") String address, @Param("city") String city);
}
以下有两种写法,可以大幅提高代码的可读性,如下:
1、使用一个对象将所有的入参都包起来, dao层代码可以这么写:
@Repository
public interface PersonDao {
void insert(Person person);
}
<insert id="insertPerson">
INSERT INTO t_persons (LastName, FirstName, Address, City)
select #{lastName}, #{firstName}, #{address}, #{city}
</insert>
2、当一个对象不能把所有的属性都包括起来,那也是可以的,还是用上面做例子
这里记得函数需要添加**@Param**
@Repository
public interface PersonDao {
void insert(@Param("name")PersonName personName, @Param("addr")PersonAddress personAddress);
}
<insert id="insertPerson">
INSERT INTO t_persons (LastName, FirstName, Address, City)
select #{name.lastName}, #{name.firstName}, #{addr.address}, #{addr.city}
</insert>
4、Java时间数据类型跟数据库如何对应
java数据类型 | 数据库日期 | 说明 |
---|---|---|
java.time.Date | Date | 日职:YYYY-MM-DD |
java.time.Time | Time[WITHOUT TIME ZONE] | 时间:HH-MM-ss |
java.time.Time | TIMESTAMP[WITHOUT TIME ZONE] | 日期时间: YYYY-MM-DD HH-MM-ss |
java.time.OffsetDateTime | TIMESTAMP WITHOUT TIME ZONE | 带时区的日期时间: YYYY-MM-DD HH-MM-ss |
补充:在提到时间戳的数据类型时,不得不提到还有一种时间间隔的类型interval, 不过这个在java原生的代码中没有对应的数据类型对应,所以针对这种我一般都是转换成字符串或者long类型
5、在mybatis如何进行字符串拼接
1、使用concat()拼接
<insert id="querySomePerson">
select * from t_persons where name like concat('%',#{name},'%')
</insert>
2、使用${}代替#{}
<insert id="querySomePerson">
select * from t_persons where name like '%${name}%'
</insert>
KaTeX parse error: Expected 'EOF', got '#' at position 4: {}跟#̲{}的差别是{}是直接替换的,有存在被黑客攻击的分享,使用该曾经需要做强校验
本博客使用的数据库:postgres
对应的代码也上传到github了, 可戳:https://github.com/junkaitongxue/LearnSpringBoot/tree/main/usePostgres/src/test/java/com/dreamkite/pg/dao/PersonDaoTest.java
(以上为DreamKite本人原创,转载请附上原文链接)