MyBatis XML简单理解

时间:2022-07-25
本文章向大家介绍MyBatis XML简单理解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本文集各家之长,自学整理,若有错误,欢迎留言指出!!!


固定格式

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.scau.demo.mapper.UserMapper">
## ...具体内容...
</mapper>

  其中,namespace用于绑定Mapper接口。不同mapper接口对应到不同的xml。

前置操作

1、在application.yml中添加:

mybatis:
  # 设置别名,这样,在xml文件中就不用写全名 
  type-aliases-package: com.scau.demo.entity
  # resources文件夹下创建mapper文件夹,内含xxxMapper.xml文件
  mapper-locations: classpath:mapper/*.xml

2、在启动类前添加:

// mapper接口所在包路径
@MapperScan(basePackages = "com.scau.demo.mapper") 

顶级元素

<xx>内最外层可以包含的元素。

  • cache – 配置给定命名空间的缓存。
  • cache-ref – 从其他命名空间引用缓存配置。
  • resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
  • parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
  • sql – 可以重用的 SQL 块,也可以被其他语句引用。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

select

补充说明:

  • id:对应mapper接口中的函数定义,如:
  • parameterType:入参类型,可以使用的有基本数据类型Java复杂数据类型
    • 基本数据类型:包含int,String,Date等。基本数据类型作为传参,只能传入一个。通过#{参数名} 即可获取传入的值
    • 复杂数据类型:包含JAVA实体类、Map。通过#{属性名}或#{map的KeyName}即可获取传入的值
// 基本类型
<select id="get" parameterType="String" resultType="User">
    select * from `scau_log` where `_openid`=#{_openid};
</select>

// 复杂类型 - 实体类
<select id="selectTeacher" parameterType="com.myapp.domain.Teacher" resultType="com.myapp.domain.Teacher">  
    select * from Teacher where c_id=#{id}  
</select>  
  • resultType:结果类型,与mapper接口中的函数定义的返回值一致
// 返回一般数据类型的值
<select id="Sel" resultType="java.lang.String">
    select username from user_test where id = #{id}
</select>	

// 返回类型是javaBean
<select id="Sel" resultType="com.tx.springboottestdemo.entity.User">
    select * from user_test where id = #{id}
</select>

// 返回是List类型
List<User> getUsers();  // mapper 接口
// SQL映射文件,这里需要注意的是返回是List类型 但是resultType依然是javaBean
<select id="getUsers" resultType="com.tx.entity.User">
    select * from user
</select>

// 返回类型是Map结构
// 当我们在查询并返回一条数据的时候,可以把{字段名,字段值}封装成Map结构
Map<String, Object> findUserByName(Integer id);  // mapper 接口
<select id="findUserByName" resultType="string">
    select userName from user where id=#{id};
</select>

// 传入多个参数 - 1
// 可以看做是加了注解
public List<User> findUser(@Param("name1") String name1, @Param("name2") String name2);
// 对应的SQL文件:
<select id="findUser" resultType="com.tx.springboottestdemo.entity.User">
    select * from user_test where userName = #{name1} and realName = #{name2}
</select>

// 传入多个参数 - 2
// 可以把参数封装到Map里面 有些时候我们的业务数据查询没有定义对应的POJO,就进行参数的封装操作。
public List<User> findUser1(Map<String, Object> map);
// 对应的SQL文件:
<select id="findUser1" parameterType="java.util.Map" resultType="com.tx.springboottestdemo.entity.User">
    select * from user_test where userName = #{username} and realName = #{realname}
</select>

insert,update,delete

  数据变更语句 insert,update 和 delete 在它们的实现中非常相似。

补充说明:

  • useGeneratedKeys、keyProperty:如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。例如使用下列语句,这样每次插入数据时,就可以省略掉 id 列了。(:当数据库中的字段不是自增的时,useGeneratedKeys 不起作用。)
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
    insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio})
</insert>

  如果你的数据库还支持多行插入, 你也可以传入一个数组或集合,并返回自动生成的主键。

<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user (name, age) VALUES
    <foreach collection="list" item="user" index="index" separator="," >
        (#{user.name}, #{user.age})
    </foreach>
</insert>
  • keyColumn:用于指定数据库table中的主键。通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
  • 插入的时候系统时间值可以直接用now()

xml语法

总体说来mybatis 动态SQL 语句主要有以下几类:

  • if 语句 (简单的条件判断)
  • choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似.
  • trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
  • where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误)
  • set (主要用于更新时)
  • foreach (在实现 mybatis in 语句查询时特别有用)

if 语句

  在mapper接口中定义一个函数名,其中@Param指定xml中对应的名称,后面会用到。

List<Map<String,Object>> getByItem(@Param("item") String item, @Param("val") String val);

  在controller类和service类中:

@RequestMapping(value = "/getByItem")
public Result getByItem(String item, String value){
    return userService.getByItem(item, value);
}

public Result getByItem(String item, String value){
    return Result.ok(userMapper.getByItem(item, value));
}

Result 类是封装的一个返回类,可以先不用管。   XML中:

<select id="getByItem" resultType="User">
    select * from `scau_log` where
    <if test="item == '_id'">
        _id=#{val}
    </if>
</select>

  postman发送:

  但如果item!=_id,则语句就变成了select * fromscau_logwhere而报错,可以使用<where >

where 语句

where元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。   将上面的xml改为如下即可:

<select id="getByItem" resultType="User">
    select * from `scau_log`
    <where>
        <if test="item == '_id'">
            _id=#{val}
        </if>
    </where>
</select>

  如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。

trim 语句

  和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides、suffixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides(suffixOverrides) 属性中指定的内容,并且插入 prefix(suffix) 属性中指定的内容。

set 语句

 用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

 这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。  来看看与 set 元素等价的自定义 trim 元素,注意我们覆盖了后缀值设置,并且自定义了前缀值。:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

foreach

 对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

 foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符  你可以将任何可迭代对象(如 ListSet 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用Map对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

 foreach元素的属性主要有item,index,collection,open,separator,close。

  • item表示集合中每一个元素进行迭代时的别名。
  • index指定一个名字,用于表示在迭代过程中,每次迭代到的位置。
  • open表示该语句以什么开始。
  • separator表示在每次进行迭代之间以什么符号作为分隔符。
  • close表示以什么结束。

 在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:

  • 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
  • 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
  • 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。
// 单参数List的类型
public List<User> dynamicForeachTest(List<Integer> ids);  // 对应的Mapper
<select id="dynamicForeachTest" resultType="com.mybatis.entity.User">
    select * from t_user where id in
    <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

// 数组类型的参数
public List<User> dynamicForeach2Test(int[] ids);  // 对应的Mapper
<select id="dynamicForeach2Test" resultType="com.mybatis.entity.User">
    select * from t_user where id in
    <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

// Map类型的参数
public List<User> dynamicForeach3Test(Map<String, Object> params);   // 对应的Mapper
<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User">
    select * from t_user where username like '%${username}%' and id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

choose(when,otherwize) 语句

<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
    select * from t_blog where 1 = 1 
    <choose>
        <when test="title != null">
            and title = #{title}
        </when>
        <when test="content != null">
            and content = #{content}
        </when>
        <otherwise>
            and owner = "owner1"
        </otherwise>
    </choose>
</select>

when元素表示当when中的条件满足的时候就输出其中的内容,当when中有条件满足的时候,就会跳出choose,即所有的whenotherwise条件中,只有一个会输出;当所有的条件都不满足的时候就输出otherwise中的内容。  所以上述语句的意思非常简单,当title!=null的时候就输出and titlte = #{title},不再往下判断条件,当title为空且content!=null的时候就输出and content = #{content},当所有条件都不满足的时候就输出otherwise中的内容。

模糊查找

<if test="infoTemplateAll.templateName != null">
    AND template_name LIKE '%${infoTemplateAll.templateName}%'
</if>

批量插入

<insert id="insertSelectives" parameterType="java.util.List">
	INSERT INTO oap_detail_income
		(
			income_seq_num,
			interest_terms
		)
		VALUES
			<foreach collection="list" item="file" index="index"
			separator=",">
			(
			 #{file.incomeSeqNum},
			 <choose>
				<when test="file.interestTerms != null">
					#{file.interestTerms},
				</when>
				<otherwise>
					0,
				</otherwise>
			 </choose>
			)
		 </foreach>
</insert>

… …


其他

MySQL时区错误

打开my.ini,搜索[mysqld],在[mysql]节点下加上这一行

default-time-zone='+08:00'

重启mysql服务

IDEA快速创建xml

File -> Setting -> File and Code Templates - > ‘+’号新建 -> 填写Name和Extension -> 自行填写内容 -> OK

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xx.mapper.xxMapper">
    <select id="GetUserByID" parameterType="int" resultType="com.test.springtest.dao.MUser">
        select * from `student` where id = #{id}
    </select>
    <insert
        id="saveUser" parameterType="com.test.springtest.User" useGeneratedKeys="true">
        insert into student(NAME,AGE) values (#{name},#{age})
    </insert>
</mapper>