- 自定义持久层框架
- jdbc 代码基础回顾
- 解决传统jdbc存在的问题
- 自定义持久层框架设计思路
- 使用端 --> 项目
- 自定义持久层框架本身
- mybatis 简介
- sqlMapConfig.
- 传统dao层开发方式
- dao层开发方式
- mybatis 外部properties 文件
- mybatis aliasType
- mapper.
- 动态sql
- mybatis复杂映射开发
- 一对一查询
- 一对多查询
- 多对多查询
- jdbc 代码基础回顾
- mybatis 注解开发
- 注解一对多
- 注解多对多
- mybatis 缓存
- 一级缓存
- 一级缓存分析
- 二级缓存
- redis-cache 分析
- mybatis的插件
- 以上组件的创建原理
- 自定义mybatis 插件
- mybatis的第三方插件
- mybatis架构原理
- mybatis传统方式源码分析
- Mapper代理方式
- 设计模式
- mybatis 执行流程图解
- mybatis延迟加载
- mybatis 动态sql相关类
- 常用的数据库连接池
- mybatis 查询数据量大的时候会造成oom 如何处理
2020年8月25日20:55:29
自定义持久层框架
- 持久层框架 是对jdbc 的封装, 并解决了jdbc存在的问题
jdbc 代码基础回顾
try{ Class.formName("com.mysql.jdbc.Driver"); connection = .....}cache(Exception e){ }
- 传统jdbc 存在 数据库配置信息存在硬编码问题 当更换数据库后需要再次对数据库驱动信息进行更改
- 频繁创建释放数据库连接
- sql语句 设置参数 获取结果集等参数均存在硬编码问题
- 手动封装结果集 较为繁琐
解决传统jdbc存在的问题
- 硬编码 --> 配置文件
- 硬编码 --> 连接池
- 手动封装结果集 --> 反射 内省
自定义持久层框架设计思路
使用端 --> 项目
- 引入自定义持久层jar
- 提供数据库配置信息及sql配置信息
- sql配置信息
- sql语句
- 参数类型
- 返回值类型
- sql配置信息
- 使用配置文件提供外上述两种配置信息
- sqlMapConfig.存入mapper.
- mapper.
自定义持久层框架本身
创建为项目工程,本质是对jdbc代码进行封装
-->
底层为传统的jdbc- 数据库配置信息
- sql 配置信息 占位符 参数 sql语句等
- 根据调用处传递的配置信息进行解析
- 加载配置文件
-->
以字节输入流的形式加载-->
存储在内存中 - 创建Resource类,getResourceAsStream(String path)
- 创建2个javaBean(容器对象),存放的是对配置文件解析出的内容
- Configuration:核心配置类: 存放sqlMapperConfig.
- MappedStrement:映射配置类:存放mapper.
- 解析配置文件:Dom4j
- 创建类:SqlSessionFactoryBuilder,存在方法:build(InputStream in)
- build方法实现逻辑:
- 使用dom4j解析配置文件,将解析结果封装到容器对象内
- 创建sqlSessionFactory对象,生产sqlSession(会话对象),避免重复创建连接
-->
工厂模式 降低耦合
- 创建sqlSessionFactory接口及实现类DefaultSqlSessionFactory
- openSession方法 : 创建 sqlSession对象
- 创建SqlSession 接口及实现类DefaultSqlSession 定义对数据库的CRUD方法
- selectList()
- selectOne()
- update()
- delete()
- 创建Excutor接口及实现类 SimpleExcutor 实现类
- query(Configuration conf,MappedStatement mapped,Object ...params):执行JDBC代码
- 加载配置文件
graph TBb("工程项目")subgraph 工程项目d("mapper.
mybatis
简介
持久层框架
基于
orm:Object Relation Mapping
实体类和数据库表建立映射关联关系半自动 可以对sql进行优化
hibernate -> 全自动
轻量级:启动的过程中需要的资源比较少
底层: 对jdbc执行代码 进行封装 规避硬编码,频繁开闭数据源
- property.driver 数据库驱动
- property.url 数据库地址 注意连接编码格式
- property.user 数据库连接用户名
- property.password 数据库连接用密码
mapper.resource
相对于类路径的引用mapper.url
完全限定资源定位符mapper.class
接口对应的全路径package.name
批量加载 保证映射文件与接口同包同名
传统dao层开发方式
dao层开发方式
mybatis 外部properties 文件
- 设置mybatis
- 在resources下创建外部配置文件 格式:
对象.属性=值
- 加载外部配置文件
- 在 configutation 后第一个节点之前 引入外部配置文件
<properties resource='路径'/>
- 在 configutation 后第一个节点之前 引入外部配置文件
mybatis aliasType
- 在mybatis 配置文件中的typeAliases 节点中设置
<typeAliases> <typeAlias type="pojo类路径的全限定名" alais="别名"></typeAlias></typeAliases>// 对于基础数据类型 mybatis 已定义了别名string ==> Stringlong ==> Longint ==> Integerdouble ==> Doubleboolean ==> Boolean
- 当存在多个pojo时不适用以上方法,采用package模式[批量起别名]
- package模式
不要单独指定alias属性 默认为类本身的类名,且不区分大小写
<typeAliases> <package name="pojo类所在包的全限定名"></typeAlias> // 不要单独指定alias属性 默认为类本身的类名,且不区分大小写</typeAliases>
- package模式
动态sqlif
标签 判断入参是否符合条件, 不符合不拼接where
标签 自动拼接where 同时去掉where后的第一个and 关键字foreach
标签collection
array 注意便携式不要使用#{}open
循环前追加close
循环结束后追加item
单次循环内的数据对象 生成的变量separator
前后循环数据之间的分隔符
sql
标签 抽取sql片段- id sql语句的标识
- 内容为具体的sql语句 可用于封装 分页 和 查询某张表时的前面部分
mybatis复杂映射开发
if
标签 判断入参是否符合条件, 不符合不拼接where
标签 自动拼接where 同时去掉where后的第一个and 关键字foreach
标签collection
array 注意便携式不要使用#{}open
循环前追加close
循环结束后追加item
单次循环内的数据对象 生成的变量separator
前后循环数据之间的分隔符
sql
标签 抽取sql片段- id sql语句的标识
- 内容为具体的sql语句 可用于封装 分页 和 查询某张表时的前面部分
sqlMapConfig.
<package name="与接口同包同名的包名"><package>
一对一查询
resultMap
手动配置实体属性与表字段的映射关系 可用于mybatis 的resultMMap- id
- type 按照封装对象的全路径
<resultMap id="orderMap" type="com.lagou.pojo.Order"> <result property="id" column="id"></result> <result property="orderTime" column="orderTime"></result> <result property="total" column="total"></result> <association property="user" javaType="com.lagou.pojo.User"> <result property="id" column="uid"></result> <result property="username" column="username"></result> </association></resultMap><!--resultMap:手动来配置实体属性与表字段的映射关系--><select id="findOrderAndUser" resultMap="orderMap"> select * from orders o,user u where o.uid = u.id</select>
一对多查询
<resultMap id="userMap" type="com.lagou.pojo.User"> <result property="id" column="uid"></result> <result property="username" column="username"></result> <collection property="orderList" ofType="com.lagou.pojo.Order"> <result property="id" column="id"></result> <result property="orderTime" column="orderTime"></result> <result property="total" column="total"></result> </collection> </resultMap> <select id="findAll" resultMap="userMap"> select * from user u left join orders o on u.id = o.uid </select>
多对多查询
- 查询用户的同时查询出用户的角色
<resultMap id="userRoleMap" type="com.lagou.pojo.User"> <result property="id" column="userid"></result> <result property="username" column="username"></result> <collection property="roleList" ofType="com.lagou.pojo.Role"> <result property="id" column="roleid"></result> <result property="roleName" column="roleName"></result> <result property="roleDesc" column="roleDesc"></result> </collection> </resultMap> <select id="findAllUserAndRole" resultMap="userRoleMap"> select * from user u left join sys_user_role ur on u.id = ur.userid left join sys_role r on r.id = ur.roleid </select>
mybatis 注解开发
使用注解开发 无需编写任何配置文件
- @Insert 增
- @Update 删
- @Delete 改
- @Select 查
- @Result 实现对结果集的封装 替代result标签节点
- @Results 替代resultMap 标签节点
- @One 替代单个pojo对象 替代 association 标签节点
- @Many 如果属性为集合时 则采用 此注解
注解一对多
@Results({ @Result(property = "id",column = "id"), @Result(property = "orderTime",column = "orderTime"), @Result(property = "total",column = "total"), @Result(property = "user",column = "uid",javaType = User.class, one=@One(select = "com.lagou.mapper.IUserMapper.findUserById"))})@Select("select * from orders")public List<Order> findOrderAndUser();
注解多对多
# IUserMapper //查询所有用户、同时查询每个用户关联的角色信息 @Select("select * from user") @Results({ @Result(property = "id",column = "id"), @Result(property = "username",column = "username"), @Result(property = "roleList",column = "id",javaType = List.class, many = @Many(select = "com.lagou.mapper.IRoleMapper.findRoleByUid")) }) public List<User> findAllUserAndRole();# IRoleMapper @Select("select * from sys_role r,sys_user_role ur where r.id = ur.roleid and ur.userid = #{uid}") public List<Role> findRoleByUid(Integer uid);
mybatis 缓存
一级缓存
使用同一个sqlSession 对象时,数据会被缓存
- 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从
数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。 - 如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的
一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 - 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直
接从缓存中获取用户信息
一级缓存分析
- 一级缓存到底是什么
底层是一个hashMap 参照上述流程图
- 一级缓存什么时候被创建
缓存key创建类: Excustor.class.createCacheKey()BaseExcutor.createCacheKey() //创建一级缓存的keyCacheKey.update() - updateList.add(configuration.getEnviroment().getId());
- 一级缓存的工作流程是怎样的
- 一级缓存的清空
sqlSession.close()
或者执行带有事务的操作 - 在分布式环境下也会存在
脏读
问题解决:禁用一级缓存或调整缓存为statement 级别
二级缓存
- 原理 类似 一级缓存
- 操作的sqlSession 执行了事务操作后 会清空二级缓存
- 一级缓存 默认开启
- 二级缓存需要手动配置开启
1.
- 二级缓存 缓存的不是对象 而是对象中的数据
- pojo类需要实现 Serializable 接口
- 二级缓存的存储机制是多样的,可能存储在硬盘上 或者内存中
- 当执行带有事务的操作后,二级缓存会被清空
- 当基于
- useCache 属性 false 禁用二级缓存 每次查询都发送sql去数据库查询 默认为true
注解形式:@select 注解之前添加 @Options(cache="false")
- flushCache 属性: 每次增删改操作后 清空缓存 默认true
二级缓存整合redis
PerpetualCache
是mybatis默认实现缓存功能的类- 二级缓存的底层数据结构 还是 HashMap
org.apache.ibatis.cache.impl.PerpetualCache --> private Map<Object, Object> cache = new HashMap()
- 指定mybatis二级缓存的实现类
在dao接口上添加注解 @CacheNamespace(implementation=PerpetualCache.class) PerpetualCache.class 更换为自定义缓存实现类如 : @CacheNamespace(implementation = RedisCache.class)
- 二级缓存 存在的问题
- 单服务器下 --> 没问题
- 分布式 --> 无法实现分布式缓存
- 分布式缓存技术
- redis 官方提供有mybatis-redis实现类
<dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-redis</artifactId> <version>1.0.0-beta2</version></dependency>配置配置文件 : redis.properties配置以下属性: host=localhost port=6379 connectionTimeout=5000 password=123456 database=0
- memcached
- ehcache
- 二级缓存存在的脏读问题分析
redis-cache 分析
- redis-cache 是如何存取值的
1. 必须实现mybatis 的cache 接口2. 使用 jedis.hget 进行取值
- redis-cache 使用的是哪种redis 数据结构
redis 的 hash 数据类型
mybatis的插件
- 一种形式的拓展点
- 增加灵活性
- 根据实际需求 自行拓展
- mybatis 的四大组件 及允许拦截的方法
- Executor 执行器
- update
- query
- commit
- rollback 等
- StatementHandler sql语法构建器
- prepare
- parameterize
- batch
- update
- query 等
- ParameterHandler 参数处理器
- getParameterObject
- setParameterObject
- ResultSetHandler 结果集处理器
- handleResultSets
- handleOutputParameters
- Executor 执行器
- 插件
拦截器
底层是对以上四个组件的拦截,采用动态代理实现
以上组件的创建原理
- 每个创建出来的对象不是直接返回的,而是
interceptorChain.pluginAll(parameterHandler)
- 获取到所有的Interceptor(拦截器)(插件需要实现的接口);调用
interceptor.plugin(target)
;返回target包装后的对象 - 插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行;
- 由于使用了jdk动态代理,那么就回去执行 invoke 方法,可以在拦截器 的前置和后置处理器内做相应的处理操作
@Intercepta({ @signature( type=Executor.class, method="query", args=(MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class} )})public class ExamplePlugin implements Interceptor{//省略逻辑}
自定义mybatis 插件
- 插件 --> 拦截器
org.apache.ibatis.plugin.Interceptor 类# 拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法Interceptor.intercept # 主要为了把当前的拦截器生成代理存到拦截器链中Interceptor.plugin# 获取配置文件的参数Interceptor.setProperties
- 定义
import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.plugin.*;import java.sql.Connection;import java.util.Properties;# 可以多个Signature @Intercepts({ @Signature(type= StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class}), @Signature(type= Executor.class,method = "prepare",args = {Connection.class,Integer.class})})public class MyPlugin implements Interceptor { /* 拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法 */ @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("对方法:" + invocation.getMethod().getName() + " 进行了增强...." ); return invocation.proceed(); //原方法执行 } /* 主要为了把当前的拦截器生成代理存到拦截器链中 */ @Override public Object plugin(Object target) { Object wrap = Plugin.wrap(target, this); return wrap; } /* 获取配置文件的参数 */ @Override public void setProperties(Properties properties) { System.out.println("获取到的配置文件的参数是:"+properties); }}
- 配置
<plugins> <plugin interceptor="com.lagou.plugin.MyPlugin"> <property name="name" value="tom"/> <!-- 设置参数 --> </plugin></plugins>
- 使用
1. MyPlugin.plugin --> MyPlugin.intercept --> MyPlugin.setProperties
mybatis的第三方插件
- PageHelper
- 导入maven 依赖
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>3.7.5</version></dependency>
- 在mybatis配置文件中配置PageHelper
在 plugins 节点内 添加 plugin 并设置属性 `property` 方言 `dialect` 值设 `mysql`<plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql"/></plugin>
- 通用 mapper
- 导入依赖
<dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.1.2</version></dependency>
- mybatis 的配置文件内配置 通用mapper 的plugin
<plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor"> <!--指定当前通用mapper接口使用的是哪一个--> <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/></plugin>
- 实体类设置关联
@Table(name = "user")public class User implements Serializable { @Id //对应的是注解id @GeneratedValue(strategy = GenerationType.IDENTITY) // @GeneratedValue strategy 设置主键的生成策略 // GenerationType.IDENTITY 底层必须支持自增长 // GenerationType.SEQUENCY 底层不支持自增长 // GenerationType.TABLE 从表中取值 生成主键 // GenerationType.AUTO 自动选择合适的生成主键 private Integer id; @Column(name="123") 当与表的字段不同时,采用@Column 保持同步 private String username; // Get Set 略}
- 创建dao接口 继承
tk.mybatis.mapper.common.Mapper
传入泛型
egg: public interface UserMapper extends Mapper<User> {}
- 使用
- 传统调用
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.
Example
方式调用
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.
随堂测试01 自定义持久层框架
自定义持久层框架IPersistence是如何解决JDBC存在的问题:() [多选题]
- [x] A. 用配置文件解决了硬编码问题
- [x] B.使用了C3P0连接池解决了频繁创建释放数据库连接问题
- [x] C.在simpleExecute中使用到了反射进行了参数的设置
- [x] D.在simpleExecute中使用了内省进行了返回结果集的封装
在进行自定义持久层框架IPersistence优化时,主要为了解决那些问题:() [多选题]
- [x] A.应用在Dao层,整个操作的模板代码重复
- [x] B.调用sqlSession方法时、参数statementId硬编码
- [ ] C.无法保证statementId的唯一性
- [ ] D.参数存在硬编码
下列关于Configuration及MappedStatement配置类,说法正确的是:() [多选题]
- [x] A.使用dom4j对sqlMapConfig.
- [ ] B.使用dom4j对mapper.标签的内容均对应一个MappedStatement对象[x] C.Configuration中包含了MappedStatement的引用[ ] D.MappedStatement对象对应Mapper.
原文转载:http://www.shaoqun.com/a/485790.html
三维度:https://www.ikjzd.com/w/1312
cima:https://www.ikjzd.com/w/1372
目录自定义持久层框架jdbc代码基础回顾解决传统jdbc存在的问题自定义持久层框架设计思路使用端-->项目自定义持久层框架本身mybatis简介sqlMapConfig.传统dao层开发方式dao层开发方式mybatis外部properties文件mybatisaliasTypemapper.动态sqlmybatis复杂映射开发一对一查询一对多查询多对多查询mybatis注解开发注解一对多注
乐一番:https://www.ikjzd.com/w/1562
c88是什么:https://www.ikjzd.com/w/1017
2020五一宁波奇异国门票多少钱?五一宁波奇e国门票价格?:http://tour.shaoqun.com/a/47141.html
Wish API更新:编辑SKU相关信息等:https://www.ikjzd.com/home/118633
2020香港五一天气怎么样?穿什么衣服好?:http://tour.shaoqun.com/a/45293.html
No comments:
Post a Comment