kuriyame

mybatis笔记

JDBC 问题分析:
1、数据库配置信息存在硬编码问题
2、频繁创建释放数据库连接
3、sql语句 设置参数 获取结果集 存在硬编码问题
4、手动封装返回结果集 较为繁琐

解决思路:
1、数据库信息 请求配置文件
2、使用连接池
3、sql语句 设置参数 获取结果集 使用配置文件
4、使用反射 内省

自定义持久层框架设计思路:
项目:引入自定义持久层框架jar包
提供两部分配置信息:数据库配置信息、sql配置信息:sql语句 参数类型 返回值类型
(1)sqlMapConfig.xml 存放数据库配置信息
(2)mapper.xml 存放sql信息

自定义持久层框架本身: 本质就是对JDBC 进行封装
(1)加载配置文件 根据配置文件的路径加,加载配置文件成字节输入流,存储在内存中
创建Resources类 方法:InputSteam getResourceAsSteam(String path)

(2)创建两个javaBean(容器对象): 存放的就是对配置文件解析出来的内容
configuration:核心配置类 存放sqlMapConfig.xml解析出来的内容
MappedStatement映射配置类: 存放mapper.xml解析出来的内容
(3)解析配置文件 dom4j
创建SqlSessionFactoryBuilder 方法 build (inputSteam in)
第一:使用dom4j解析配置文件 , 将解析出来的内容 封装到容器对象中
第二:创建SqlSessionFactory 对象 生产 sqlSession 会对对象 (工厂模式) 降低程度的耦合 根据不同的需求 产生不同的对象
(4)创建SqlSessionFactory 接口及实现类 DefaultSqlSessionFactory
第一: openSession() 生产session
(5)创建sqlSession接口及实现类 DefaultSession
定义对数据库的crud 操作: selectList() selectOne() update() delete()

(6)创建executor接口以及实现类 SimpleExecutor实现类
query(configur, mappedStatement, Object... params) 方法 执行JDBC 代码

mapper 中占位符不使用?的原因 需要根据{} 里面的属性值 去对应要传递的参数的值

自定义持久层框架问题:
1.Dao 层 使用自定义持久层框架 存在代码重复 (加载配置文件, 创建SqlSessionFactory 生产session)
2.statementId 存在硬编码问题

解决思路:不要对应dao层的实现类 使用代理模式生成Dao层接口的实现类(JDK动态代理模式)

代理对象执行接口中的任意方法 都会执行invoke 方法
mapper中 namespace 命名=Dao层接口的路径 select 标签的Id = Dao层接口的方法名 (需要规范化配置)

错题解析:
使用了C3P0连接池解决了频繁创建释放数据库连接问题(正解)
每个<select>标签的内容均对应一个MappedStatement对象 key=statementId
GenericTokenParser是通用的标记解析类(正解) 需要用到TokenHandler去处理

mybaties 简述
基于ORM 半自动轻量级持久层框架
需要写SQL语句 可以对sql语句进行优化
引用的资源较少
返回对象字段和数据库字段保持一致、
sql和java编码进行分离 功能边界清晰,一个专注业务,一个专注数据。

映射配置文件:
部分组成:
1、DTO约束头
2、根标签(属性为namespace)
3、标签 根据功能不同使用不同的标签 (id,resultType paramerType)namespace.id 组成唯一标识
4、内容(需要执行的sql语句)
核心配置文件:
1、environment 标签(数据库环境)根据环境的不同 配置不同的environment 的个数
2、transactionManager 事物类型
3、DataSource 数据源类型 UNPOOLED(非连接池,每次请求的时候产生连接) POOLED(连接池) JNDI
4、mapper 1)resource 全路径 2)URL 磁盘中的位置 3)class 完全限定类名 4)name 将包内的映射器接口实现全部注册为映射器
其他配置:
1、Properties 用于配置文件的引用 习惯将数据源的配置信息单独抽成一个配置文件
2、typeAliases标签 给实体类的权限名类型名起别名
1)typeAlias 用于单独文件
2)package 批量文件 (该包下所有类的本身类名 不区分大小写)
3)常用类型使用mysql定义名称

相关API
Resources工具类 配置文件——> 字节输入流
SqlSessionFactoryBuilder 创建SqlSessionFactory 解析配置文件
SqlSessionFactory 生产SqlSession
SqlSession 调用数据库处理方法 CURD
增删改 需要手动提交事务 sqlSession.commit() or 在openSession时传递参数 true(自动提交事务)
需要手动关闭 sqlSession.close()

动态sql
1) if标签 一般用于多条件判断
2) forech 循环 collection="list" open="(" close=")" item="id" separator=","
3) <sql id="selectUser">抽取 <include refid="selectUser"></include> 使用 共用sql抽取

Mybatis 映射:
单表查询可直接使用对应实体类,复杂表结构查询 可以使用<resultMap> 标签进行定义 select 标签中的resultType——> resultMap
<result> 标签进行字段与类名的对应关系
一对一使用:
<association> 标签进行 是实体中另一个实体进行定义和赋值
一对多使用:
<collection> 标签进行定义 ofType 指定为集合实体类

myBatis 注解
@Insert
@Update
@Delete
@Select
@Result 代替的标签是result column调用另一台sql需要传递的值
@Results 代替的标签是resultMap
@One 代替的标签是association
@Many 代替的标签是collection

加载方式:
1、package name=包路径(建议使用)
2、mapper class=类路径(量比较多)


Mybatis 缓存 对数据库查询结果的保存
一级缓存:sqlSession级别的缓存 不同sqlSession之间的缓存数据区域互不影响,数据结构为hashMap
二级缓存:mapper级别的缓存 多个sqlSession去操作同一个Mapper的sql语句 多个sqlSession 共用二级缓存

一级缓存测试类详解:共有两个查询 指向为同一对象
查询规则:首先在一级缓存中查询 有 直接返回 没有:查询数据库 并放到以及缓存中
一级缓存的key:statementid,params,boundSql(封装的sql语句) rowBounds
测试类第一次 一级缓存未能查询到数据,直接查询数据库,保存的到cache中、
测试类第二次 一级缓存可以查到 直接返回

两次查询增删改操作,并进行事物提交,会刷新一级缓存
sqlSession.clearCache(); 主动刷新一级缓存
刷新缓存的目的:更新数据,避免脏读

一级缓存的原理探究与源码分析:入口:sqlSession
(1)一级缓存的数据结构 通过PerpetualCache类得知 一级缓存的底层数据结构为hashMap
(2)一级缓存创建时间
(3)一级缓存的工作流程

cacheKey:
cacheKey.update(ms.getId()); //namespace
cacheKey.update(rowBounds.getOffset()); //分页参数
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql()); //执行的sql语句

二级缓存:底层配置为hashMap 需要配置使用 (缓存内容为对象数据,底层为临时创建的对象 重新封装成对象 并返回)并非指向为同一个对象
开启二级缓存之后 需要实体类实现序列化
单独配置的usecache 和 flushCache 需要在@Options 注解中使用 xml文件配置 则在select 等标签中进行配置
flushCache 一般默认为true 无需配置

@CacheNamespace(implementation = PerpetualCache.class) 指定二级缓存类
mybatis自带的二级缓存,是单服务器工作,无法实现分布式缓存

mybatis-redisCache 源码分析:
1、redisCache 在mybatis 初始化的时候进行创建 redisConfig类为默认的redis信息(如果使用自己本地服务,可以不用使用redis.properties)
2、redisCache 底层结构为redis中的hash key=redisCache的id 和mybatis的key
3、get 和 put 都是调用redisCache中的executor 重写dowithJides 方法

Mybatis插件:
executor:执行器 负责curd 的行为
statementHandler:sql语法构建 预编译
ParameterHandler:参数处理
ResultSetHandler:结果集处理

插件原理:
1、每个创建出来的对象不是直接返回的,而是interceptorChain.pluginAll(parameterHandler);
2、获取到所有的Interceptor (拦截器)(插件需要实现的接口);调用 interceptor.plugin(target);返
回 target 包装后的对象
3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP (面向切面)我们的插件可 以
为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行;

自定义插件步骤:
1、创建类并实现 Interceptor
2、使用标签进行插件的拦截部分 @Intercepts @Signature
3、配置到sqlMapConfig.xml

mybatis 支持使用第三方插件 例如:pageHelper 分页插件

通用Mapper(基础实现类) 就是为了解决单表增删改查,基于Mybatis的插件机制。开发人员不需要编写SQL,不需要
在DAO中增加方法,只要写好实体类,就能支持相应的增删改查方法
1、导入依赖
2、配置plugin
3、表关联实体
4、定义接口类 继承Mapper接口 泛型为实体类.class
Example example = new Example(User.class);
example.createCriteria();为查询全部 如果需要增加对应条件 接.方法 参数为 列名,和需要匹配的值 例如:example.createCriteria().andEqualTo("id",1);

posted on 2021-08-01 21:29  kuriyame  阅读(46)  评论(0编辑  收藏  举报

导航