Mybatis 笔记(万字长文)

  • 1. 判断字符串相等
  • 2. Mybatis-批量插入
  • 3.where 条件
  • 4. 循环获取 Map 中的 key 和 value
  • 5.mybatis property column
  • 6. 在 xml 中使用`><`等特殊符号
  • 7. 插入并更新
  • 8. MyBatis+MySQL 返回插入的主键ID
  • 9.MybatisPlus问题 xxxMapper 未找到Bean
  • 10. mybatis IndexOutOfBoundsException: Index: , Size:
  • 11.Mybatis中foreach优化
  • 12.Mybatis传入多个map参数
  • 13.MyBatis嵌套循环map
  • 14. MyBatis 嵌套循环 map 的高级用法


1. 判断字符串相等

mybatis 映射文件中,if 标签判断字符串相等
两种方式:因为 mybatis 映射文件,是使用的 ognl 表达式,所以在判断字符串 sex 变量是否是字符串 Y 的时候使用

<test="sex=='Y'.toString()">或者<test = 'sex== "Y"'>

将自己的 sql 改为:

<if test="companyId != null and companyId !='' ">
	<if test="companyFlag == '1'.toString() ">
		AND COMPANY_ID = `#{companyId,jdbcType=VARCHAR}` 
	</if>
	<if test="companyFlag == '0'.toString() ">
		AND COMPANY_ID != `#{companyId,jdbcType=VARCHAR}` 
	</if>
</if>

再次调用 sql,则条件正常可用了。

2. Mybatis-批量插入

参数 list 时,先判断是否为空,否则会报错

<if test='list != null and list.size()>0'>
    AND purchase_id IN (229, 159)
</if>

遍历

<!-- 批量插入生成的兑换码 -->
<insert id ="insertCodeBatch" parameterType="java.util.List" >
           insert into redeem_code
           (bach_id, code, type, facevalue,create_user,create_time)
           values
        <foreach collection ="list" item="reddemCode" index= "index" separator =",">
                (
`#{reddemCode.batchId}, #{reddemCode.code}` ,
`#{reddemCode.type}` ,
`#{reddemCode.facevalue},` 
`#{reddemCode.createUser}, #{reddemCode.createTime}` 
                )
        </foreach >
</insert >

3.where 条件

<select id="testWhere" parameterType="Map"
        resultMap="UserInfoResult">
        select * from userinfo
        <where>
            <if test="department!=null">
            department like `#{department}` 
            </if>
            <if test="gender!=null">
                AND gender= `#{gender}` 
            </if>
            <if test="position!=null">
                AND position like `#{position}` 
            </if>
        </where>
</select>
  • 不确定条件是否存在就使用 <where> 标签
  • 按照标准写法,第一个 <if> 标签内的 AND 应该不写,但是,就算开发中书写也不会报错。
  • where 标签帮助我们自动的移除了第一个 AND 链接。
  • 第二个之后的 <if> 标签内,必须有 AND 链接。
  • 如果没有一个条件符合,则返回所有条目, where 不起作用。
  • 相当于 where 1=1 之后加条件

4. 循环获取 Map 中的 key 和 value

有时候需要简单地把一个 Map 中所有的 key 和 value 获取出来,拼到 sql 语句中。MyBatis 提供的一种方法是遍历 Map 中的 entrySet,然后把 key 扔进 index 里面,value 扔进 item 中。具体的一个使用的例子如下:

<insert id="operationName" parameterType="map">
		INSERT INTO table_name(hot_word, cnt)
		VALUES
		<foreach item="value" index="key" collection="mapData.entrySet()" open="(" separator="),(" close=")">
			 `#{key}, #{value}` 
		</foreach>
		ON DUPLICATE KEY UPDATE
		cnt=VALUES(cnt)
	</insert>

5.mybatis property column

通过里面的 id 标签和 result 标签来建立映射关系,由 property 和 column 分别指定实体类属性和数据表的列名。

6. 在 xml 中使用><等特殊符号

特殊字符

xml 中表示:
<= 小于等于

> = 大于等于

需加标记:<![CDATA[   ]]>
xml中有 & 的符号,需要<![CDATA[&]]>这样表示&

<= 小于等于 :<![CDATA[ <= ]]>

> = 大于等于:<![CDATA[  >=  ]]>

CDATA 区

它的全称为 character data, 以 <![CDATA[ 开始,以 ]]> 结束,在两者之间嵌入不想被解析程序解析的原始数据,解析器不对 CDATA 区中的内容进行解析,而是将这些数据原封不动地交给下游程序处理。

一些特殊字符也可用下面的替代符号所代替。

特殊字符 替代符号

&           &

<           <

> 			">>

"           "

'           '

7. 插入并更新

ON DUPLICATE KEY UPDATE
		sale_cost= VALUES(sale_cost),
		amount = VALUES(amount),
		user_id = VALUES(user_id);

8. MyBatis+MySQL 返回插入的主键ID

<insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="com.chenzhou.mybatis.User">  
    insert into user(userName,password,comment)  
`values( #{userName},#{password},#{comment} )  ` 
</insert>

9.MybatisPlus问题 xxxMapper 未找到Bean

缺包:

<properties>
        <mybatis-plus.vision>3.1.2</mybatis-plus.vision>
    </properties>        
		
		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>${mybatis-plus.vision}</version>
            <scope>compile</scope>
     </dependency>
     <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.vision}</version>
     </dependency>

10. mybatis IndexOutOfBoundsException: Index: , Size:

### Cause: java.lang.IndexOutOfBoundsException: Index: 4, Size: 4
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
	at com.sun.proxy.$Proxy203.selectList(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)

解决

返回实体增加构造方法,增加lombok注解或者是直接添加无参构造方法

@AllArgsConstructor
@NoArgsConstructor

11.Mybatis中foreach优化

关键代码

<if test="devIds != null and devIds != ''">
      and EXISTS (select 1 from
       (SELECT regexp_split_to_table(#{devIds},',') AS dev_id) AS vir where cast(vir.dev_id as BIGINT) = sd.id)
</if>

12.Mybatis传入多个map参数

如果你不但需要传入map作为参数去sql中遍历,还需要传入别的参数

1,首先,传入map的遍历方式

把要传入的map转换为如下的形式

Map<String,Map<String,String>> map = new HashMap<>();

mabatis遍历中

<foreach collection="Map_Name"  item="value" index="key">
    sql语句

</foreach>

2,map的解决了,那么其他的参数怎么获取呢?我是这么解决的

仿照1的做法,把其他的参数也放到map中

Map<String,Object> map = new HashMap<>();
map.put("参数名","参数值");

再把这个map也添加到1中的大map中去,取值的时候也需要用foreach的方式取值,

3,坑点

注意在一个sql中,两个foreach的 item 和 index 的变量名,不要一样,一样的话会报下面的错

source is null for getProperty(null, "name")
<foreach collection="Map_Name1"  item="value1" index="key1">
    sql语句

</foreach>


<foreach collection="Map_Name2"  item="value2" index="key2">
    sql语句

</foreach>

13.MyBatis嵌套循环map

前言

mybatis 有默认的 list,array,但是没有默认的 map。所以不能直接写 collection=“map”,如果这么写,它会当成是根据 map.get(“map”)来取 value 值,大部分情况下是一个 map 中是不会有 “map” 这个 key 的,于是就是报错。如果你想用这个 “map” 标识取参数 map,就需要保证传入的 Map 参数有 @Param(“map”)注解。

mybatis 入参 map 的基本语法:

service,dao 的写法:

//service:
public List<BpmDefUser> getByMap(Map<String,List<Long>> map){
        Map<String,Object> paramsMap= new HashMap<String, Object>();
        params.put("paramsMap", map);
        return this.getByMap(paramsMap);   
}
//dao:
int getByMap(Map<String,Object> map)
//service:
public List<BpmDefUser> getByMap(Map<String,List<Long>> map){
        Map<String,Object> paramsMap= new HashMap<String, Object>();
        params.put("paramsMap", map);
        return this.getByMap(paramsMap);   
}
 
//dao:
int getByMap(Map<String,Object> map)

或者(推荐):

//service直接调用dao
int getByMap(@param("paramsMap") Map<String,Object> map)
//service直接调用dao
int getByMap(@param("paramsMap") Map<String,Object> map)

xml 的写法:

  • 循环 key:
<foreach collection="paramsMap.keys" item="k" separator="and">   
        `${k} = #{k}    `
    </foreach>   
    <foreach collection="paramsMap.keys" item="k" separator="and">   
      	` ${k} = #{k} `  
    </foreach>
  • 循环 values
<foreach collection="paramsMap.values" item="v" separator="and">   
   ` ${v} = #{v}   ` 
</foreach>   
<foreach collection="paramsMap.values" item="v" separator="and">   
   ` ${v} = #{v}  `  
</foreach>
  • 循环获取 key 和 value:
<foreach collection="paramsMap.keys" item="k" separator="and">   
    <if test="null != paramsMap[k]">    
       ` ${k} = ${paramsMap[k]}   ` 
    </if>  
</foreach>   
<foreach collection="paramsMap.keys" item="k" separator="and">   
    <if test="null != paramsMap[k]">    
       ` ${k} = ${paramsMap[k]}  `  
    </if>  
</foreach>
  • 一次循环得到 key 和 value 值(推荐):
<foreach collection="paramsMap" index="key"  item="value">
       `  ${key} = ${value}`
</foreach>
<foreach collection="paramsMap" index="key"  item="value">
        ` ${key} = ${value}`
</foreach>

易错点:表达式抒写错误

通常我们设置值的时候,会以 #{} 的方式,而不是 ${},如下:

<foreach collection="paramsMap.keys" item="k" separator=",">   
    <if test="null != paramsMap[k]">    
        `${k} = `#{paramsMap[k]}`    `
    </if>  
</foreach>   
<foreach collection="paramsMap.keys" item="k" separator=",">   
    <if test="null != paramsMap[k]">    
       ` ${k} = #{paramsMap[k]}`    
    </if>  
</foreach>

你会发现,取不了值了,${condition[k]} 能取的出值,但 #{condition[k]} 取出来的值却实 null,正确的写法应该是:

<foreach collection="paramsMap.keys" item="k" separator=",">   
    <if test="null != paramsMap[k]">    
        `${k} = `#{paramsMap[${k}]}`  `
    </if>  
</foreach>   
<foreach collection="paramsMap.keys" item="k" separator=",">   
    <if test="null != paramsMap[k]">    
        `${k} = `#{paramsMap[${k}]}` ` 
    </if>  
</foreach>

14. MyBatis 嵌套循环 map 的高级用法

假如参数类型是这么一个类型结构:Map map = new HashMap<String, HashSet<String>>我想要拼装出来的 sql 如下:

select * from 表名
where (
    (id = 1 and name in ('小二','小三','小四') or
    (id = 2 and name in ('小二','小三','赵六') or
    (id = 3 and name in ('小三','王五','王八') or
    ……
)
select * from 表名
where (
    (id = 1 and name in ('小二','小三','小四') or
    (id = 2 and name in ('小二','小三','赵六') or
    (id = 3 and name in ('小三','王五','王八') or
    ……
)

mybatis 应该怎么写?

第一种写法:

SELECT * FROM 表名
        WHERE 
        <foreach collection="paramsMap.keys" item="key" open="(" separator="OR" close=")">
            (id = `#{key}` AND name in
              <foreach collection = "paramsMap[key]" item="name" separator="," open="(" close=")">
                  `#{name}`
              </foreach>
            )
        </foreach>
 SELECT * FROM 表名
        WHERE 
        <foreach collection="paramsMap.keys" item="key" open="(" separator="OR" close=")">
            (id = `#{key}` AND name in
              <foreach collection = "paramsMap[key]" item="name" separator="," open="(" close=")">
                  `#{name}`
              </foreach>
            )
        </foreach>

第二种写法(推荐):

SELECT * FROM 表名
        WHERE 
        <foreach collection="paramsMap" index="key"  item="value" open="(" separator="OR" close=")">
            (id = `#{key}` AND name in
              <foreach collection = "value" item="name" separator="," open="(" close=")">
                  `#{name}`
              </foreach>
            )
        </foreach>
 SELECT * FROM 表名
        WHERE 
        <foreach collection="paramsMap" index="key"  item="value" open="(" separator="OR" close=")">
            (id = `#{key}` AND name in
              <foreach collection = "value" item="name" separator="," open="(" close=")">
                  `#{name}`
              </foreach>
            )
        </foreach>