MABITIS
MABITIS框架知识点
一部分:框架
MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀 持久层框架。
MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
1. SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。(mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。
此文件需要在SqlMapConfig.xml中加载。)
2通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂。由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
3 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mappedstatement的id。
6 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对 preparedStatement设置参数。
7 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果 的解析处理过程。
二部分:Mapper代理开发
1、用mapper代理开发时只要写2个:
(1)mapper.xml
(2)mapper接口
2、Mapper接口开发需要遵循以下规范:
(1)Mapper.xml文件中的namespace与mapper接口的类路径相同。
(2)Mapper接口方法名和Mapper.xml中定义的每个statement的id相同。
(3)Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
(4)Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
3、代理对象内部调用selectOne()和selectList()
如果mapper对象返回单个pojo对象(非集合对象)代理对象内部通过selectOne查询数据库,如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
4、mapper接口中的方法参数只能有一个是否影响系统开发,mapper接口方法参数只能有一个,
系统是否不利于维护?
回答:系统框架中,dao层的代码是被业务层公用的。mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
<SqlMapConfig.xml全局配置文件解析见文档>
三部分:动态sql
OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行导航。
mybatis 动态SQL 语句主要有以下几类: if choose trim where set foreach
if: 提供了title参数,那么就要满足title=#{title}
choose :所有的when和otherwise条件中,只有一个会输出
trim : 在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀
prefix:前缀 prefixoverride:去掉第一个 suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样) suffix:后缀
where : (主要是用来简化sql语句中where条件判断的,能智能的处理 and or 条件)
set : 主要用于更新时, 如果包含的语句是以逗号结束的话将会把该逗号忽略
<select id="dynamicForeachTest" resultType="com.mybatis.entity.User">
select * from t_user where id in
<foreach collection="list" index="index" item="item" open="(" separator=","
close=")">
#{item}
</foreach>
</select>
item表示集合中每一个元素进行迭代时的别名。index指定一个名字,用于表示在迭代过程中,每次迭代到的位置。
open表示该语句以什么开始。separator表示在每次进行迭代之间以什么符号作为分隔符。
close表示以什么结束。
四部分 延迟加载
需求:如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
**延迟加载**:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
使用association实现延迟加载
需要定义两个mapper的方法对应的statement
<!-- 查询订单关联查询用户,用户信息按需延迟加载 的 resultMap定义 --> 第二部:查询订单,关联用户
<resultMap type="com.mybatis.entity.Orders" id="ordersUserLazyLoading">
<!--对订单信息进行映射配置 -->
<id column="id" property="id"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<!-- 实现对用户信息进行延迟加载 select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
column:订单信息中关联用户信息查询的列,是user_id
<association property="user" javaType="com.mybatis.entity.User" select="findUserById" column="user_id"/>
</resultMap>
<!-- 查询订单关联用户,用户信息延迟加载 --> 第一步:查询订单,返回resultMap="ordersUserLazyLoading
<select id="findOrdersUserLazyLoading" resultMap="ordersUserLazyLoading">
select * from orders
</select>
<!-- 根据Id查询用户,用于测试延迟加载 --> 第三部,根据关联字段 user_id,查询用户信息
<select id="findUserById" parameterType="int" resultType="com.mybatis.entity.User" >
select * from t_user where id=#{id}
</select>
延迟加载在mybatis核心配置文件sqlMapConfig.xml中的配置
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
mybatis核心配置文件中配置:
lazyLoadingEnabled:全局性设置懒加载。如果设为'false'(默认),则所有相关联的都会被初始化加载。
aggressiveLazyLoading:true(默认)懒加载的对象可能被任何懒属性全部加载。false,每个属性都按需加载。
延迟加载的原理:
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好
的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
五部分 查询缓存
查询缓存:mybatis提供查询缓存(一级缓存和二级缓存),用于减轻数据压力,提高数据库性能。
一级缓存(默认支持)
一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap),用于存储缓存数据。不同的sqlSession之间的缓存区域(HashMap)是互不影响的。
***如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
(1). 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,然后将用户信息存储到一级缓存中。
(2). 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
(3). 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
二级缓存
(1). 首先开启mybatis的二级缓存。
(2). sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
(3). 如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
(4). sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace
如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。
开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存
<setting name="cacheEnabled" value="true"/>
禁用二级缓存
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
刷新缓存
设置statement配置中的flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
<insert id="insertUser" parameterType="com.mybaits.entity.User" flushCache="true">
Mybatis Cache参数
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false
二级缓存应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
7、二级缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级
缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解
决此类问题需要在业务层根据需求对数据有针对性缓存。
六部分高级映射
例:业务关系
一对一查询 :创建包装类VO
需求:查询订单信息,关联查询用户信息,resultType实现(resultMapXXX)
SELECT t1.*, t2.username,t2.sex,t2.address FROM orders t1,t_user t2 WHERE t1.user_id=t2.id
步骤: 创建各个实体类;
创建一个包装类,将查询到的信息可以全部映射到此类:OrdersCustom.java (public class OrdersCustom extends Orders,所有订单信息和部分用户信息)
创建OrdersCustomMapper.java接口,public interface OrdersCustomMapper {
创建OrdersCustomMapper.xml和上面对应的接口名称一致,以便通过mapper接口加载配置文件
<!-- 查询订单,关联查询用户信息 -->
<select id="findOrdersUser" resultType="com.mybatis.entity.OrdersCustom">
<!sql语句 ; 确定查询的主表:订单表,确定查询的关联表:用户表。>
select t1.*,t2.username,t2.sex,t2.address from orders t1,t_user t2
where t1.user_id = t2.id
</select>
一对多查询 : mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
需求:查询订单(关联用户)及订单明细;
在orders.java类中添加List<orderDetail> orderDetails属性(上面实体已添加)。最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中.
在ordersCustomMapper.xml中添加如下代码
<!-- 查询订单(关联用户)及订单明细的resultMap -->
<resultMap type="com.mybatis.entity.Orders" id="ordersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<collection property="orderdetails" ofType="com.mybatis.entity.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
</collection>
</resultMap>
、statement定义
<!-- 查询订单关联查询用户及订单明细 -->
<select id="findOrdersAndOrderDetailResultMap" resultMap="ordersAndOrderDetailResultMap">
SELECT t1.*,t2.username,t2.sex,t2.address,t3.id orderdetail_id,t3.items_id,
t3.items_num,t3.orders_id FROM orders t1,t_user t2,orderdetail t3
WHERE t1.user_id = t2.id AND t3.orders_id=t1.id
</select>
、在OrdersCustomMapper.java接口类中添加一个方法
/**查询订单(关联用户)以及订单明细*/
public List<OrderDetail>findOrdersAndOrderDetailResultMap();
多对多
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
(1)association:
作用:将关联查询信息映射到一个pojo对象中。
场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据
对结果集查询遍历的需要选择使用resultType还是resultMap。
(2)collection:
作用:将关联查询信息映射到一个list集合中。
场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的
菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用resultType无法将查询结果映射到list集合中。
SpRING+SPEINGMVC+MABATIS 框架
- Spring用了那些设计模式?Spring注入bean的方式?对SpringIOC和SpringAOP的理解?
工厂设计模式(BeanFactory 、ApplicationContext)/ 代理设计模式(AOP)/ 单例设计模式(bean) /模板设计 (jdbcTemplate) /适配器模式(AOP中的增强,MVC) /包装器 /观察者…
Spring 通过XML配置或者注解的方式来管理bean .
IoC是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。AOP(面向方面编程),代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
- Spring事务隔离级别和传播机制
事务的隔离级别就是为了解决脏读、幻读、不可重复读等问题,包括DEFAULT /READ_UNCOMMITTED /READ_COMMITED /REPEATABLE_READ /SERLALIZABLE ,传播机制包括 PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_SUPPORTS…
- Mybatis的缓存机制(一级缓存和二级缓存),mybatis的mapper文件中的#和$的区别
一级缓存是sqlSession 级别的,一级缓存默认开启;二级缓存是userMapper级别的,二级缓存需要开启,查询的实时性不高。#会给参数加上“”,防止sql注入。
- SpringMVC的流程
DispatcherServlet接收到请求后,根据对应配置文件中配置的处理器映射,找到对应的处理器映射项(HandlerMapping),根据配置的映射规则,找到对应的处理器(Handler)。接着再通过相应的HandlerAdapter处理该Handler
HandlerAdapter在对Handler进行处理之后会返 回一个ModelAndView传给DispatcherServlet, ModelAndView包含了处理结果的视图和视图中要使用的数据。
DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewReslover(视图解析器),根据视图解析器的配置,DispatcherServlet将视图要显示的数据传给对应的视图,最后给浏览器构造一个HTTP响应。
- Spring和SpringBoot的区别?
- 对springBoot的理解
来简化新Spring应用的初始搭建以及开发过程, 。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
- RPC框架有哪些,他们的区别?
Dubbo
- Dubbo的使用和理解
- SpringCloud的使用和理解