MyBatis 持久化框架快速使用入门(Xml配置版)

目录

MyBatis 持久化框架概述

Mybatis 标签汇总

SqlSessionFactory & SqlSession

搭建 Spring boot + Mybatis 环境

MyBatis 语法使用快速入门

resultType 设置查询结果类型

resultMap 结果集映射

association 一对一结果集映射

collection 一对多结果集映射

parameterType 设置参数类型

#{} VS ${} 取值对比

[CDATA[XXX]]> 转义小于符号

foreach 循环容器元素

concat 字符串拼接

choose (when, otherwise) 流程控制

if 条件判断

where 条件语句

if + set 修改语句

trim 代替 where、set 标签

sql 片段标签定义 sql 片段

 update 标签操作 DDL 定义语句

MyBatis 集成 Spring boot 自动配置原理

@Param 定义 XxxMapper 方法多个参数


本文环境:Spring boot 2.3.5 + Java jdk 8 + Mysql + Log4j2 . + MyBatis 3.5.7

1、用户访问 Controller 控制层 -> Servires 业务层-> XxxMapper 接口-> XxxMapper.xml 映射。

2、所以使用 MyBatis 的重点就是 XxxMapper 接口 与 XxxMapper.xml 映射,本文采用 xml 的方式,不采用在注解上写 Sql 的方式。

MyBatis 持久化框架概述

1、MyBatis 是世界上流行最广泛的 SQL 映射框架之一。

 官网:https://blog.mybatis.org/

 MyBatis中文官网:https://github.com/mybatis/mybatis-3

 配置:https://mybatis.org/mybatis-3/configuration.html#settings

 集成:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

 github:https://github.com/mybatis/mybatis-3

2、Hibernate 的优点是将整个开发设计过程全部面向对象开发,全ORM,不用写任何SQL语句。

3、MyBatis 维持原有的编程方式,前部分按面向对象思考和设计,持久层时使用sql语句,面向过程,半 ORM。

4、Hibernate 的弱点是底层仍然使用sql,需要将hql语句转为sql,导致Sql无法优化,且Hibernate需要通过反射,性能较低。

5、MyBatis 只是基于jdbc的轻量级封装,还是使用sql,性能比较高。

6、所以业内认为:中小型项目使用 Hibernate,开发速度快;大型项目使用MyBatis,项目性能高。

7、 SqlSessionFactory 是线程安全的,SqlSession是线程不安全的,不能做类的公共变量。

8、学习 MyBatis 主要是学习它的标签语法,它们很类似以前的 JSTL 标签,所以本文重点就是介绍它的语法使用。

Mybatis 标签汇总

常用标签描述
<select>用于 select 查询 sql 语句
<insert>用于 insert 插入 sql 语句
<update>用于 update 更新 sql 语句。不仅支持 update 操作,还能支持DDL语句:如 CREATE、ALTER、DROP 等等。
<delete>用于 delete 删除 sql 语句
<foreach>用于遍历容器元素,如 List、Set、Array 等,通常用于为 in 函数设置参数.
<![CDATA[xxx]]>

小于符号转义,如 <![CDATA[and sal <= #{end}]]>

<mapper namespace="xxx">mapper 是整个 xml 文件的根标签,namespace 表示此配置文件的命名空间,严格上来说,没有强制要求,只需要唯一即可,不过官方推荐命名空间设置为 XxxMapper 的全路径.
<if test=true|false>

如果判断结果为 true,则将其中的内容拼接到 sql 中,否则不拼接。
<if test="name!=null and name !=''">xxx</if>
<if test="age <= 18 or age == 30">xxx</if>

<where>

当 where 标签中有返回值时,where 标签会自动插入一个 'where' 字符串 sql .
当 where 标签返回的内容是以 AND 或 OR 开头时,会自动剔除掉开头的 'and' 和 'or',不区分大小写。

<set>当其中有内容时,自动添加 set 关键字,如果内容结尾有多余的逗号,也会自动删除。
<trim>trim 是一个格式化的标记,可以完成 set、where 标记的功能,有如下属性:
prefix:为内容添加前缀,如 "set"
suffix:为内容添加前缀,如 "where id=#{id}"
suffixOverrides:去掉内容结尾的指定字符串(多个时用"|"隔开),如逗号 ","
prefixOverrides:去掉内容开头的指定字符串(多个时用"|"隔开),如逗号 "and|or"

SqlSessionFactory & SqlSession

MyBatis 核心API描述
SqlSessionFactoryBuilder

a、这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是本地方法变量)。

b、可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

SqlSessionFactory

a、一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。

b、因此 SqlSessionFactory 的最佳范围是应用范围,有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

openSession():会默认开启一个事务,但事务不会自动提交,需要手动提交和回滚。
openSession(boolean autoCommit):参数为是否自动提交,如果设置为true。
SqlSession

a、每个线程都应该有它自己的 SqlSession 实例,SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。

b、绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例域也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的 HttpSession。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

 9、如下所示为纯 MyBatis 底层用法,如果是 myBatis + Sring Boot 集成,则无法在编写这种底层代码了。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession= sqlSessionFactory.openSession();
try {
  BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  // do work
  sqlSession.commit();
} catch(Exception e){
  sqlSession.rollback();
} finally {
  session.close();
}

搭建 Spring boot + Mybatis 环境

1、新建 Spring boot 应用,pom.xml 文件引入相关依赖,比如 log4j2 日志、mysql 驱动、myBatis:https://gitee.com/wangmx1993/hb/blob/master/pom.xml

2、Mysql 数据库中准备好数据库、表、以及测试数据创建 emp 与 dept 脚本.sql

3、类路径下提供 log4j2 日志配置文件:src/main/resources/log4j2.xml · 汪少棠/hb - Gitee.com

为了能清晰的看到 myBatis 执行的 sql,可以设置 myBatis 的日志输出基本为 debug:

<logger name="org.mybatis" level="debug"></logger>

4、application.yml 全局配置文件配置数据源与 myBatis:src/main/resources/application.yml · 汪少棠/hb - Gitee.com

5、提供 myBatis 核心配置文件mybatis-config

6、jdbc 默认使用的 Hikari 数据源,可以写一个测试类 DataBaseTests 运行一下,看看数据库是否连接正常,此时需要先将 application.yml  中 myBatis 的配置暂时注释掉。

7、为了更好的封装接口返回的参数,提供返回数据实体和枚举:ResultData.javaResultCode.java

8、提供全局统一异常处理类:AppExceptionController.java

9、本文的 XxxMapper 映射接口在线源码目录:https://gitee.com/wangmx1993/hb/blob/master/src/main/java/com/wmx/hb/mapper 

10、本文的 XxxMapper.xml 映射在线源码目录:/src/main/resources/myBatis/mapper 

MyBatis 语法使用快速入门

resultType 设置查询结果类型

1.    resultType 是 <select> 标签中的属性,表示查询结果的类型。

2.    resultType 的值可以是基础类型,如 int、String;也可以是 POJO 对象,如 User,POJO 对象时要写全路径。

<!--查询表中的数据总条数-->
<select id="countForTable" resultType="long">
	select count(1) from dept
</select>

<!--返回值类型指定为 List 中的元素类型-->
<select id="findDeptEmp" resultType="java.util.Map">
	SELECT t1.*,t2.* from dept t1,emp t2 WHERE t1.deptno = #{deptno} and t1.deptno = t2.deptno;
</select>

<!-- select 表示查询标签,id 属性值是 DeptMapper 接口中的方法名称,resultType 指定返回值的类型-->
<!--可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<select id="findDeptById" resultType="com.wmx.hb.pojo.Dept">
	select dept.deptno,dept.dname,dept.loc from dept where deptno = #{deptno}
</select>

resultMap 结果集映射

    <!--对查询结果进行数据库列与实体属性的映射。与注解 @Results 等价-->
    <!--resultMap 的 id 属性用于唯一定义,用于 select 标签引用;type 属性用于定义返回的对象类型 -->
    <!--id 标签用于定义主键列,可以省略不写;result 标签用于定义数据库列与对象属性的映射,省略时根据名称自动映射.-->
    <!--column 属性定义数据库表的列;property 定义对象的属性名,对象关联对象时,属性也可以级联指定-->
    <resultMap id="getEmpByName_resultMap" type="com.wmx.hb.pojo.Emp">
        <id column="empno" property="empno"/>
        <result column="deptno" property="deptno"/>
        <result column="deptno" property="dept.deptno"/>
        <result column="dname" property="dept.dname"/>
        <result column="loc" property="dept.loc"/>
    </resultMap>

    <!--根据姓名查询员工信息————一对一关联查询员工所属的部门信息-->
    <!--resultMap 指定结果集字段映射-->
    <select id="getEmpByName" resultType="com.wmx.hb.pojo.Emp" resultMap="getEmpByName_resultMap">
        SELECT e.EMPNO,e.ENAME,e.JOB,e.MGR,e.HIREDATE,e.SAL,e.COMM,d.DEPTNO,d.DNAME,d.LOC
        FROM emp e LEFT JOIN dept d ON e.DEPTNO = d.DEPTNO
        WHERE ename like concat('%',concat(#{ename},'%'))
    </select>

EmpMapper.xmlEmpMapper.javaEmp.java

association 一对一结果集映射

1、除了上面 resultMap 结果集映射 中的写法,下面也可以实现一对一结果集映射。

    <!--一对一结果集映射,除了级联写法,也可以通过 association 指定关联的对象属性,等价于注解 @One -->
    <!--此时对象的属性都必须显示指定,否则值会为 null.-->
    <resultMap id="getEmpByName_resultMap2" type="com.wmx.hb.pojo.Emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
        <association property="dept" javaType="com.wmx.hb.pojo.Dept">
            <id column="deptno" property="deptno"/>
            <result column="dname" property="dname"/>
            <result column="loc" property="loc"/>
        </association>
    </resultMap>

EmpMapper.xml  、EmpMapper.javaEmp.java

collection 一对多结果集映射

1、多对多本质也是一对多,与一对多完全同理,比如 用户对角色——多对多,单方面看时同一也是一对多。

    <!--一对多关联查询部门下的员工信息,collection:用于定义多方对象的属性映射信息,等价于 @Many 注解。-->
    <!--虽然使用内连接或者左右外连接查询时,一个部门对多个员工,部门信息在结果集中存在重复数据,
        但是其中的 id 标签用于定义主键列,所以它会自动归类,并将关联的员工信息放入对应的集合中,实现一对多查询.-->
    <resultMap id="findDeptEmp_resultMap" type="com.wmx.hb.pojo.Dept" >
        <id column="deptno" property="deptno" />
        <result column="dname" property="dname" />
        <result column="loc" property="loc" />
        <collection property="empList" ofType="com.wmx.hb.pojo.Emp">
            <id column="empno" property="empno" />
            <result column="ename" property="ename"/>
            <result column="job" property="job"/>
            <result column="mgr" property="mgr"/>
            <result column="hiredate" property="hiredate"/>
            <result column="sal" property="sal"/>
            <result column="comm" property="comm"/>
        </collection>
    </resultMap>
	
	<!-- 根据关键字模糊查询,不为空时才拼 like 条件,否则默认查询所有.-->
    <!--一对多关联查询部门下的员工信息-->
    <select id="findByKeyword" resultType="com.wmx.hb.pojo.Dept" parameterType="string" resultMap="findDeptEmp_resultMap">
        select e.EMPNO,e.ENAME,e.JOB,e.MGR,e.HIREDATE,e.SAL,e.COMM,d.DEPTNO,d.DNAME,d.LOC
        from dept d left join emp e on d.deptno = e.deptno
        <where>
            <if test="keyword!=null">
                dname like concat('%',concat(#{keyword},'%')) or loc like concat('%',concat(#{keyword},'%'))
            </if>
        </where>
        order by deptno desc
    </select>

DeptMapper.xmlDeptMapper.javaDept.java

parameterType 设置参数类型

1、parameterType 是 CRUD 标签中的属性,表示参数类型、参数映射,可以省略不写,此时会自动根据接口方法的参数进行映射。

2、parameterType 同样可以是基本数据类型如:int、flout等;也可以是POJO对象;甚至是List、Set、Array、Map等。

3、因为 Map 最灵活,所以项目中一般用 Map 最多,#{key} 取值的 key 就是 Map 中的 key。使用示例看下一节。

#{} VS ${} 取值对比

1、两者都是用于获取传入的参数值。

#{}表示一个占位符号,通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java类型和 jdbc 类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

2、#{}:会自动根据参数类型做封装,例如对字符串、日期类型,两边自动加单引号,而对数值类型直接使用。

3、${}:将传入的参数直接拼接到 SQL 中,例如拼接 表名,或者 order by xxx 等等,这些比较特殊的地方。

4、#{} 的好处是可以防止 SQL注入,因为非法用户传入的非法SQL只能是字符串类型,这样两头加上单引号后,SQL语法就错了,不会执行成功的()。

5、${} 取的值如果为 null,还容易报错,所以除非不得已,否则推荐一律使用 #{}。

//分页查询接口
@GetMapping("/dept/findByLimit")
public ResultData<List<Dept>> findByLimit(Integer page, Integer rows) {
	page = page == null || page <= 0 ? 1 : page;
	rows = rows == null || rows <= 0 ? 2 : rows;

	Map<String, Object> paramMap = new HashMap<>();
	paramMap.put("start", (page - 1) * rows);
	paramMap.put("end", (page - 1) * rows + rows);
	paramMap.put("orderColumn","dname");

	List<Dept> deptList = deptMapper.findByLimit(paramMap);
	return new ResultData<>(ResultCode.SUCCESS, deptList, null, page, rows);
}

//deptMapper 映射接口方法
List<Dept> findByLimit(Map<String, Object> paramMap);

<!--DeptMapper.xml 标签-->
<!-- 可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<!-- order by 的值必须使用 ${} 取值}-->
<select id="findByLimit" resultType="com.wmx.hb.pojo.Dept" parameterType="map">
	select dept.deptno,dept.dname,dept.loc from dept order by ${orderColumn} limit #{start},#{end}
</select>
//比如想根据某列的值进行查询,其中 ${column} 会被直接替换,如  id,name,age...,而 #{value} 会使用 ? 预处理
//用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击,
//因此,要么不允许用户输入这些字段(column),要么自行转义并检验这些参数。
@Select("select * from user where ${column} = #{value}")
List<User> findByColumn(String column, String value);

[CDATA[XXX]]> 转义小于符号

1、小于符号'<' 在 xml 文件中表示标签的开始,所以 sql 中的小于符号必须进行转义。

//查询薪资在[start,end]之间的员工,start 为空时,不设下限,end 为空时,不设上限.
@GetMapping("/emp/getEmpBySal")
public ResultData<Emp> getEmpBySal(Double start, Double end) {
	Map<String, Double> paramMap = new HashMap<>();
	paramMap.put("start", start);
	paramMap.put("end", end);
	List<Emp> empList = empMapper.getEmpBySal(paramMap);
	return new ResultData(ResultCode.SUCCESS, empList);
}

//EmpMapper 接口方法
List<Emp> getEmpBySal(Map<String, Double> paramMap);

<!--EmpMapper.xml 映射:小于符号'<'必须进行转义-->
<select id="getEmpBySal" resultType="com.wmx.hb.pojo.Emp" parameterType="map">
	select * from emp t
	<where>
		<if test="start!=null">
			sal >= #{start}
		</if>
		<if test="end != null">
			<![CDATA[and sal <= #{end}]]>
		</if>
	</where>
</select>

foreach 循环容器元素

1、foreach 元素的属性主要有:item,index,collection,open,separator,close
    item:集合中元素迭代时的别名
    index:集合中元素迭代时的索引
    open:常用语where语句中,表示以什么开始,比如以'('开始
    separator:表示在每次进行迭代时的分隔符,比如','
    close:常用语where语句中,表示以什么结束,比如以')'结尾
    collection:集合名称,通常是集合或者数组的参数名称,必传,其他的选项可选

2、collection 属性是必须指定的,在不同情况下,其值是不一样的,主要有以下3种情况:
    如果传入的是单参数且参数类型是一个List的时候,collection属性值约定为list.
    如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值约定为array.
    如果传入的参数是多参数,则需要把它们封装成一个Map,当然单参数也可以封装成map.
    
3、不管是多参数还是单参数的 list,array,set类型,collection  都可以封装为map进行传递。
    如果传递的是一个List,则mybatis会封装为一个list为key,list值为object的map,
    如果是array,则封装成一个array为key,array的值为object的map,
    如果自己封装呢,则colloection里放的是自己封装的map里的key值

4、注意 foreach 的集合或者数组如果为空,则抛异常。

//mapper 接口中提供方法:根据主键集合查询部门数据
List<Dept> findByDeptnos(List<Integer> deptnos);

!--根据主键 id集合查询,deptnos 就是接口方法参数的名称,如果 foreach 的集合或者数组为空,则直接异常-->
<select id="findByDeptnos" resultType="com.wmx.hb.pojo.Dept">
	select * from dept
	<where>
		<if test="deptnos !=null and deptnos.size > 0">
			deptno in
			<foreach collection="deptnos" item="deptno" index="index" open="(" separator="," close=")">
				#{deptno}
			</foreach>
		</if>
	</where>
</select>

EmpMapper.javaDeptMapper.javaDeptMapper.xmlEmpMapper.xml

concat 字符串拼接

1、concat 元素类似数据库的 concat 函数,用于拼接字符串。如:

SELECT e.* FROM emp e WHERE ename like concat('%',concat(#{ename},'%'))

2、示例可以参考上面的《collection 一对多结果集映射》

choose (when, otherwise) 流程控制

1、choose 标签是按顺序判断其内部 when 标签中的 test 条件是否成立,如果有一个成立,则 choose 结束,其他的 when 以及 otherwise 都不会再走。

2、当 choose 中所有 when 的条件都不满足时,则执行 otherwise 中的 sql。

//mapper 接口中提供方法:按顺序将实体类 Emp 第一个不为空的属性作为 where 查询条件,默认查所有
List<Emp> getEmp(Emp emp);

<!--对应 xml 中标签:choose-when-otherwise,其中一个 when 条件成立,则其他的都不会再走,所有 when 都不成立时,走 otherwise-->
<!-- select 表示查询标签,id 属性值是 XxxMapper 接口中的方法名称,resultType 指定返回值的类型-->
<!--可以不指定 parameterType 属性,此时会自动根据接口方法的参数类型进行映射-->
<select id="getEmp" resultType="com.wmx.hb.pojo.Emp" parameterType="com.wmx.hb.pojo.Emp">
	select * from emp
	<where>
		<choose>
			<when test="empno !=null">
				empno=#{empno}
			</when>
			<when test="ename !=null and ename !=''">
				ename like concat('%',concat(#{ename},'%'))
			</when>
			<when test="job !=null and job !=''">
				job like concat('%',concat(#{job},'%'))
			</when>
			<when test="hiredate !=null">
				hiredate=#{hiredate}
			</when>
			<otherwise></otherwise>
		</choose>
	</where>
</select>

if 条件判断

1、myBatis 中很多标签,如果参数为空,或者为 null,则容易出现异常,比如 foreach 的集合或者数组为空,则直接异常。

2、此时可以使用 if 动态 sql 语句先进行判断,如果值为 null 或等于空字符串,或者集合的 size<=0,则不进行操作。

where 条件语句

1、当 where 标签中有返回值时,where 标签会自动插入一个 'where' 字符串 sql .

2、当 where 标签返回的内容是以 AND 或 OR 开头,则会自动剔除掉 'and' 和 'or',不区分大小写。

//mapper 接口中提供方法:查询指定部门的信息,将实体对象中不为空的属性都作为 where 条件,默认查所有
List<Dept> findByDept(Dept dept);

<!--对应 xml 中标签:拼接 where 条件前进行是否为空判断-->
<!--where 标签会自动删除内容开头的 and 或者 or 字符串   -->
<select id="findByDept" resultType="com.wmx.hb.pojo.Dept">
	SELECT t1.deptno,t1.dname,t1.loc from dept t1
	<where>
		<if test="deptno!=null">
			deptno = #{deptno}
		</if>
		<if test="dname!=null and dname !=''">
			and dname like concat('%',concat(#{dname},'%'))
		</if>
		<if test="loc!=null and loc!=''">
			and loc like concat('%',concat(#{loc},'%'))
		</if>
	</where>
</select>

if + set 修改语句

1、当在 update 语句中使用 if 标签时,如果后面的 if 没有执行,则结尾会产生多余的逗号,从而导致错误。

2、使用 set 标签可以动态的追加 SET 关键字,以及剔除追加到条件末尾的任何多余的逗号。

//mapper 接口中提供方法:根据主键id修改部门信息,只修改不为null,且不为空的属性
Integer updateDeptByNotNull(Dept dept);

<!--对应 xml 中标签:set标签会自动去除内容结尾多余的逗号-->
<update id="updateDeptByNotNull" parameterType="com.wmx.hb.pojo.Dept">
	update dept t
	<set>
		<if test="dname!=null and dname !=''">
			dname=#{dname},
		</if>
		<if test="loc!=null and loc!=''">
			loc=#{loc}
		</if>
	</set>
	where deptno=#{deptno}
</update>

trim 代替 where、set 标签

1、trim 是更灵活的去处多余关键字的标签,可以代替 where 和 set 标签。

    prefix:表示为内容添加前缀,比如 where
    suffix:表示为内容添加后缀
    prefixOverrides:表示前缀覆盖,去除内容开头多余的前缀,如 'and'、'or'
    suffixOverrides:表示后缀覆盖,去除内容结尾多余的后缀,如 ','

2、trim标签代替 where标签,prefix 表示添加前缀 where,prefixOverrides 表示前缀覆盖,去除内容开头多余的 and 或者 or。

    <!--trim标签代替 where标签,prefix 表示添加前缀 where,prefixOverrides 表示前缀覆盖,去除前缀多余的 and 或者 or-->
    <select id="loadByDept" resultType="com.wmx.hb.pojo.Dept">
        SELECT t1.deptno,t1.dname,t1.loc from dept t1
        <trim prefix="where" prefixOverrides="and|or">
            <if test="deptno!=null">
                deptno = #{deptno}
            </if>
            <if test="dname!=null and dname !=''">
                and dname like concat('%',concat(#{dname},'%'))
            </if>
            <if test="loc!=null and loc!=''">
                and loc like concat('%',concat(#{loc},'%'))
            </if>
        </trim>
    </select>

3、trim 标签代替 set 标签,prefix 表示添加前缀 set,suffixOverrides 表示后缀覆盖,去除内容结尾多余的逗号

    <!--trim标签代替 set 标签,prefix 表示添加前缀 set,suffixOverrides 表示后缀覆盖,去除内容结尾多余的逗号-->
    <update id="modifyDeptByNotNull" parameterType="com.wmx.hb.pojo.Dept">
        update dept t
        <trim prefix="set" suffixOverrides=",">
            <if test="dname!=null and dname !=''">
                dname=#{dname},
            </if>
            <if test="loc!=null and loc!=''">
                loc=#{loc}
            </if>
        </trim>
        where deptno=#{deptno}
    </update>

sql 片段标签定义 sql 片段

1、sql 片段标签 <sql> 可定义能复用的 sql 语句片段,在执行 sql 语句标签中直接引用即可。

2、<sql> 的属性 id="xxx" 值表示该 sql 语句片段的唯一标识.

3、引用 sql 片段:通过 <include refid="xxx" /> 标签引用,refid="" 中的值指向需要引用的<sql>中的id属性。

<!--定义 dept 表的列信息,查询标签可以直接引用,不用再每次都重复写一遍-->
<sql id="dept_columns">
	dept.deptno,dept.dname,dept.loc
</sql>

<!-- 查询所有,虽然返回值是一个 List<Dept>,但是 resultType 只需要指定列表元素的类型即可.-->
<!--include 引用定义好的 sql 片段-->
<select id="findAllDepts" resultType="com.wmx.hb.pojo.Dept">
	select <include refid="dept_columns"/> from dept;
</select>

 update 标签操作 DDL 定义语句

1、<update> 标签不仅支持 update 更新操作,还能支持DDL语句:如 CREATE、ALTER、DROP 等等。

    <!-- 删除指定的表-->
    <update id="dropTable" parameterType="String">
        DROP TABLE IF EXISTS ${tableName}
    </update>

    <!-- 创建新人员信息表(person)-->
    <update id="createTableForPerson" parameterType="String">
        CREATE TABLE ${tableName} (
          p_id int NOT NULL AUTO_INCREMENT COMMENT '主键',
          p_name varchar(18) COLLATE utf8mb4_bin NOT NULL COMMENT '姓名',
          birthday date NOT NULL COMMENT '出生日期',
          salary float(10,2) DEFAULT NULL COMMENT '薪资水平',
          summary varchar(256) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '描述',
          PRIMARY KEY (p_id)
        ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='人员信息表';
    </update>

src/main/java/com/wmx/hb/mapper/DatabaseInitMapper.java · 汪少棠/hb - Gitee.com

src/main/resources/myBatis/mapper/base/DatabaseInitMapper.xml · 汪少棠/hb - Gitee.com

MyBatis 集成 Spring boot 自动配置原理

Spring Boot 2.x 集成 MyBatis ,MyBatis 自动配置原理与自定义配置

@Param 定义 XxxMapper 方法多个参数

1、XxxMapper 接口方法中如果需要使用到多个参数,通常是封装成 POJO 对象,或者使用 Map 封装,而 Map 看起来不太直观,此时可以使用 myBatis 的 @Param 注解进行定义多个参数名称。

//控制层方法
@PostMapping("/findByDept")
public List<Dept> findByDept(@RequestBody(required = false) Dept dept, Integer pageNum, Integer pageSize) {
	pageNum = pageNum == null || pageNum <= 0L ? 1 : pageNum;
	pageSize = pageSize == null || pageSize <= 0L ? 2 : pageSize;
 
	List<Dept> deptList = deptMapper.findByDept(dept, pageNum, pageSize);
	return deptList;
}

/**DeptMapper 接口方法
 * 1、查询指定部门的信息,将实体对象中不为空的属性都作为 where 条件,默认查所有。
 * 2、使用 org.apache.ibatis.annotations.Param 注解可以为 XxxMapper 接口方法指定多个参数。
 * 3、多个参数会被封装成一个 map,map 的 key 是使用 @Param 注解指定的值,value 是参数值。
 * 4、如果是级联对象,则 XxxMapper.xml 映射文件中也是级联取值,如 dept.deptno、dept.dname,前提是 dept 不能为 null,否则异常.
 * 
 * @param dept
 * @param pageNum  :查询的页码,从1开始
 * @param pageSize :每页显示的条数
 * @return
 */
List<Dept> findByDept(@Param("dept") Dept dept, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize);

<!--dept是对象,所以需要级联取值,必须不等于 null,才能级联取值-->
<!--拼接 where 条件前进行参数是否为空判断。返回值类型指定为 List 中的元素类型-->
<!--where 标签会自动删除内容开头的 and 或者 or 字符串   -->
<select id="findByDept" resultType="com.wmx.hb.pojo.Dept">
	SELECT t1.deptno,t1.dname,t1.loc from dept t1
	<where>
		<if test="dept !=null and dept.deptno!=null">
			deptno = #{dept.deptno}
		</if>
		<if test="dept !=null and dept.dname!=null and dept.dname !=''">
			and dname like concat('%',concat(#{dept.dname},'%'))
		</if>
		<if test="dept !=null and dept.loc!=null and dept.loc!=''">
			and loc like concat('%',concat(#{dept.loc},'%'))
		</if>
	</where>
</select>

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蚩尤后裔-汪茂雄

芝兰生于深林,不以无人而不芳。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值