mybatis的原理和实现
mybatis底层为itbatis。有人问了,为什么用mybatis不用itbatis?
mybatis介绍
mybatis的xml配置
首先,我们介绍一下mybatis的使用方法
如图所示
我们在xml文件里使用权限定符来定义映射的接口
id为接口里面的方法
id与namespace结合引到某接口里的方法 而resuleType呢
dml语句即:增加删除修改不需要设置,因为这三者返回的是影响的行数
我们只需要设置select标签的返回值。
返回值怎么设置呢?参数怎么设置呢?
为什么这个xml文件里面的select参数是#{id}的形式?
id可以换为其它的吗?
这些问题,我们稍后会讲,先回归到刚才的问题上。
我们实践后会观察到,mybatis的配置方式,非常的方便
编写namespace时,会有相应的提示
以及,id的对应关系使得我们写代码过程中会明白自己调用的是什么方法,以及方便后续其他人员的参考。
返回值类型呢我们暂且使用权限定符,写的时候会发现也有提示,方便。
mybatis的测试
写完了xml文件,怎么调用呢?
如图
读取相关的配置文件,同时获得mapper接口的类
之后调用这个接口的各种方法以实现sql语句的执行
itbatis对比
itbatis的xml配置
ok刚说的过程中我们了解到,mybatis有很多方便之处
这些方便是因为原有的机制并不方便
ok,我们来看看mybatis底层的itbatis是怎么写相关xml文件的
刚才我们写了什么?接口,接口对应的xml文件
而这里,不需要!
刚才我们的namespace以及id是分别对应了接口的位置以及接口里面的方法
而这里不需要,namespace随便写,id随便写
配置方法具体如图
itbatis的使用方法
如图
调用时只需要对应上相关的namespace以及id的关系即可
二者明明随便,但是,没有提示符号,同时参数是Object的形式,当是其它形式的时候,需要提前声明,很麻烦,以及在编写代码过程中不一定能写对
取值符号
我们观察到刚才写select标签的时候,我们引入参数id的时候是#{id},这个#{}是一种引入参数的方法
而这个id则是另一种原因,等会在传入的类型处会讲
为什么用#{}呢?有没有其他的?答案是有的
另一种是${}。这两者有什么区别呢?我们需要看具体的实现过程
这时候呢,我们就需要在总配置文件里面开启一个日志打印。
让日志能够打印到控制台上
之后呢,select设置两种模式
#{}参数引入
当是#{}的时候,如图,输出
可以看到当是#{}的时候,显示的是emp_id这个东西=? 后面又跟了一个参数的复数之后:1
${}参数引入
配置文件里面改为${}引入
在测试环境里运行,运行结果如图
这次发现,我们这里直接是数据库某以属性名=具体的数字1.而参数后面没有跟任何东西
也就是说${}是直接将东西拼接上去了
两种参数引入方式的总结
总结来看,#{}是,${}是字符串的拼接,也就是说结果为参数=字符串
#{}引入的东西会被当成一个单独的值
#{}这个有什么好处呢?比如说,这个题里面,我们设置的emp_id为varchar类型
当用户录入的id为1=1时候
${}会执行emp_id=1=1这句话,会报错
而#{}执行这句话时是 emp_id='1=1'。等于的是一个具体的东西,而不会受到=的影响
传入的类型
单个简单类型
如图,我们传入的是id这个一个单个的参数,怎么写呢?
首先用#{}会安全一点,其次,直接引入即可,这个key(识别参数的标识),可以随便写,不仅仅可以写#{id},也可以写#{a},随便写,但是为了规范,写为id较好,方便后续相关人员的识别。
多个简单类型
如图,我们的参数为String的name 和Double的salary
总共有三种引入方式
arg引入
前两种为按照顺序引入
从0开始的arg0 arg1。arg0对应的是第一个参数name,arg1对应的是第二个参数salary
param引入
从1开始的param1 param2。对应的为按照参数引入的顺序,比如我们这次引入了两个参数那么param1是name,param2是salary
@param定义
我们在mapper接口类里面的参数面前添加@param备注,备注里面的名字,即为我们要在xml文件里面写的引入的参数的名字
包装类
比如,这次,我们引入的参数的Employee类
、
而它有三个属性empId,empName以及empSalary
怎么引入参数呢?
只需要一个一个的对应即可,比如属性为empName,那么在参数引入里面直接写empName即可
Map参数
当,参数为map的时候怎么引入呢?
只需要设置Map类型,以及在test类里面map的每一个key也就是属性名 对上相应的具体的属性值即可
mapper里面写的接口如下
xml文件引入的如下
test类里面如下
import com.atguigu.mapper.EmployeeMapper;
import com.atguigu.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class MybatisTes {
@Test
public void test01() throws IOException {
//1.读取外部配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSessionFactory
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取SqlSession对象
SqlSession sqlSession = build.openSession();
//获取mapper 对象
EmployeeMapper m = sqlSession.getMapper(EmployeeMapper.class);
//管理资源或提交事务
Map<String,Object> param=new HashMap<>();
param.put("name","张三");
param.put("salary",8000.0);
int employee = m.insertEmpMap(param);
System.out.println("employee"+employee);
sqlSession.close();
}
}
返回值
单个简单类型
如图mapper里面返回为String类型
xml里如图
我们的result为string,String为包装数据类型,我们用它首字母的小写
也可以用具体的权限定符即java.long.String
当遇到基本数据类型比如int时候 我们写成_int
包装类型
权限定符
当返回的是包装类比如Employee时
我们可以使用全限定符,即具体的位置,比如com.Employee
但是这样太麻烦了,当然了,还有另外两种方式
使用typeAliases定义别名
在总配置文件里面
1.给类单独定义别名
<typeAliases>
<typeAlias type="com.atguigu.pojo.Employee" alias="ergouzi"/>
</typeAliases>
2.批量定义
<typeAliases>
批量给包下的东西其别名,别名就是类的缩写
<package name="com.atguigu.pojo"/>
</typeAliases>
使用@Alias注释
在目标返回值类型的类上面写上@Alias即可
mapper类型
mapper里面的配置如图,返回值为Map<String,Objece>
xml配置如下
<select id="selectEmpNameAndMaxSalary" resultType="map">
SELECT
emp_name 员工姓名,
emp_salary 员工工资,
(SELECT AVG(emp_salary) FROM t_emp) 部门平均工资
FROM t_emp WHERE emp_salary=(
SELECT MAX(emp_salary) FROM t_emp
)
</select>
接收的时候使用String,Object的Map类型接收即可
之后通过foreach语句,对该map的每一个键值对都进行遍历
五种标签的使用
当我们要动态的改变语句的时候,会发现传统的方法很难,我们一个一个语句写
但是当,用户要筛选省份,地址,等各种条件,我们总不能一种一种结果的去敲吧?
这样显然费时费力,所以我们就有了下面这些标签的出现。
where以及if标签
<select id="query" resultType="employee">
select * from t_emp
<where>
<if test="name != null">
emp_name=#{name}
</if>
<if test="salary !=null and salary > 100">
and emp_salary=#{salary}
</if>
</where>
</select>
对比这个代码以及原代码
select * from t_emp where emp_name=#{name} and emp_salary=#{salary}
当名字为空,不作为选择对象时,直接就舍弃了,当salary不达到筛选条件时,也直接不用。
那有人就问了,为什么要多加一个where,我只用这里面的if不行吗?
我们来试试看,当第一个if不成立,第二个if成立的时候,会发现,where and ...这句话有明显的语法错误
这怎么办啊?这怎么实现动态筛选啊
这时候就有where标签的出现了,省略写where,然后当有多余的and的时候会自动的进行过滤
set标签
当我们写动态的更新语句时,例如下面这句时
update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}
如果我设置empName不设为参考元素怎么办?我加入if?但是多一个逗号怎么处理?这时候就跟where标签出现处理and这个一样,set出现了,set标签可以省略set以及去掉多余的逗号
update t_emp
<set>
<if test="empName !=null">
emp_name=#{empName},
</if>
<if test="empSalary">
emp_salary=#{empSalary}
</if>
</set>
where emp_id=#{empId}
trim标签
trim标签,可以当作前两者的替换,只不过,写起来比较的多,在每句前面加上什么,去掉什么等等
<select id="querytrim" resultType="employee">
select * from t_emp
<!-- 前面加where 同时去掉多余的and or这种修饰符-->
<trim prefix="where" prefixOverrides="and|or">
<if test="name != null">
emp_name=#{name}
</if>
<!-- 如果传入属性就判断相等
如果不传入就不添加条件怎么弄呢?
怎么动态呢? 不推荐直接写符 写实体符号>
但是拼接符号 where等都不满足怎么办
添加where标签
1.不满足where时,自动删除where
2.多余and和or时候,自动去掉多余的or 和 and
-->
<if test="salary !=null and salary > 100">
and emp_salary=#{salary}
</if>
</trim>
</select>
如图,代替where标签,在trim里面备注,语句的前面要多一个where,同时,语句前面遇到and时候也要用prefixOverrides这个属性去掉
choose标签
相当于是switch case语句 当第一个条件成立,选第一个,全部行就选otherwise
<select id="queryChoose" resultType="employee">
select * from t_emp
where
<choose>
<when test="name != null">emp_name=#{name}</when>
<when test="salary !=null">emp_salary=#{salary}</when>
<otherwise>1=1</otherwise>
</choose>
</select>
foreach标签
当我们要插入多条语句,同时只想用一句话来写怎么办?
首先,输入一个集合类型,用xml语句进行批量的判断
比如下面这个insert语句
每一项之间加,为分隔符,批量的插入即
<insert id="insertBatch">
insert into t_emp(emp_name,emp_salary)
values
<foreach collection="list" separator="," item="itema">
(#{itema.empName},#{itema.empSalary})
</foreach>
</insert>
上面还只是一个语句的执行
当我们要批量update时,我们需要重写语句,怎么办?那就所有的foreach,记得每句加上个;哦
<update id="updateBatch">
<!-- 没地方遍历?整体遍历
如果一个标签设计多个语句,需要设计多个语句
?allowMultiQueries=true这样允许多语句执行
-->
<foreach collection="list" item="emp">
update t_emp set emp_name=#{emp.empName},emp_salary=#{emp.empSalary}
where emp_id=#{emp.empId};
</foreach>
</update>
Mybatis XML配置总结
ok,就讲这么多吧,我们再简单回顾一下
xml配置时需要使用接口权限定符
传入参数有一种,多种,包装类,Map参数
返回值类型有一种,包装类,Map类型
以及五种标签where,set,trim,choose,foreach等