1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > MyBatis 持久化框架快速使用入门(Xml配置版)

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

时间:2021-01-18 04:14:36

相关推荐

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

目录

MyBatis 持久化框架概述

Mybatis 标签汇总

SqlSessionFactory & SqlSession

搭建 Spring boot + Mybatis 环境

MyBatis 语法使用快速入门

resultType 设置查询结果类型

parameterType 设置参数类型

#{} VS ${} 取值对比

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

foreach 循环容器元素

concat 字符串拼接

choose (when, otherwise) 流程控制

if 条件判断

where 条件语句

if + set 修改语句

trim 代替 where、set 标签

sql 片段标签定义 sql 片段

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 映射框架之一。

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 标签汇总

SqlSessionFactory & SqlSession

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 mit();} catch(Exception e){sqlSession.rollback();} finally {session.close();}

搭建 Spring boot + Mybatis 环境

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

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

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

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

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

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

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

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

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

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

9、本文的 XxxMapper 映射接口在线源码目录:/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>

parameterType 设置参数类型

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

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

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

#{} VS ${} 取值对比

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

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>

concat 字符串拼接

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

//mapper 接口中提供方法:根据关键字模糊查询,默认查询所有List<Dept> findByKeyword(String keyword);<!-- 对应 xml 中标签:根据关键字模糊查询,不为空时才拼 like 条件,否则默认查询所有.--><select id="findByKeyword" resultType="com.wmx.hb.pojo.Dept" parameterType="string">select * from dept<where><if test="keyword!=null">dname like concat('%',concat(#{keyword},'%')) or loc like concat('%',concat(#{keyword},'%'))</if></where></select>

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>

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>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。