前言:由于一段时间的外包生活,觉得自己技术开始落后,很多基础知识和底层已经遗忘殆尽。对所有的框架都所谓“知其然而不知所以然”,焦虑袭上心头的时候发现了拉勾高薪课程。目前学习完mybatis源码实现和spring手写ioc和aop,感受颇多。此文结合讲师的设计模式解析。自己总结并结合身边实例,输出自己学习内容。
相关拉勾课程输出笔记:模块一:房屋租赁流程理解设计模式(单例模式,代理模式,工厂模式) 专栏地址:拉勾专栏(持续更新…)
原始jdbc开发存在的问题如下:
使用端: 提供核心配置文件:
git clone -b master1 https://gitee.com/idse666666/lagou.git
封装为分别的dao方法
git clone -b master2 https://gitee.com/idse666666/lagou.git
git clone -b master3 https://gitee.com/idse666666/lagou.git
//例: <if test="p.depaCode != null and p.depaCode != ''"> and u.depa_code in <foreach collection="p.umsDepas" separator="," close=")" open="(" item="item" index="index"> #{item} </foreach> </if>
git clone -b master4 https://gitee.com/idse666666/lagou.git
二级缓存的原理和一级缓存原理一样,第一次查询,会将数据放入缓存中,然后第二次查询则会直接去缓存中取。但是一级缓存是基于sqlSession的,而二级缓存是基于mapper文件的namespace的,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace 相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域 中
二级缓存需要手动开启
//sqlMapConfig.xml中 <!--开启二级缓存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings> //mapper.xml中 <!--开启二级缓存--> <cache> </cache> //或者注解方式在mapper接口上方 @CacheNamespace //同时要注意实体类需要序列化 User implements Serializable
验证
二级缓存附加配置:mybatis中还可以配置userCache和flushCache等配置项
@CacheNamespace(implementation = RedisCache.class)
mybatis在四大组件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)处提供了简单易用的插 件扩展机制
实际上就是一个拦截器,可以自定义
源码 git clone -b master5 https://gitee.com/idse666666/lagou.git
git clone -b master5 https://gitee.com/idse666666/lagou.git
二级缓存>一级缓存>数据库
只有提交了SqlSession.commit(),后二级缓存才被真正写入
存储二级缓存对象的时候是放到了TransactionalCache.entriesToAddOnCommit这个map中,但是每次查询的时候是直接从TransactionalCache.delegate中去查询的,所以这个二级缓存查询数据库后,设置缓存值是没有立刻生效的,主要是因为直接存到 delegate 会导致脏数据问题
MyBatis二级缓存只适用于不常进行增、删、改的数据,比如国家行政区省市区街道数据。一但数据变更,MyBatis会清空缓存。因此二级缓存不适用于经常进行更新的数据。
源码 git clone -b master6 https://gitee.com/idse666666/lagou.git
git clone -b master6 https://gitee.com/idse666666/lagou.git
//1.返回resultMap <select id="findById" resultMap="userMap" > select * from user where id = #{id} </select> //2.设置fetchType="lazy,并指定子查询的全路径和参数值 <resultMap id="userMap" type="com.lagou.pojo.User"> <id property="id" column="id"></id> <result property="username" column="username"></result> <collection property="orderList" ofType="com.lagou.pojo.Order" select="com.lagou.mapper.IOrderMapper.findOrderByUid" column="id" fetchType="lazy"> <id property="id" column="oid"/> <result property="orderTime" column="ordertime"/> <result property="total" column="total"/> </collection> </resultMap> //3.子查询,需要id作为参数值 <select id="findOrderByUid" resultType="com.lagou.pojo.Order"> select * from orders where uid = #{uid}
<settings> <!--开启全局延迟加载功能--> <setting name="lazyLoadingEnabled" value="true"/> </settings>
git clone -b master7 https://gitee.com/idse666666/lagou.git
Builder模式的定义是"将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建,甚至只会构建产品的一个部分,直白来说,就是使用多个简单的对象一步一步构建成一个复杂的对象
SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的 MybatisMapConfig.xml 和所有的 Mapper.xml 文件,构建 Mybatis 运行的核心对象 Configuration 对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类
SqlSessionFactory,该Factory的openSession ()方法重载了很多个,分别支持autoCommit、Executor、Transaction等参数的输入,来构建核心的SqlSession对象。该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory 获得一个 Transaction 对象,然后通过 Transaction 获取一个 Executor 对象,最后通过configuration、Executor、是否autoCommit三个参数构建了 SqlSession
代理模式(Proxy Pattern):给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式 的英文叫做Proxy,它是一种对象结构型模式,代理模式分为静态代理和动态代理,
代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由Mybati s后台帮我们完成具体SQL的执行。当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理
git clone -b master8 https://gitee.com/idse666666/lagou.git
阶段一模块一源码(总):git clone -b master https://gitee.com/idse666666/lagou.git
git clone -b master https://gitee.com/idse666666/lagou.git