Mybatis 笔记
- 什么是MyBatis ?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)
为数据库中的记录。
- 搭建步骤 (配置文件的使用)
i. 引入Mybatis坐标
ii. 创建实体类,写dao层接口
iii. 创建映射文件(也就是dao层接口的实现类)
iv. 创建Mybatis配置文件
iv.i. 配置mybatis的环境(数据源,事务机制类型,映射配置文件所在的位置)
v. 测试
v.i. 加载Mybatis配置文件
v.ii. 创建工厂构造器对象(SqlSessionFactoryBuilder),读取配置文件
v.iii. 构造工厂(SqlSessionFactory),通过工厂创建连接(SqlSession)
v.iv. 通过反射加载接口的字节码(getMapper),动态生成接口的实现类,并调用方法,释放资源
- 映射文件的标签属性说明
<select> 标签:
id 属性: 用于指定接口中的方法
SelectKey 标签 只能写在Insert 标签中
keyColumn 属性: 数据库表中的字段
keyProperty 属性: 实体类中的属性
resultType 属性: 返回时的属性
SQL语句: select last_insert_id(); 查询最后新增加的id
order 属性: AFTER 新增后执行查询id语句(默认值) BEFORE 先查找id再新增
resultType 属性: 用于指定结果集的类型.
resultMap 属性: 建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
还可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
resultMap 标签:
id 属性: 给定一个唯一标识,是给查询 select 标签引用用的。
type 属性:指定实体类的全限定类名
resultMap里面的标签:
id 标签: 用于指定主键字段
result标签: 用于指定非主键字段
这两个标签里面的属性:
column 属性: 用于指定数据库列名
property 属性: 用于指定实体类属性名称
parameterType 属性: 此属性可写可不写
用于指定传入参数的类型.
如果参数是一个对象那么需要写类的全限定类名
SQL语句中的#{} 字符: 它代表占位符,相当于jdbc所学的,都是用于执行语句时替换成实际的数据. 具体的数据是由#{}里面的内容决定的.
#{} 中内容的写法:
如果是基本类型可以随便写.(推荐传过来参数名是什么就写什么就好)
如果是一个对象那么需要采用ognl表达式#{对象.属性} 此种书写方法已过时,直接写传过来的属性名即可(必须)
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:
Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.属性}的方式
- 配置文件的标签属性说明
configuration
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
alias 属性: 自定义别名
type 属性: 类的全限定类名
--package (批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以))
name 属性: 包路径.
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
--transactionManager(事务管理)
--dataSource(数据源)
--mappers(映射器)
--mapper
resource 属性: 指定映射文件
class 属性: 使用注解形式,指定需要实现那个接口增强那些方法
--package
name 属性: 注册指定包下的全部接口(也就是让Mybatis通过反射Proxy.newProxyInstance(被代理类的类加载器,被代理类的字节码文件,代理策略))
- 说说 #{} 和 ${}有什么区别
#{} 是占位符的方式,在执行语句时会替换成实际的数据(是jdbc preparedStatement向占位符中设置值)
${} 是字符串拼接的方式, 可能会进行SQL注入 例如 select * from user -- where id = 1 SQL语句--后面都注释掉了
- Mybatis 的三种数据源
i. UNPOOLED 不使用连接池的数据源
ii. pooled 使用连接池的数据源
iii.jndi 使用jndi实现的数据源
- Mybatis 中连接的获取分析
当调用SqlSession.selectList() Mybatis底层会创建连接会操作数据库
- Mybatis 中事务的管理
每次必须手动提交,因为从连接池中取出连接会connection.setAutoCommit(false)
- Mybatis 动态SQL语句
<if>标签 : 从实体类中取值,使用不同的SQL语句查询.
比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件.这种多条件组合查询
test 属性: 表示如何判断. 例如: "属性 != null and 属性 != ''" 表示该属性!=null 并且 != 空字符串 会执行if里面的语句 否则不执行
<where>标签 : 如果where 标签里面的 if 标签里面的语句有一条可以执行,那么就会有where 语句 否则 没有where
例如: select * from user <where> <if test="name != null and name != ''"> name = #{name}</if> </where> 如果test为true
那么执行语句为 : select * from user where name = #{name} 否则 select * from user
<set>标签 update <set> <if test="username != null and username != ''">username = #{username},</if> <if test="name != null and name != ''">name = #{name},</if></set>
最后会自动去掉逗号
<foreach>标签 : 相当于 for 循环,用于遍历集合,使用需求 批量添加,批量删除等等
collection 属性: 代表要遍历的集合元素,直接参数名(属性名),注意编写是不要写#{}
open 属性: 代表语句开始部分
clone 属性: 代表结束部分
item 属性: 代表遍历集合的每个元素,生成的遍历名
sperator 属性: 代表分隔符
select * from user where id in(xx,xx,xx,xx)
例如: select * from user <where> <if test ="变量名 != null and 变量名.size() > 0">
<foreach collection ="变量名" open="id in(" clone=")" item="index" sperator=",">
#{index}
</foreach>
</if></where>
<sql>标签 : 主要用于抽取共性sql语句,进而达到高可用的目的,与之匹配的是<include>标签
id 属性: 唯一标识符
<include>标签 :
refid 属性: 引用(指定)sql标签的唯一标识符
- Mybatis 的多表查询之一对一
<result id="唯一标识符" type="类的全限定类名">
<id column="列名" property="类属性名称"/>
<result column="列名" property="类属性名称"/>
<association property="类属性名" javaType="属性(另一个对象)的全限定类名(别名)">
<id column="列名" property="(另一对象的)类属性名称"/>
<result column="列名" property="(另一个对象的)类属性名称"/>
</association>
</result>
- Mybatis 的多表查询之一对多
<result id="唯一标识符" type="类的全限定类名">
<id column="列名" property="类属性名称"/>
<result column="列名" property="类属性名称"/>
<!-- collection标签 : 用于建立一对多中集合属性的对应关系
property 属性: 用于指定类中的属性名
javaType 属性: 用于指定是什么集合类型
ofType 属性: 用于指定集合中都是什么类型(泛型)
例如: List<Account> accounts
-->
<collection property="accounts" javaType="list" ofType="account">
<id column="列名" property="(另一对象的)类属性名称"/>
<result column="列名" property="(另一个对象的)类属性名称"/>
</collection>
</result>
- association 和 collection 有什么区别?
association标签是用于建立一对一的映射关系
collection标签是用于建立一对多的映射关系
- Mybatis 的多表查询之多对多
其实就是两个一对多
例如: 用户表 用户角色表 角色表
用户相关信息 用户id,角色id 角色相关信息
一个用户可以有多个角色,一个角色可以有多个用户使用 - Mybatis 的策略
延迟加载策略(个人感觉用处不太大,如有想要了解的可以自行百度搜索)
一下为个人理解,如有不同理解可以留言评论,我会观看并和码友们一起交流
简单介绍一下, 也就是当开启延迟加载策略时,是什么时候需要数据什么时候查询数据库. 也称之为'懒加载' 大大提高数据库性能
坏处: 如果需要查询大批量数据时,有可能会造成用户等待时间过长,造成用户体验下降.
也不是完全没用. 也可以像阿里 每次数据库表访问不能级联3张表 也可以开启延迟加载策略
缓存策略
- Mybatis 的缓存(缓存策略)
分为一级缓存 和 二级缓存
一级缓存的范围: 只在一个SqlSession(也就是连接,一个连接缓存一次),连接不close和clearCache(清空本地缓存),一级缓存就一直存在,但是作用范围太小
证实一级缓存: 只需要通过同一个SqlSession调用两次相同的方法,并且开启日志,查看是否发送了两次SQL语句
问题: DML(增删改)操作时会清空一级缓存,这样做是为了解决脏读问题(也就是要保持缓存数据和数据库中的数据一致) 作用范围太小
二级缓存的范围: 多个SqlSession共同操作同一个本地二级缓存区域(也就是JVM开辟的一块Map数据类型),二级缓存跨SqlSession的.
开启二级缓存: 二级缓存配置文件中默认是开启的,但是不知道哪个映射文件需要缓存,需要在映射文件中添加<cache/>标签 开启二级缓存
标记那些SQL语句开启二级缓存: 需要在<select>标签 上的userCache属性值设置为true 表示当前标签开启二级缓存
警告: 此处经过测试 <select>标签上面userCache属性值设置为true与不设置没有任何区别,只需要在映射文件中配置<cache/>标签即可.
问题: 同上,最主要的是范围够了但是太占用jvm的运行内存空间
- 说说Mybatis 的缓存策略
一级缓存默认开启,但是作用范围只在一个SqlSession,作用范围太小
二级缓存 配置文件中默认开启,只需要在映射文件中添加<cache/>标签即可,但是它所采用的是jvm分配的map空间,如果项目缓存数据越来越多,太占用jvm资源,并且系统只分配固定的jvm空间
- Mybatis 注解式开发
增删改
@Insert("sql") @Delete("sql") @Update("sql") @Select("sql") CRUD
@MapKey、@Options、@SelelctKey、@Param、@InsertProvider、@UpdateProvider、@DeleteProvider
@SelectProvider: 实现动态 SQL 映射
结果集映射
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@ResultType、@ConstructorArgs、@Arg、@TypeDiscriminator、@Case
缓存
@CacheNamespace:实现注解二级缓存的使用
@Property、@CacheNamespaceRef、@Flush
基本上使用率不太,Mybatis 好不容易把持久层做到了解耦效果,如果@Select 配合@Result 和 @Results 封装结果集这不又耦合了么,这是其一
其二: 如果是复杂对象映射关系呢? 还是推荐使用映射文件
如果对Mybatis注解开发感兴趣可以访问 [Mybatis注解开发](http://www.tianshouzhi.com/api/tutorials/mybatis/393)
Mybatis 面试题可以参考 [Mybatis相关面试题](https://blog.csdn.net/a745233700/article/details/80977133)
这两篇文章都挺不错的