一、使用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片段
六、Mybatis的一级缓存和二级缓存
一级缓存(对每一个sqlSession的缓存)
一级缓存是针对每一个sqlSession进行缓存。每个sqlSession对象中使用Map存储一级缓存数据,
map中存储了sql执行查询的结果集(java对象)。
生命周期(先查找一级缓存数据,没有再查询数据库)
第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。
第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。
具体讲解:
- 一级缓存基于sqlSession默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互相不影响的。
- 一级缓存的作用域是SqlSession范围的,当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),
- 第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
- 需要注意的是,如果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中的二级缓存数据仍然存在。
生命周期(二级缓存 ———> 一级缓存——> 数据库)
- sqlsession1执行UserMapper下的查询用户请求先从二级缓存中查找有没有数据,如果没有就从数据库中查询,并且将查询到数据存储二级缓存中。
- 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整合第三方缓存框架 (待续)