什么是MyBatis
半自动ORM框架
XML
- MyBatis是一个半自动ORM框架
- 最主要的功能就是为了避免大量的JDBC链接代码的使用,如加载驱动,创建链接,创建statement
- 强大的XML文档解析能力
- 可以通过XML映射数据库记录与model层,无需手动,即可自动获取JDBC结果集并映射到指定model
- 通过XML还可以统一管理SQL
MyBatis的优点
避免连接代码的重复使用
xml动态拼接SQL
SQL统一管理
- 无需大量重复冗余的JDBC连接代码
- 通过XML映射后,即可自动获取JDBC的结果集,且封装制定model
- XML中有还具有强大的动态拼接SQL功能,如我们常见的 标签
</foreach> </if test=""> </SQL>
- XML统一管理SQL,避免SQL与程序代码耦合
- 与SpringFramework具有很好的继承
- 很好的与各种数据库兼容,JDBC支持的MyBatis都支持
MyBatis的缺点
- SQL依赖数据库,数据库移植性差
- 因为是半自动ORM框架 所以还是会手动写一些SQL语句
- Hibenate全自动ORM框架,无特定SQL书写
- 需大量手动SQL编写,对开发人员SQL功底有一定要求
- 同样因为半自动
MyBatis与Hibernate的区别
- 半自动,全自动
- 半自动的需要手动写SQL,全自动的无需
- 当然现在常用的MyBatis-Plus则是全自动ORM,现在也有自动生成常用SQL的能力,应对一般单表需求 ,或简单无需连表查询的多表需求完全不在话下
- Hibernate同样也有HQL
- MyBatis SQL关联性强,不易移植,Hibernate强调SQL无关性,易移植
#{}与${}的区别
#{}是预编译 会转换成?,${}则是字符替换
使用#{}的好处
#{}可以有效防止SQL注入,提高安全性
SQL注入是啥
select * from student where id = ${}
${} = “1 or id !=1”
原本只能查出id = 1 的student数据,现在会全部返回,更危险的像使用delete
数据库table字段名与代码中model字段名不同,如何关联
<resultMap id="">
<resultMap property="">
模糊查询
select * from student where name like concat('%', #{name}, '%')
Mapper接口方法能否重载?
不能重载
- Mapper接口是没有实现类的,他是通过代理模式,根据Mapper+方法名 全限定名,
如com.vission.Mapper.xxMapper.findAll;
动态生成proxy类,再执行根据指定namespace的xml对应方法名id里的SQL,如果全限定名重合,无法通过常规的入参变量区分,将无法生成proxy类
MyBatis的Mapper接口使用要求
- Mapper接口的方法名 需要与XML每个sql的id相同
- Mapper接口的入参需要与parameterType类型一样
- Mapper接口的出参需要与resultType类型一样
- XML中的namespace为与Mapper接口的类路径
Mapper.xml id能否相同?
同namespace下不能相同
- MyBatis通过namespact+id关联接口方法,重合了就没法关联了
MyBatis如何分页
- 逻辑分页
- MyBatis自带的RowBouds,全量加载再进行分页查询,JDBC虽然有优化,但是不推荐使用,数据量大的查询会对DB产生压力
- 物理分页
- 直接SQL使用limit关键字
- 实现MyBatis的Interceptor,全局拦截SQL拼接limit关键字
- 使用现成框架
PageHelper
插件分页- MyBatis-Plus集成了分页插件IPage
MyBatis将SQL查询结果映射为指定Model
- resultMap
- SQL
as
别名- 找到对应映射关系通过反射实现
MyBatis如何实现批量插入
MyBatis-Plus,重写DefaultSqlInjector,添加InsertBatchSomeColumn,并自定义BaseMapper继承BaseMapper,添加insertBatchSomeColumn方法
MyBatis,批量提交单条插入方法
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch); nameMapper Mapper = sqlsession.getMapper(nameMapper.class); for (string name: names) { Mapper.insertname(name); } sqlsession.commit();
* insert如何获取自动生成的主键
insert标签方法默认返回插入行数
使用
<insert>
标签的usegeneratedkeys属性 可以将生成的key设置回入参对象中keyproperty指定赋值属性
<insert id=”insert” usegeneratedkeys=”true” keyproperty=”id”></insert>
如何再Mapper中传递多个入参
@param
List<String> selectNames(@param("name") name,@param("deleted")deleted);
<select id = 'selectNames'> select * from students where name like contact("%",#{name},"%") and deleted = #{deleted} </select>
MyBatis中XML动态SQL,使用哪些标签
trim
- prefix 前缀
- suffix 后缀
- prefixOverrides 删除前缀
- suffixOverrides 删除后缀
where
- 包装where 条件查询的sql主要用于去除多余的and关键字
set
- 用于update语句替代sql中set关键字
foreach
- collection 循环的集合
- item 单条实例
- separator 分隔填充
<where> <foreach collection="queryList" item="employeeQuery" separator="or"> <trim prefix="(" suffix=")"> <include refid="emp_query_list_condition"/> </trim> </foreach> </where>
if
- test = “”
choose
- 配合when otherwise使用
when
otherwise
<choose> <when test = ""></when> <when test = ""></when> <otherwise></otherwise> </choose>
bind 没用过
常用的MyBatis标签
<resultMap>
<include>
<sql>
MyBatis一对一
<resultMap type="" id = ""> <id property = "" column = ""> <result property = "" column = ""> <association property = "" javaType = ""> <id property = "" column = ""> <result property = "" column = ""> </association> </resultMap>
MyBatis一对多
<resultMap type="" id = ""> <id property = "" column = ""> <result property = "" column = ""> <collection property = "" ofType=""> <id property = "" column = ""/> <result property = "" column = ""/> </collection> </resultMap>
MyBatis查询结果能否延迟加载
MyBatis支持association与collection关联查询的延迟加载
全局
application.yml => lazyLoadingEnabled = true|false
局部
<!--fetchType="lazy" 懒加载策略 fetchType="eager" ⽴即加载策略--> <association property="" column="" javaType = "" select = "" fetchType = "lazy|eager"/> <collection property="" column = "" ofType = "" select = "" fetchType = "lazy|eager"/>
通过代理模式,拦截,当调用model.getXXX(); 则再去DB执行select的方法 几乎所有的包括Hibernate 凡是支持懒加载的原理都是一样的
实际工作中我确实没用过,甚至同事们的代码也没看到过,难道是因为在dao层model查完都会转为DTO返回去?
Mapper的使用的方式
无Spring
MyBatis-config.xml
<Mappers> <Mapper resource="Mapper/XXX.xml"/> </Mappers>
Main.java
public static void main(){ InputStream resourceAsStream = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); }
Spring
包扫描
@MapperScan("XXX")
Main.java
public static void main(){ //伪代码 Application.getBean(Mappper.class) }
MyBatis的接口绑定
XML
- namespace
注解
- @Select
- @Update
- @Delect
- @Insert
- 等
@Select("select * from user where name = #{name}") User findUserByName(@Param("name") String name);
MyBatis插件实现原理
实现MyBatis的Interceptor接口,通过拦截器全局拼接sql,例如PageHelp就是拼接的limt关键字
MyBatis的缓存机制
不太懂