测试博客
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.xml 存放数据库的配置信息,
存入mapper.xml全路径
- mapper.xml 存放sql配置信息
自定义持久层框架本身
-
创建为项目工程,本质是对jdbc代码进行封装
-->
底层为传统的jdbc- 数据库配置信息
- sql 配置信息 占位符 参数 sql语句等
- 根据调用处传递的配置信息进行解析
- 加载配置文件
-->
以字节输入流的形式加载-->
存储在内存中 - 创建Resource类,getResourceAsStream(String path)
- 创建2个javaBean(容器对象),存放的是对配置文件解析出的内容
- Configuration:核心配置类: 存放sqlMapperConfig.xml解析的内容
- MappedStrement:映射配置类:存放mapper.xml解析的内容
- 解析配置文件: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 TB b("工程项目") subgraph 工程项目 d("mapper.xml") --"mapper.xml全路径"--> c("sqlMapConfig.xml") b --"sql执行语句"--> d b --"数据库配置"--> c end b --"引用"--> a subgraph 自定义持久层 tip("本质是对jdbc代码的封装") a("自定义持久层") tip --> a a --"1. 创建"--> a1("Resources类") a1 --> a1a("InputStream()") a1 --"加载配置文件为字节输入流"--> a1b("getResourceAsStream(String path)") a --"2. 创建"--> a2("容器javaBean") subgraph 容器 a2 --"创建核心配置类"--> a2a("Configuration") a2a --"存放"--> a21a("sqlMapConfig.xml 解析的内容") a2 --"创建核心配置类"--> a2b("MappedStatement") a2b --"映射配置类"--> a2b1("mapper.xml 解析的内容") end a --"3. 创建"--> a3("SqlSessionFactory") a3 --"实现类"--> a3a("DefaultSqlSessionFactory") a3a --"方法"--> a3a1("openSession()") a3a1 --"生产"--> a3a1a("Sqlsession") a --"4. 解析配置文件dom4j"--> a4("SqlSessionFactoryBuilder") a4 --"方法"--> a41("build(inputStream in)") a41 --"使用dom4j解析配置文件" --> a4a1a("解析结果") a4a1a --"封装到容器对象"--> a2 a41 --"创建"--> a41b("SqlSessionFactory对象") a41b --"工厂模式生产"--> a41b1("sqlSession会话对象") a --"5. 创建"--> a5("SqlSession接口") a5 --"实现类"--> a5a("DefaultSession") a5a --"列表查询"--> a5a1("selectList()") a5a --"查询单个"--> a5a2("selectONe()") a5a --"修改"--> a5a3("update()") a5a --"删除"--> a5a4("delete()") a --"6. 创建"--> a6("Excutor接口") a6 --"实现类"--> a6a("SimpleExcutor") a6a --"成员方法"--> a6a1("query(Configuration conf,MappedStatement st,Object ...params);") a6a1 --"执行jdbc代码" -->a6a1a("sql语句") end
mybatis
简介
-
持久层框架
-
基于
orm:Object Relation Mapping
实体类和数据库表建立映射关联关系 -
半自动 可以对sql进行优化
hibernate -> 全自动
-
轻量级:启动的过程中需要的资源比较少
-
底层: 对jdbc执行代码 进行封装 规避硬编码,频繁开闭数据源
sqlMapConfig.xml
节点说明
- environments 数据库环境的配置,支持多环境配置
- environments.default
-->
指定mybatis 使用的默认环境名称 - environment.id
-->
当前环境的名称 - environment – transcationManager.type=”JDBC” 指定事务管理类型为jdbc
- environment – dataSource.type=”POOLED” 指定数据源类型为连接池
- environment – dataSource
- property.driver 数据库驱动
- property.url 数据库地址 注意连接编码格式
- property.user 数据库连接用户名
- property.password 数据库连接用密码
- mapper 配置的四种方式:
-
mapper.resource
相对于类路径的引用 -
mapper.url
完全限定资源定位符 -
mapper.class
接口对应的全路径 -
package.name
批量加载 保证映射文件与接口同包同名
-
传统dao层开发方式
dao层开发方式
mybatis 外部properties 文件
- 设置mybatis xml配置文件的约束头
- 在resources下创建外部配置文件 格式:
对象.属性=值
- 加载外部配置文件
- 在 configutation 后第一个节点之前 引入外部配置文件
<properties resource='路径'/>
- 在 configutation 后第一个节点之前 引入外部配置文件
mybatis aliasType
- 在mybatis 配置文件中的typeAliases 节点中设置
<typeAliases> <typeAlias type="pojo类路径的全限定名" alais="别名"></typeAlias> </typeAliases> // 对于基础数据类型 mybatis 已定义了别名 string ==> String long ==> Long int ==> Integer double ==> Double boolean ==> Boolean
- 当存在多个pojo时不适用以上方法,采用package模式[批量起别名]
- package模式
不要单独指定alias属性 默认为类本身的类名,且不区分大小写
<typeAliases> <package name="pojo类所在包的全限定名"></typeAlias> // 不要单独指定alias属性 默认为类本身的类名,且不区分大小写 </typeAliases>
- package模式
mapper.xml
动态sql
-
if
标签 判断入参是否符合条件, 不符合不拼接 -
where
标签 自动拼接where 同时去掉where后的第一个and 关键字 -
foreach
标签-
collection
array 注意便携式不要使用#{} -
open
循环前追加 -
close
循环结束后追加 -
item
单次循环内的数据对象 生成的变量 -
separator
前后循环数据之间的分隔符
-
-
sql
标签 抽取sql片段- id sql语句的标识
- 内容为具体的sql语句 可用于封装 分页 和 查询某张表时的前面部分
mybatis复杂映射开发
sqlMapConfig.xml 内引入 mapper.xml
<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() //创建一级缓存的key CacheKey.update() - updateList.add(configuration.getEnviroment().getId());
- 一级缓存的工作流程是怎样的
- 一级缓存的清空
sqlSession.close()
或者执行带有事务的操作 - 在分布式环境下也会存在
脏读
问题解决:禁用一级缓存或调整缓存为statement 级别
二级缓存
- 原理 类似 一级缓存
- 操作的sqlSession 执行了事务操作后 会清空二级缓存
- 一级缓存 默认开启
- 二级缓存需要手动配置开启
1. xml开发形式 <setting> <setting name="cacheEnabled" value="true" /> </setting> 2. 注解形式 在dao接口上添加注解 @CacheNamespace
- 二级缓存 缓存的不是对象 而是对象中的数据
- pojo类需要实现 Serializable 接口
- 二级缓存的存储机制是多样的,可能存储在硬盘上 或者内存中
- 当执行带有事务的操作后,二级缓存会被清空
- 当基于xml配置时还可以配置
- 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.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setId(1); User user1 = mapper.selectOne(user); System.out.println(user1);
-
Example
方式调用
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); // example 方式调用 Example example = new Example(User.class); // 查询User表中的全部记录 example.createCriteria().andEqualTo("id",1); // 执行查询,获得结果 List<User> users = mapper.selectByExample(example); for (User user2 : users) { System.out.println(user2); }
随堂测试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.xml解析时,会将解析出来的内容以不同形式封装到Configuration对象中
- [ ] B.使用dom4j对mapper.xml解析时,每个标签的内容均对应一个MappedStatement对象
[x] C.Configuration中包含了MappedStatement的引用
[ ] D.MappedStatement对象对应Mapper.xml,一个Mapper.xml对应一个MappedStatement对象下列关于GenericTokenParser类,说法正确的是:() [多选题]
[x] A.该类只能通过有参构造进行创建
[x] B.GenericTokenParser是通用的标记解析类
[x] C.GenericTokenParser在解析#{}占位符时必须要通过标记处理类TokenHandler的配合
[x] D.GenericTokenParse三个构造参数分别为开始标记、结束标记、标记处理器随堂测试02 MyBatis基础回顾及高级应用
在一个MyBatis的应用中,关于SlqessionFactoyfBuilder,SqlsessionFactory以及Sqlsession的应用范围和生命周期,以下说法错误的是:()
[ ] A.SqlSessionFactoryBuilder的最佳范围为方法范围,即可要定义为本地方法变量
[ ] B.SqlSessionFactory的最佳范围是应用范围
[ ] C.SqlSession的最佳范围是方法范围或请求范围
[x] D.SqlSession执行CRUD操作,不同线程可以共享使用在Mybatis中,下列关于ResultType说法错误的是:()
[ ] A.ResultType表示返回值类型为:完整类名或别名,Mybatis也允许使用基本的数据类型,包括String、int类型
[ ] B.ResultType和ResultMap的数据结构是一样的,都是Map结构
[x] C.如果POJO的属性名与SQL语句查询出来的字段名不一致的话,也可使用resultType来进行结果的自动映射
[ ] D.ResultType和ResultMap不能同时使用使用MyBatis的时候,除了可以使用@Param注解来实现多参数入参,还可以用()传递多个参数值:()
[x] A.用Map对象可以实现传递多参数值
[ ] B.用List对象可以实现传递多参数值
[ ] C.用数组的方式传递
[ ] D.用Set集合的方式传递Mapper接口开发需要遵循下列哪些规范? [多选题]
[x] A.Mapper.xml文件中的namespace与mapper接口的类路径相同
[x] B.Mapper接口方法名和Mapper.xml 中定义的每个statement的id相同
[x] C.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
[x] D.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同mybatis架构原理
2020年8月25日21:20:04接口层
传统方式 –> sqlSession.selectList()…
mapper代理方式 –> 代理对象 –> 内省数据处理层
框架支撑层层次结构示意图
mybatis传统方式源码分析
Configuration
SqlSession 是Mybatis 中用于和数据库交互的顶层类,通常与ThreadLocal绑定,一个会话使用一个SqlSession,并且在使用完毕后需要closeDefaultSqlSession 默认
SqlSession中较为重要的两个参数 configuration与初始化时相同,Executor为执行器
openSession 生产DefaultSqlSession实例对象,设置事务不自动提交,完成Executor对象的创建Mapper代理方式
如何对mapper接口产生代理对象
代理对象在调用方法时,底层的invoke方法是如何执行的设计模式
Builder模式(构建者模式) –>
如果某个对象的构建比较复杂或超出了构建函数所能包含的范围时,就可以使用工厂模式和构建者模式
使用多个简单对象 一步一步 构建出一个复杂的对象
egg: 构建电脑 –> 各个组件的构建工厂方法模式
简单工厂模式 根据传入的参数不同创建其他不同的实例
被创建的实例一般都具有相同父类单例模式
代理模式
组合模式
模板方法模式
适配器模式
装饰者模式
迭代器模式mybatis 执行流程图解
mybatis延迟加载
一对多,延迟加载,多对一 立即加载 当同时配置了局部和全局, 那么局部优先于全局
主要通过动态代理的方式实现的,通过代理拦截到指定的方法,执行数据加载局部延迟
<1–关闭一对一延迟加载–>
<resultMap id=”orderMap”type=”order”>
<id column=”id”property=”id”></id>
<result column=”ordertime”property=”ordertime”></result>
<result column=”total”property=”total”></result>
<!–
fetchrype=”lazy”懒加载策略
fetchType=”eager”立即加载策略
–>
<association property=”user”column=”uid”javarype=”user”
select=”com.lagou.dao.UserMapper.findById”fetchrype=”eager”I
</association>
</resultMap>全局延迟
在核心配置文件中的setting 标签<settings>
<1–开启全局延迟加载功能–>
<setting name=”lazytoadingEnabled”value=”true”/>
</settings>Iidea 调试延迟加载的注意点
mybatis 动态sql相关类
SqlNode 接口
SqlSource Sql 源接口
BoundSql 类XMLConfigBuilder 在执行过程中会调用 XMLMapperBuilder
XMLMapperBuilder 内部使用XMLStatementBuilder 处理xml中的各个节点
XMLStatementBuilder
解析xml文件中的各个节点,如select,insert,update,delete节点,
内部会使用XMLScriptBuilder处理节点的sql部分,
遍历产生的数据会丢到Configuration的mappedStatements中。XMLScriptBuilder 解析sql内容,会使用到LanguageDriver接口极其实现类,该接口的主要作用是构建SQL
LanguageDriver –> 追踪 mybatis 拼接sql的具体执行部分
mybatis 四大对象的生命周期及应用范围
SqlSession :现成不安全,作用于请求或方法期间
常用的数据库连接池
c3p0 架构复杂
dbcp 迭代了一个版本
druid 功能全面 中文文档mybatis 查询数据量大的时候会造成oom 如何处理
?