数据访问篇
流行词:顶层设计 Mybatis
参考代码:https://gitee.com/li-lixiang/learn-mybatis.git
在前面的blog中,已经实现学习了Spring源码,接下来学习当下数据库访问框架Mybatis。
目录
2、掌握Mybatis工作流程、架构分层与模块划分、缓存机制、底层工作原理与设计思想
顶层设计
数据访问篇主要从以下几个方面学习:
1、了解Mybatis、使用Mybatis
2、掌握Mybatis工作流程、架构分层与模块划分、缓存机制的底层工作原理与设计思想
3、Mybatis框架源码学习
4、手写Mybatis关键源码
1、了解Mybatis
why mybatis?
在Java程序里面去连接数据库,最原始的办法是使用JDBC的API。
//注册JDBC驱动
Class.forName("com.mysql.jdbc.Driver");
//打开连接
conn=DriverManager.getConnection(DB_URL,USER,PASSWORD);
//执行查询
stmt=conn.createStatement();
String sql="……;
ResultSetrs=stmt.executeQuery(sql);
//获取结果集
while(rs.next()){……}
更简单的方式:
1、Apache DbUtils https://commons.apache.org/proper/commons-dbutils/DbUtils解决的最核心的问题就是结果集的映射,可以把ResultSet封装成JavaBean。
2、Spring JDBC 对原生的JDBC进行了封装,并且给我们提供了一个模板方法JdbcTemplate,来简化我们对数据库的操作。
3、全自动Hibernate ORM框架,ORM的全拼是Object Relational Mapping 也就是对象与关系的映射
//创建对象
Useruser=newUser();
user.setPassword("123456");
user.setCellphone("18166669999");
user.setUsername("qingshan");
//获取加载配置管理类
Configuration configuration=new Configuration();
//不给参数就默认加载hibernate.cfg.xml文件,
configuration.configure();
//创建Session工厂对象
SessionFactory factory=configuration.buildSessionFactory();
//得到Session对象
Session session=factory.openSession();
//使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction=session.getTransaction();
//开启事务
transaction.begin();
//把对象添加到数据库中
session.save(user);
//提交事务
transaction.commit();
//关闭Session
session.close();
4、半自动Mybatis 主要解决的是SQL和对象的映射问题
MyBatis的核心特性:1、使用连接池对连接进行管理;2、SQL和代码分离,集中管理;3、结果集映射;4、参数映射和动态SQL;5、重复SQL的提取;6、缓存管理;7、插件机制。
使用Mybatis
编程式使用
代码说明:先引入mybatisjar包,创建一个全局配置文件,这里面是对MyBatis的核心行为的控制,比如mybatis-config.xml。
第二个就是我们的映射器文件,Mapper.xml。
再创建一个会话,SqlSession。
最后我们通过SqlSession接口上的方法,传入我们的StatementID来执行SQL。
2、掌握Mybatis工作流程、架构分层与模块划分、缓存机制、底层工作原理与设计思想
Mybatis工作流程
如下图:
说明:
1)在工程中配置;2)创建工厂;3)获得会话;4)获得执行器;
Mybatis架构分层与模块划分
Mybatis缓存机制
所有的缓存实现类总体上可分为三类:基本缓存、淘汰算法缓存、装饰器缓存。装饰器模式
缓存实现类 | 描述 | 作用 | 装饰条件 |
基本缓存 | 缓存基本实现类 | 默认是PerpetualCache,也可以自定义比如RedisCache、EhCache等,具备基本功能的缓存类 | 无 |
LruCache | LRU策略的缓存 | 当缓存到达上限时候,删除最近最少使用的缓存(LeastRecentlyUse) | eviction="LRU"(默认) |
FifoCache | FIFO策略的缓存 | 当缓存到达上限时候,删除最先入队的缓存 | eviction="FIFO" |
SoftCache WeakCache | 带清理策略的缓存 | 通过JVM的软引用和弱引用来实现缓存,当JVM内存不足时,会自动清理掉这些缓存,基于SoftReference和WeakReference | eviction="SOFT" eviction="WEAK" |
LoggingCache | 带日志功能的缓存 | 比如:输出缓存命中率 | 基本 |
SynchronizedCache | 同步缓存 | 基于synchronized关键字实现,解决并发问题 | 基本 |
BlockingCache | 阻塞缓存 | 通过在get/put方式中加锁,保证只有一个线程操作缓存,基于Java重入锁实现 | blocking=true |
SerializedCache | 支持序列化的缓存 | 将对象序列化以后存到缓存中,取出时反序列化 | readOnly=false(默认) |
ScheduledCache | 定时调度的缓存 | 在进行get/put/remove/getSize等操作前,判断缓存时间是否超过了设置的最长缓存时间(默认是一小时),如果是则清空缓存--即每隔一段时间清空一次缓存 | flushInterval不为空 |
TransactionalCache | 事务缓存 | 在二级缓存中使用,可一次存入多个缓存,移除多个缓存 | 在TransactionalCacheManager中用Map维护对应关系 |
思考:缓存对象在什么时候创建?什么情况下被装饰?我们要弄清楚这个问题,就必须要知道MyBatis的一级缓存和二级缓存的工作位置和工作方式的区别。
一级缓存
一级缓存(本地缓存)在会话(SqlSession)层面进行缓存的。MyBatis的一级缓存是默认开启的,不需要任何的配置。
sqlSessionFactory.openSession();不能共享本地缓存,会出现脏读。
【思考】一级缓存是默认开启的,怎么关闭一级缓存?
二级缓存
开启二级缓存的方法
第一步:在mybatis-config.xml中配置了(可以不配置,默认是true)
第二步:在Mapper.xml中配置<cache/>标签:
<!--声明这个namespace使用二级缓存-->
<cachetype="org.apache.ibatis.cache.impl.PerpetualCache"size="1024"
<!—最多缓存对象个数,默认1024-->
eviction="LRU"
<!—回收策略-->
flushInterval="120000"
<!—自动刷新时间ms,未配置时只有调用时刷新-->
readOnly="false"/>
<!—默认是false(安全),改为true可读写时,对象必须支持序列化-->
3、Mybatis框架源码学习
回顾mybatis的编程式使用过程:
InputStream inputStream=Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session=sqlSessionFactory.openSession();
BlogMapper mapper=session.getMapper(BlogMapper.class);
Blog blog=mapper.selectBlogById(1);
追踪源码,画出如下时序图:
4、手写Mybatis关键源码
参考代码:https://gitee.com/li-lixiang/learn-mybatis.git
小结:
使用到的设计模式:构造者模式、装饰器模式、工厂方法模式