链接: mybatis中文文档
//第一步获取文件
String resource = "org/mybatis/example/mybatis-config.xml";
Reader reader = null;
try {
//第二步,读取文件io信息
reader = Resources
.getResourceAsReader(resource);
} catch (IOException e) {
}
//SqlSessionFactory 工厂,里面就是读取config文件里面的信息
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = build.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
SqlSessionFactory 中的XMLConfigBuilder解析配置文件,XMLConfigBuilder只能使用一次,因为Configuration是全局的,
XMLConfigBuilder 解析xml配置文件
Configuration就是存入的配置的文件,bean文件
1.0 mapper与接口绑定原理分析
通过jdk动态代理模式来实现的—重要代码之一:MapperProxy—ProxyClassFactory生成的代理类会调用invoke,因此可以证明MyBatis是使用JDK动态代理实现的。
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private static final int ALLOWED_MODES = 15;
private static final Constructor<Lookup> lookupConstructor;
private static final Method privateLookupInMethod;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//判断是否Object的方法,如toString、hashCode直接调用 ,调用里面的方法
if(Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if(method.isDefault()) {
if(privateLookupInMethod == null) {
return this.invokeDefaultMethodJava8(proxy, method, args);
}
return this.invokeDefaultMethodJava9(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
//通过method获取构造时传入的MapperMethod
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//执行方法代码
return mapperMethod.execute(this.sqlSession, args);
}
2.0 mybaits sqlsession 一级缓存
链接: 美团聊聊mybaits 缓存机制.
在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能
一级缓存,会有概率出现脏数据,当同一个SqlSession 执行时,会出现第二次,走的是一级缓存,如果是分布式缓存,第二次查询数据对不上。
每个SqlSession中持有了Executor,每个Executor中有一个LocalCache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。新增。修改,删除时,就会清楚缓存
spring 融合mybaits—里面有个final,写了个清除缓存的方法
如果没有开启事务,每一次sql都是用的新的SqlSession,这时mybatis的一级缓存是失效的。
如果有事务,同一个事务中相同的查询使用的相同的SqlSessioon,此时一级缓存是生效的。
一级缓存总结:缓存用的是hashMap,缓存key:方法类+id+sql语句作为key
MyBatis一级缓存的生命周期和SqlSession一致。
MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。
MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。
3.0 mybaits sqlsession 二级缓存
二级缓存使用了很多装饰设计模式,自己整合redis,encha就行,默认是开启本地缓存encha
4.0 mybaits 生命周期
1:SqlSessionFactoryBuilder(构造器)
2:SqlSessionFactory(工厂接口)
3:Sqlsession(会话)
4:SQL Mapper(映射器)
SqlSessionFactoryBuilder : SqlSessionFactoryBuilder的作用在于创建SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder就失去了作用,所以它只能存在于创建SqlSessionFactory的方法中,而不要让其长期存在。
SqlSessionFactory : 可以被认为是一个数据库连接池, 它的作用是创建Session接口对象。因为MyBatis的本质就是Java对数据库的操作,所以SqlSessionFactory的生命周期存在于整个MyBatis的应用之中,所以一旦创建 了SqlSessionFactory,就要长期保存它,直至不再使用MyBatis应用,所以可以认为SqlSessionFactory的生命周期就等同于MyBatis的应用周期。由于SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源,如果创建多个SqlSessionFactory, 那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。因此在一般的应用中我们往往希望SqlSessionFactory作为一个单例(Singleton), 让它在应用中被共享。
如果说SlssonFactory相当于数据库连接池,那么SqlSession就相当于一个数据库连接(Conection对象),你可以在一个事务里面执行多条SQL,然后通过它的commit、rollback等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给SqlSessionFactory, 否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用try{}catch{} fnally{}语句来保证其正确关闭。
Mapper是个接口, 它由Ssesion所创建,所以它的最大生命周期至多和SqlSession一致,随着SqlSession的关闭,它的数据库连接资源也会消失,所以。Mapper生命周期\leqslantSqlSession生命周期。Mapper是一个请求中的业务处理,所以它应该在一个请求中, 当相关业务处理完毕后就应该销毁它。
5.0 mybaits 常用设计模式
1:Builder模式:
例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
:2:工厂模式:
例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
:3:单例模式:例如ErrorContext和LogFactory;
:4:代理模式:Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
:5:组合模式:例如SqlNode和各个子类ChooseSqlNode等;
:6:模板方法模式: 例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
:7:适配器模式: 例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
:8:装饰者模式: 例如cache包中的cache.decorators子包中等各个装饰者的实现;
:9:迭代器模式: 例如迭代器模式PropertyTokenizer;
6.0 mybaits 一些问题
1:A系统给B系统一条SQL是正确SQL—通过语法引擎,而mybaits 里面的xml,需要通过语法引擎检测,然后改写sql,执行sql语句—后面很多分库分表shardJdbc,阿里seata 也是重写sql语句
2:mybaits 是一个半ORM(对象关系映射),mybaits 可以使用xml或注解来配置和映射原生信息,将POJO映射成数据库中的记录,也可以通过手写SQL语句
3:#{}和 , {}, ,{}是字符串替换,#{} 是预处理—可以有效的防止SQL注入,提高系统安全性
6.0 mybaits_plus
官网链接:https://baomidou.com/guide/
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
- 特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
组件:实现逻辑删除,全局id/自定义全局id,自定义分页插件,代码生成器,