Mybatis的核心问题详解

一、使用jdbc开发时,和mybatis相比的不足 


1,数据库连接,使用时就创建,不使用就释放,对数据库进行频繁连接开关和关闭,造成数据库资源浪费,影响数据库的性能 
解决:使用数据库连接池管理数据库的连接 
2,sql语句使用硬编码在java程序中,修改sql语句,就需要重新编译java代码,不利于系统维护 
解决:把sql语句放在xml配置文件中,修改sql语句也不需要重新编译java代码 
3,向预编译语句PreparedStatement中设置参数,对占位符位置和设置参数值,硬编码,修改sql语句也不需要重新编译java代码 
解决:把sql语句和占位符设置参数值放在xml配置文件中 
4,从result中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码 
解决:将查询的结果集,自动映射成 java对象

 

二、 mybatis框架,是一个持久层框架,是apache下的顶级项目

   
mybatis让程序员将主要精力放在sql上,通过mytabis提供的映射方式,自动生成满足需要的sql语句 
mybatis可以向PreparedStatement中输入参数自动进行输入映射,将查询结果集灵活的映射成Java对象(输出映射),输入映射和输出映射这是mybatis的核心 
mybatis框架执行流程图 
这里写图片描述 
三 mybatis的工作环境搭建和架构示意图 
这里写图片描述

注意点:

(1)

详情:https://blog.csdn.net/jaryle/article/details/51228751

 

三、mybatis利用mapper代理开发dao(重点掌握) 


          mapper代理开发,就不需要接口的实现类,只需要接口UserMapper.java和映射文件UserMapper.xml就可以了,但是遵循一定的开发规范: 
1,在UserMapper.xml文件中namespace等于UserMapper接口地址 
这里写图片描述 
2,UserMapper.java接口中的方法名要和UserMapper.xml中的statement的id一致 
3,UserMapper.java接口中的方法输入参数要和UserMapper.xml中的statement的parameterType指定的类型一致 
4,UserMapper.java接口中的方法的返回值类型要和UserMapper.xml中的statement的resultType指定的类型一致

 

四、mybatis的核心输入映射和输出映射开始:

输入映射 (将传入参数进行封装,定义包装类型pojo)


通过parameterType指定输入参数类型,类型可以是简单类型、hashmap、pojo的包装类型 
1,传递pojo的包装对象 
(1)需求 
完成用户信息的综合查询,需要传入查询条件复杂(可能包括用户信息,商品信息,商品订单等),这样靠一个parameterType只能传入一个输入参数,所有需要pojo的包装类型来实现 
(2)定义包装类型pojo 
针对上面的需求,在包装类型的pojo中把这些复杂的查询条件包装进去,定义包装类UserQueryVo,把需要查询的条件全部定义在里面 
这里写图片描述

输出映射 


1,resultType 
使用resultType进行输出映射时,只有查询输出结果列名和pojo中的属性名一致才可以,映射成功 
如果查询出来的列名和pojo中的属性名没有一个一致的,就不会创建pojo对象 
如果查询出来的列名和pojo中的属性名有一个一致,就会创建pojo对象 
输出pojo对象和pojo列表 
不管是输出的pojo单个对象还是一个列表(list中包含pojo),在mapper.xml中resultType指定的类型是一样的 
在mapper.java指定的方法返回值类型不一样: 
(1)输出单个pojo对象,方法返回值是个单个对象类型 
(2)输出pojo对象list,方法返回值就是list对象类型 
在动态代理对象中,是根据mapper方法的返回值类型来确定是调用selectOne(返回单个对象)还是selectList(返回集合对象) 
2,resultMap 
使用resultMap进行映射时,查询结果列名和pojo的属性名不一致时,resultMap会对列名和pojo属性名进行映射,保证其成功映射 

五、mybatis的动态sql和sql片段

动态sql 


     mybatis核心就是对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接和组装。 
需求:用户信息查询的综合信息需要使用动态sql 
对查询条件进行判断,如果出入参数不为空,才进行拼接 
这里写图片描述

sql片段 


需求:将上面的动态sql(重复的sql语句)抽取出来做成一个片段方便其他statement语句重复使用sql片段 
定义sql片段 
使用sql片段 
这里写图片描述

 

六、Mybatis的一级缓存和二级缓存

 

一级缓存(对每一个sqlSession的缓存

一级缓存是针对每一个sqlSession进行缓存。每个sqlSession对象中使用Map存储一级缓存数据, 
map中存储了sql执行查询的结果集(java对象)。

生命周期(先查找一级缓存数据,没有再查询数据库

第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。 
第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。 

 

具体讲解:

  1. 一级缓存基于sqlSession默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互相不影响的。
  2. 一级缓存的作用域是SqlSession范围的,当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),
  3. 第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
  4. 需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。

小结:

1、如果 执行sqlsession的添加、修改、删除等操作,会执行commit,最终会清空缓存。保证缓存中存储的是最新的信息,避免出现脏读现象

2、sqlSession对象销毁其中一级缓存数据不存在了

3、sqlSession与SqlSession之间的一级缓存互相不影响


二级缓存(针对每个mapper相同的namespace进行缓存

     二级缓存是mapper级别的缓存。使用二级缓存时,多个SqlSession使用同一个Mapper的sql语句去操作数据库,得到的数据会存在二级缓存区域,它同样是使用HashMap进行数据存储。相比一级缓存SqlSession,二级缓存的范围更大多个Sqlsession可以共用二级缓存,二级缓存是跨SqlSession的

       二级缓存的作用域是mapper的同一个namespace。不同的sqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。


每个SqlSession都可以访问到二级缓存中的数据,sqlsession对象销毁mapper中的二级缓存数据仍然存在

生命周期(二级缓存 ———> 一级缓存——> 数据库)

  1. sqlsession1执行UserMapper下的查询用户请求先从二级缓存中查找有没有数据,如果没有就从数据库中查询,并且将查询到数据存储二级缓存中。
  2. sqlsession2执行UserMapper下的同一个查询用户请求,先从二级缓存中查找有没有数据,如果有就从二级缓存中查询数据,返回。

如果有一个sqlsession3执行UserMapper下添加、修改、删除语句,执行commit操作后,将UserMapper下的所有缓存数据全部清空。

二级缓存需要手动打开

1. Mybatis内部二级缓存的配置

要使用Mybatis的二级缓存,需要对Mybatis进行配置,配置分三步

  • Mybatis全局配置中启用二级缓存配置
<setting name="cacheEnabled" value="true"/>
  • 在对应的Mapper.xml中配置cache节点
<mapper namespace="userMapper">
    <cache />
    <result ... />
    <select ... />
</mapper>
  • 在对应的select查询节点中添加useCache=true
<select id="findUserById" parameterType="int" resultMap="user" useCache="true">
    select * from users where id=#{id};
</select>

        二级缓存是跨sqlsession的是基于mapper级别的缓存,sqlsession可以使用多个对象,多个对象必须要访问同一个mapper下的sql语句 。

七、内部二级缓存的实现详解

     Mybatis内部二级缓存的设计及工作模式(静态代理模式):

       mybatis的二级缓存是通过CacheExecutor实现的。CacheExecutor其实是Executor的代理对象。所有的查询操作,在CacheExecutor中都会先匹配缓存中是否存在,不存在则查询数据库。

          在CachingExecutor的所有操作都是通过调用内部的delegate对象执行的。缓存只应用于查询

八、二级缓存存在的问题(集群分布式存在问题,可以采用第三方分布式缓存)

             Mybatis默认二级缓存的实现在集群或者分布式部署下是有问题的,Mybatis默认缓存只在当节点内有效,并且对缓存的失效操作无法同步的其他节点。需要整合第三方分布式缓存(redis、memcache等)实现,如ehcache或者自定义实现。   

九、mybatis整合第三方缓存框架 (待续)

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值