MyBatis核心知识及底层原理分析
知识整理,持续更新中… … 更多Java学习资源尽在B站账号: https://space.bilibili.com/591988762 欢迎个位小伙伴前来观看,更多优质学习资源持续更新中… 内容如有差错,欢迎留言一起讨论!!!
本文是对MyBatis核心知识进行的总结,适合有一定基础的小伙伴观看。
一、框架的概念
框架,就是软件的半成品,完成了软件开发过程中的通用操作,程序员只需很少或者不用进行加工就能够实现特定的功能,从而简化开发人员在软件开发中的步骤,提高开发效率。
二、Mybatis介绍
Mybatis是一个半自动 的ORM 框架。
ORM(Object Relational Mapping)对象关系映射,将Java中的一个对象与数据表中一行记录一一对应。
ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化。ORM 是面向对象程序设计语言和关系型数据库发展不同步时的解决方案,采用 ORM 框架后,应用程序不再直接访问底层数据库,而是以面向对象的方式来操作持久化对象,而ORM 框架则将这些面向对象的操作转换成底层的 SQL 操作。
通俗的说,ORM框架就是让程序与数据库脱离,通过操作实体进而间接操作数据库。
半自动化框架: 在原生的Java操作基础上进行封装,以简化开发而生,就MyBatis而言,对原生JDBC进行了进一步封装,对开发者而言只需要进行简单的配置就能实现很多功能,之所以说是半自动的,是因为Mybatis尽管做了很多优化封装,我们只需配置调用即可,但是对于SQL来说我们仍然需要自己进行编写,因此是半自动化的。
自动化框架: 对原生操作进行全封装,就Hibernate而言,不需要手动编写SQL,是动态生成的,只需要操作相应的对象即可,大大降低数据库与对象的耦合。可移植性Hibernate比MyBatis高。
优点:
- 与JDBC相比,减少了大量的代码量。
- 是最简单的持久层框架,简单易学。
- SQL代码从程序代码中彻底分离出来,可以重用。
- 提供XML标签,支持动态SQL。
- 提供映射标签,支持对象与数据库的ORM字段关系映射。
- 支持缓存、连接池、数据库移植… .
缺点:
- SQL语句编写工作量大,熟练度要高。
- 数据库移植性比较差,如果需要切换数据库的话,SQL语句会有很大的差异。
三、MyBatis使用中的细节
3.1 事务提交
在完成MyBatis初始化配置之后,及使用默认配置进行使用的时候,sqlSession默认不是自动提交事务。因此除查询操作外要手动提交事务。 如果要自动提交事务,那么在获取SqlSession的时候就要设置自动提交事务。
3.2 MyBatis创建对象的过程
- mybatis-config.xml 配置文件中配置数据库连接信息以及对应的mapper文件。
- 将mybatis-config.xnl 配置文件加载成输入流对象。
- 得到流对象后传给工厂建造者对象创建MyBatis的会话工厂。
- 通过会话工厂创建mybatis与数据库之间的会话对象。
- 通过会话对象调用getMapper方法获取对应的对象。
3.3 MyBatis条件参数细节
只有一个参数的情况:
- 如果操作方法只有一个简单类型或者字符串类型的参数,在Mapper配置中可以直接通过#{str}直接获取。
- 如果操作方法有一个对象类型的参数,在Mapper配置文件中可以直接通过#{attrName}获取指定对象的属性值(attrName必须是参数对象的属性)。
- 如果操作方法有一个Map类型的参数,在Mapper配置中可以直接通过#{key}获取key对应的value值。
多参数情况:
- 如果有多个参数,可以采用一下方式获取值:
- 使用#{agr0},#{agr1}… … 挨个取参数的值
- 使用#{parm1},#{parm2}… … 挨个取参数的值
- 给参数加上@Param(“别名”) 使用#{别名} 的方式获取指定参数的值
3.4 Mapper初始化
四、动态SQL
在多条件查询中,如果查询条件不确定,可以直接使用HashMap作为参数 优点: 无需单独定义传递查询条件的类 缺点: 当向Map中存放参数时,key必须与动态sql保持一致() public List<Member> searchMember(HashMap<String,Object> params);
mybatis在取值的时候就是通过key来进行映射的。 也可以定义专门用于存放查询条件的实体类存放参数 优点: 设置参数时无需关注属性名 缺点: 需要单独定义一个类来封装参数 public List<Member> searchMember(MemberSearchCondition params);
4.1 where标签和trim标签的区别
where格式:
where如果判定的第一个条件成立,会自动去掉第一个条件的and
<where>
<if test="gender != null">
and member_gender=#{gender}
</if>
<if test="minAge != null">
and member_age >= #{minAge}
</if>
<if test="maxAge != null">
and member_age <= #{maxAge}
</if>
<if test="city != null">
and member_city = #{city}
</if>
</where>
trim格式:
trim可以实现和where一样的效果,但是功能比where更强大。
trim可以自动添加前缀、后缀等。
prefix=“where”: 如果有条件成立就添加上前缀
prefixOverrides=“and | or”: 在条件成立的情况下,如果第一个语句有and或者or,直接去掉。
suffix=“order by member_age”: 添加后缀,比如这种条件。
<trim prefix="where" prefixOverrides="and | or" suffix="order by member_age">
<if test="gender != null">
and member_gender=#{gender}
</if>
<if test="minAge != null">
and member_age >= #{minAge}
</if>
<if test="maxAge != null">
and member_age <= #{maxAge}
</if>
<if test="city != null">
and member_city = #{city}
</if>
</trim>
foreach标签:
foreach标签用户遍历有多个参数的,一般都封装在集合中的。
collection=“list”: 指定的是集合的类型,使用的是别名。
item=“cityName”: 集合遍历出来的每一项。
separator=“,”: 每一项之间用什么拼接
open=“(” close=“)”: 多个项之间的开闭规则
<foreach collection="list" item="cityName" separator="," open="(" close=")">
#{cityName}
</foreach>
五、#{}和${}的区别
注意:模糊查询使用${}取值,与sql进行拼接时,即使只有一个参数也需要使用@Param注解声明参数的key(非String对象参数可以不用声明)
${}:表示获取参数,是先获取参数的值,然后拼接到SQL语句上,再进行编译,不能解决SQL注入问题。
#{}:也是获取参数,但是是先完成SQL的预编译处理,在预编译之后,再将获取的值设置到SQL中。可以防止SQL注入问题。使用#{}做模糊查询,只需要在外面拼接好字符串就可以了。
#{}是预编译处理,是占位符,${}是字符串替换、是拼接符。
六、 日志信息的级别
在使用日志框架输出日志信息的时候,会根据输出的日志信息的重要程度分为5个级别
级别 | 说明 |
---|
DEBUG | 输出调试信息 | INFO | 输出提示信息 | WARN | 输出警告信息 | ERROR | 一般性错误信息 | FATAL | 致命性错误信息 |
七、MyBatis缓存
MyBatis是基于JDBC的封装,使数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化:
- 在MyBatis引入缓存机制,用于提升MyBatis的检索效率
- 在MyBatis引入延迟加载机制,用于减少对数据库不必要的访问
7.1 一级缓存
一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配的缓存内存,无需手动开启可直接使用;多个SqlSession的缓存是不共享的。
特性:
1.如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存中存储的数据;
2.如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致;
实际上查询出来的对象是存在缓存中的,我们进行修改,修改的就是缓存中的引用。 3.当我们进行在查询时想要跳过缓存直接查询数据库,则可以通过sqlSession.clearCache();来清除当前SqlSession的缓存;
4.如果第一次查询之后第二查询之前,使用当前的sqlsession执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库。
7.2 一级缓存在应用中存在的问题
以在Servlet中使用MyBatis为例,两个servlet一个做查询,一个做修改,两个使用的是不同的SqlSession,查询的servlet第一次查询出数据之后,就存入缓存,后面就不会访问数据库,即使修改的Servlet修改之后,二者不是同一个SqlSession,也不会改变。要解决的办法,可以使用单例模式创建一个对象或者每次操作完就清空缓存。
7.3 二级缓存
二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的Sqlsession可以共享二级缓存;在应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享。
特性:
1.二级缓存默认没有开启,需要在mybatis-config.xml中的settings标签开启
2.二级缓存只能缓存实现序列化接口的对象
-
在mybatis-config.xml开启使用二级缓存 <settings>
<setting name="cacheEnabled" value="true"/>
</settings>
-
在需要使用二级缓存的Mapper文件中配置cache标签使用功能二级缓存 <cache/>
-
被缓存的实体类实现序列化接口 @Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Member implements Serializable {
private int memberId;
private String memberNick;
private String memberGender;
private int memberAge;
private String memberCity;
}
总结: 二级缓存是SqlSessionFactory级的缓存,只要使用的同一个SqlSessionFactory创建的SqlSession,查询的数据都能放到缓存中,要注意的是二级缓存默认没有开启,需要我们手动开启二级缓存,并且在需要实现二级缓存的类上实现序列化。
还有要注意的就是,二级缓存,我们在做查询的时候,不管有没有开启事务提交,都需要手动提交事务才能存入二级缓存中。 注意:二级缓存默认没有清除缓存的功能的,但是我们可以在操作SQL的时候控制使不使用缓存。
7.4 MyBatis的延迟加载
mybatis的延迟加载针对的是子查询,所谓延迟加载,就是在存在子查询的情况下,在执行了子查询(至少查询两次及以上)时,默认只执行第一次查询,当用到子查询时,才会触发子查询执行,如果无需使用子查询的结果,那么就不会执行子查询。
以上是MyBatis基础核心内容的总结,接下来是MyBatis框架底层原理及应用的分析,内容在更新中,敬请期待!!!
MyBatis框架底层分析
一、代理模式在MyBatis框架中的使用
二、工厂模式在MyBatis框架中的使用
三、Builder(建造者)模式在MyBatis框架中的使用
|