myabtis知识点总结

原生JDBC操作数据库的步骤

1,导入相关的包(sql)  
2,注册数据库驱动
3,获得数据库连接
4,编写SQL语句,建立结果集,并将结果集封装到返回的对象中
5,写操作事务处理
6,关闭连接

动态sql

case when语法 in语法,传入的集合或者数组 FIELD()按照某个字段指定规则排序 concat()用于like模糊查询

批量操作数据库

1,检查数据库是否支持批量操作
2,使用foreach动态sql进行批量操作
3,或者使用Batch执行器,SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, true),将批量操作一起放入到
Batch队列中,然后最终一起执行,只有一次数据库的连接。但是如果执行的数据太对了,可能会造成队列溢出,或者执行时间过长。在和spring
集成之后,因为封装了SqlSessionFactory,所以要使用Batch就需要自己手动的去获取SqlSessionFactory

几种执行器

1,Statement简单类型的执行器
2,PreparedStatement预处理执行器
3,Batch批量操作的执行器

PreparedStatement预处理结果集

PreparedStatement结果集,可以在第一次执行时进行预编译,指令缓存在数据库中,提高效率,并且可以防止sql注入。

#{}和${}的区别

#{}:预编译,可以防止sql注入,传入的字符串会自动加上单引号,在预编译的时候会用?占位符表示
${}:不会预处理,不可以防止sql注入,传入的字符串直接替换,在表名和查询出来的字段名是动态的时候,需要使用,因为不能加单引号

几个重要组件

SqlSessionFactoryBuilder:读取所有的配置信息,创建SqlSessionFactory,使用建造者模式,方法级别生命周期;

SqlSessionFactory:创建Sqlsession,工厂单例模式,存在于程序的整个生命周期,管理连接池,用于生产SqlSession的工厂;

SqlSession:代表一次数据库连接,可以直接发送SQL执行,也可以通过调用Mapper访问数据库;线程不安全,要保证线程独享(方法级);

SQL Mapper:由一个Java接口和XML文件组成,包含了要执行的SQL语句和结果集映射规则。方法级别生命周期;

example类

最好不要使用example类,因为example类不利用解耦,不利用sql调优。

嵌套结果和嵌套查询

嵌套结果:一个sql把关联查询的数据都查出来
嵌套查询:先查出一部分数据,再根据这部分数据查出剩下的数据,这样在查询的时候会先查一次主表,再根据结果去查从表,可能会引起N+1的问题,所以需要开启延迟加载(fatchType=lazy),去解决这个问题,在日常开发中,推荐使用这种方式去解决关联查询。

关联查询

1,一对多association
2,一对多collection
3,选择策略discriminator(鉴别器),可以设置条件选择某一个resultMap执行。

一级和二级缓存

1,insert,update,delete这些操作会去清空一级缓存,一级缓存默认开启,一级缓存是sqlsession级别的,根据第一次查出的id作为key。
2,二级缓存是跨sqlseesion级别的,是以空间namespace为单位的。但是最好不要使用二级缓存,因为非常容易出现脏读。设置即可开启,同时可以设置缓存回收算法策略,有FIFO(先进先出),LRU(最近最少使用)。建议不要使用二级缓存,容易出现脏读,可以使用第三方的缓存框架代替mybatis的二级缓存。
3,优先级:优先从二级缓存找,其次是一级缓存,Hibernate是先去本地的一级缓存,如果没有就会去找二级缓存,再没有就去查数据库。

适配器模式

举例:姚明不会讲英语,需要一个适配器(翻译)来,适配之后,姚明讲的中文就变成了翻译之后的英文了。比如,mybatis的日志实现,就是将很多第三方的日志实现通过各自的适配器转成mybatis的日志Log实现。

开发使用场景:
	1,比如支付宝接口,微信支付接口,银联支付接口,可以写一个自己规则的支付接口,然后用适配器模式,将其他第三方的支付接口适配成自己支付接口模式。      
	2,还比如机票接口,有很多厂商提供机票接口,就可以用适配器模式。
在mybatis的日志框架中使用了这种模式,因为有很多日志框架的实现中的LEVEL等级都不一样,mybatis统一定制了一套日志等级,然后将其他日志框架在mybatis中转换成了自己的等级。同时,在LogFactory工厂中,static静态块中定义了日志加载顺序,优先级顺序:slf4J → commonsLoging → Log4J2 → Log4J → JdkLog.会按照顺序依次判断是否已经有了此日志实现,如果没有就开启一个线程去尝试(因为可能没有加入此依赖)创建此日志框架,如果有就不再加载其他日志框架。

对功能的扩展

1,继承(静态的,如果是一个类要多方向扩展功能,就得添加很多个增强类,这时候使用装饰器模式最佳)
2,动态代理(mybatis中的日志部分,在ConnectionLogger代理类中,让JDBC原生的Connection和PreparedStatement和Statement和ResultSet都具备了打印日志的能力,即是都被增强了)
3,装饰器模式(扩展性,灵活性更强),比如IO的设计就使用了装饰器,servlet中的httpservletrequestwrapper和mybatis缓存组件。
设计模式的几大原则:
	1,单一职责(分工明确)
	2,依赖倒转(高层不依赖底层,解耦)
	3,开放封闭(对扩展开放,对修改封闭)

装饰器模式和动态代理的区别

假设这样一种场景,我们要为类Origin增加A功能,B功能和C功能。
	1,动态代理:需要生成三个Origin的Handler来分别增加A,B,C功能。这三个代理类分别为OriginHandlerA,OriginHandlerB,OriginHandlerC
	2,装饰器模式:也需要生成三个Origin的装饰器来增加A,B,C的功能。这三个装饰器分别为OriginDecoratorA,OriginDecoratorB,OriginDecoratorC
现在我们有了新的需求,需要为Origin类增加A,B功能。
	1,动态代理:再生成一个子类来实现AB功能的组合,客户端代码获取对应功能的代理类可以解耦到配置文件中。这样就可以不用修改客户端代码来实现新的功能了。
	2,装饰器模式:不需要生成新的装饰器类,只需要在客户端代码中组合的OriginDecoratorA和OriginDecoratorB来或者AB功能。

mybatis的数据源

采用工厂模式:(因为DataSource的创建很麻烦,构造函数和内部实现很复杂,同时解耦,所以使用工厂模式)
UnpooledDataSourceFactory:创建不使用数据库连接池的数据库连接的工厂
PooledDataSourceFactory:创建使用数据库连接池的数据库连接的工厂

UnpooledDataSource:不使用数据库连接池的数据库连接对象,继承DataSource,创建连接的过程和JDBC原生一致,其中数据库驱动通过反射
去注册,在注册的时候,其实就是Driver类被加载的时候调用其内部的static进行初始化后注册到DriverManager中。
PooledDataSource:使用数据库连接池的数据库连接对象,是线程安全的,继承DataSource,几个重要的组件:
	PooledConnection:使用动态代理对从连接池中获取的Connection连接对象进行增强的代理类。
					  增强的地方有:1,使用前检查连接是否有效  2,手动关闭时对连接进行回收
	PoolState:管理PooledConntection中的一些组件信息,比如空闲连接池数idleConnections,以及活跃连接池数activeConnections....获取连接和回收连接的方法。
	获取连接的原理:首先去空闲连接池中获取连接,如果空闲连接池没有了,就去判断活跃连接池是否已经满了,如果没有满,就直接创建一个连接,并且把这个连接放入到活跃连接池中,如果	满了,就判断活跃连接池中第一个连接是否超时了,如果超时了就直接获取连接,没有超时就等待一定时间,等待被唤醒。时间过了还没获取到连接就再次循环整个流程,循环次数是有限	的,超过了次数就抛出异常。

	归还连接的原理:首先移除活跃连接池中这个连接,然后判断此连接是否失效,如果失效了就直接关闭连接,如果没有就去判断空闲接连池是否满了,如果满了就直接关闭这个连接,如果没满				就将连接放入到空闲连接池中,并且唤醒所有线程。
	注意:再归还连接的时候,需要判断此连接是否开启了手动提交事务,如果是,需要进行事务回滚,防止脏数据的生成。

select 1 可以测试mysql数据库是否连接。
select 1 from durl 可以测试orcal数据库连接是否连接。

mybatis的缓存

缓存被清空的策略:FIFO(先进先出),LRU(最近最少使用的先出)。
数据库的查询操作,超过0.3S就被称为你慢查询,需要优化系统了。
使用缓存就是一种空间换时间的操作,将磁盘数据库上的数据,备份到内存中,免去了去请求磁盘的IO操作的费时。
tomcat默认的失效时间是30分钟。

使用缓存的时候,存在数据一致性问题,有四种处理方法,其中使用比较多的缓存失效机制,容易引起缓存雪崩。
缓存雪崩:就是在缓存失效的一瞬间,有多高并发请求直接透过缓存请求数据库,使得数据库挂掉。
解决:
	  1,给缓存失效时间加“盐”,不让所有的缓存的失效时间一样。
	  2,使用jvm锁,推荐使用细粒度锁,mybatis的阻塞装饰器缓存机制中就是使用的对key进行的加锁的细粒度锁,使用粗粒度的锁,即是所有请求争取一把锁,这样效率低。
	  3,使用分布式锁。
java连接池最大连接数不能超过数据库自带的连接池的连接数。
连接数 = ((核心数 * 2) + 有效磁盘数)

CacheKey对象中重写的equals方法,比较两个对象是否相同(这两个对象是根据对象中的很多属性是否相等比较),采用的一种很高效的办法。

mybatis的反射

ObjectFactory:MyBatis每次创建结果对象的新实例时,它都会使用对象工厂(ObjectFactory)去构建POJO;
ReflectorFactory:创建Reflector的工厂类,Reflector是mybatis反射模块的基础,每个Reflector对象都对应一个类,在其中缓存了反射操作所需要的类元信息,如果没有get和set方法,也可以通过对其进行自动的设置set和get方法。
ObjectWrapper:是一种增强,对对象的包装,抽象了对象的属性信息,他定义了一系列查询对象属性信息的方法,以及更新属性的方法,可以给将sql查出来的数据赋值给相应的对象。
ObjectWrapperFactory: ObjectWrapper 的工厂类,用于创建ObjectWrapper。
MetaObject:封装了对象和类的元信息,包装了mybatis中五个核心的反射类。也是提供给外部使用的反射工具类,可以利用它可以读取或者修改对象的属性信息;

mybatis的核心流程

1,初始化配置
	读取XML配置文件和注解中的配置信息,创建配置对象,并完成各个模块的初始化的工作;
2,代理增强阶段
	封装iBatis的编程模型,使用mapper接口开发的初始化工作,就是根据mapper接口,动态代理增强获取对应的mapper接口的实现类。
3,数据读写阶段
	通过SqlSession完成SQL的解析,参数的映射、SQL的执行、结果的解析过程;

建造者模式:
	使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。符合Fluent编程风格。
	使用例子:StringBuufer,zk中的curator等。

建造者模式和工厂模式的区别:
	工厂模式一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个产品的组成部分。从代码上看,工厂模式就是一个方法,用这个方法就能生产出产品。
	建造者模式也是创建一个产品,但是不仅要把这个产品创建出来,还要关系这个产品的组成细节,组成过程。从代码上看,建造者模式在建造产品时,这个产品有很多方法,建造者模式会根据这些相同方法但是不同执行顺序建造出不同组成细节的产品。可以比较两个模式的example代码,一比较就会比较出来,工厂模式关心整体,建造者模式关心细节。
	
	对象复杂度:
	 建造者建造的对象更加复杂,是一个复合产品,它由各个部件复合而成,部件不同产品对象不同,生成的产品
	粒度细:
	 在工厂方法模式里,我们关注的是一个产品整体,无须关心产品的各部分是如何创建出来的;
	 客户端参与程度
	 建造者模式,导演对象参与了产品的创建,决定了产品的类型和内容,参与度高;适合实例化对象时属性变化
	频繁的场景:
	 工厂模式,客户端对产品的创建过程参与度低,对象实例化时属性值相对比较固定;

创建对象的几种方法:
	1,工厂模式
	2,建造者模式
	3,反射
	4,new
	5,clone
	6,反序列化


Configuration : Mybatis启动初始化的核心就是将所有xml配置文件信息加载到Configuration对象中, Configuration是单例的,生命周期是应用级的;
				 XMLConfigBuilder是用于处理核心配置文件,XMLMapperBuilder处理映射文件中的映射实体,XMLStatementBuilder处理映射文件中的sql,这三个类实际上都是使用建造者模式思想,并没有使用建造者模式的写法,后两个都调用了“秘书类”去建造Configuration ,解析相应的XML后,添加进Configuration相应的属性。
				 其中:
				 	CacheKey:是缓存的id封装之后的对象,是以命名空间的id+指定查询结果集的范围(分页信息)+查询所使用的SQL语句+用户传递给SQL语句的实际参数值组成
				 	ResultMap:存储mapper配置文件中的resultMap
				 	ResultMapping:存储resultMap中的result属性


MapperRegistry:mapper接口动态代理工厂类的注册中心。在MyBatis中,通过mapperProxy实现
InvocationHandler接口,MapperProxyFactory用于生成动态代理的实例对象;
ResultMap:用于解析mapper.xml文件中的resultMap节点,使用ResultMapping来封装id,result等子元素;
MappedStatement:用于存储mapper.xml文件中的select、insert、update和delete节点,同时还包含了这些节点的很多重要属性;
SqlSource:mapper.xml文件中的sql语句会被解析成SqlSource对象,经过解析SqlSource包含的语句最终仅仅包含?占位符,可以直接提交给数据库执行;
TypeHandlerRegistry:用于映射数据库字段属性类型和java类型。通过xml中指定typeHandler和自定义转换类实现BaseTypeHandler接口即可实现映射枚举类。

mybatis的mapper动态代理增强

MapperRegistry : mapper接口和对应的代理对象工厂的注册中心;
MapperProxyFactory:用于生成mapper接口动态代理的实例对象;
MapperProxy:实现了InvocationHandler接口,它是增强mapper接口的实现;
MapperMethod:封装了Mapper接口中对应方法的信息,以及对应的sql语句的信息;它是mapper接口与映射配置文件中sql语句的桥梁;
	MapperMethod:封装了Mapper接口中对应方法的信息,以及对应的sql语句的信息;它是mapper接口与映射配置文件中sql语句的桥梁; MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享;
  SqlCommand : 从configuration中获取方法的命名空间.方法名以及SQL语句的类型;
  MethodSignature:封装mapper接口方法的相关信息(入参,返回类型);
  ParamNameResolver: 解析mapper接口方法中的入参;

创建sqlsession的策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。
策略模式的使用场景:
 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时;
 出现同一抽象类有多个子类,而又需要使用 if-else 或者 switch-case 来选择具体子类时。
   就比如是,spring的依赖注入,@Autowired,如果不指定注入的value,就是按照类型注入,如果指定了,就按照名称注入,但是注入的方式都是一样的,所以spring的依赖注入的实现方式就是策略模式。springmvc的dispatcherservlet用到了门面模式。
sqlSessionManager同时继承了SqlSession接口和SqlSessionFactroy接口,提供了创建SqlSession对象和操纵数据库的能力;
 SqlSessionManager有两种获取SqlSession的模式:
 第一种模式和SqlSessionFactroy 相同,同一个线程每次访问数据库,每次都可以创建新的SqlSession对象;
 第二种模式,同一个线程每次访问数据库,都是使用同一个SqlSession对象,通过localSqlSession实现;

核心组件Excutor

Executor是MyBaits核心接口之一,定义了数据库操作最基本的方法,SqlSession的功能都是基于它来实现的,使用了模板方法模式。
在sqlsession执行的各种查询方法,最终都会被转成sqlsession.list方法,通过Executor的query方法来执行。
模板模式:
遇到由一系列步骤构成的过程需要执行,这个过程从高层次上看是相同的,但是有些步骤的实现可能不同,这个时候就需要考虑用模板模式了。
SimpleExecutor:默认配置,使用statement对象访问数据库,每次访问都要创建新的statement对象;
ReuseExecutor:使用预编译PrepareStatement对象访问数据库,访问时,会重用缓存中的statement对象;
BatchExecutor:实现批量执行多条SQL语句的能力;

Executor的三个重要小弟
 通过对SimpleExecutor doQuery()方法的解读发现,Executor是个指挥官,它在调度三个小弟工作:
 StatementHandler:它的作用是使用数据库的Statement或PrepareStatement执行操作,启承上启下作用;
 ParameterHandler:对预编译的SQL语句进行参数设置,SQL语句中的的占位符“?”都对应BoundSql.parameterMappings集合中的一个元素,在该对象中记录了对应的参数名称以及该参数的						相关属性。其中,对参数的设值是通过TypeHandler完成的。
 ResultSetHandler:对数据库返回的结果集(ResultSet)进行封装,返回用户指定的实体类型;

StatementHandler完成Mybatis最核心的工作,也是Executor实现的基础;功能包括:创建statement对象,为sql语句绑定参数,执行增删改查等SQL语句、将结果映射集进行转化;
BaseStatementHandler:所有子类的抽象父类,定义了初始化statement的操作顺序,由子类实现具体的实例化不同的statement
(模板模式);
 RoutingStatementHandler:Excutor组件真正实例化的子类,使用静态代理模式,根据上下文决定创建哪个具体实体类;
 SimpleStatmentHandler :使用statement对象访问数据库,无须参数化;
 PreparedStatmentHandler :使用预编译
   PrepareStatement:对象访问数据库;
 CallableStatmentHandler :调用存储过程;

执行流程是:
Sqlsession获取连接-->Executor执行sql-->StatementHandler执行(创建执行对象Statment和返回对象ResultSet)-->ParameterHandler填充参数到Statment占位符中-->请求数据库返回结果集-->ResultSetHandler处理返回结果集,封装到ResultSet-->StatementHandler返回结果集-->Executor返回结果集-->Sqlsession返回结果集.

mybatis的分页其实就是个假分页,是先将所有的数据一次性查出来,再遍历找出相应页码的数据返回,所以不用mybatis自带的分页。

spring和myabtis整合

SqlSessionFactoryBean中初始化mybatis的一系列配置文件和接口和参数。
MapperScannerConfigurer扫描mapper接口和mapper配置文件,将mapper接口转化成MapperFactoryBean。
spring只是做了初始化和mapper接口增强映射的一些操作,底层连接数据库还是mybatis自己实现的。

插件开发

1. 实现Interceptor接口方法,配置mybatis中需要去拦截的方法(mybatis中有很多种可以被拦截的方法)。
   mybatis中能使用插件进行拦截的接口和方法如下:
 Executor(update、query 、 flushStatment 、 commit 、 rollback 、 getTransaction 、 close 、 isClose)
 StatementHandler(prepare 、 paramterize 、 batch 、 update 、 query)
 ParameterHandler( getParameterObject 、 setParameters )
 ResultSetHandler( handleResultSets 、 handleCursorResultSets 、 handleOutputParameters )
2. 确定拦截的签名
3. 在配置文件中配置插件
4. 运行测试用例
插件的执行流程:
1. 插件的初始化 (XMLConfigBuilder.pluginElement)
2. 插件的加载 (Configuration.new*方法,四大对象的创建的时候都会加载插件的代理)
3. 插件的调用 (Plugin. wrap、 Plugin. invoke)

使用场景:
比如可以过滤一些非法的sql。

责任链模式

责任链模式:就是把一件工作分别经过链上的各个节点,让这些节点依次处理这个工作;和装饰器模式不同,每个节点都知道后继者是谁;适合为完成同一个请求需要多个处理类的场景;
责任链模式优点:
 降低耦合度。它将请求的发送者和接收者解耦。
 简化了对象。使得对象不需要知道链的结构。
 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
 增加新的请求处理类很方便。
拦截器/过滤器的实现就是一种责任链模式。

mybatis 是怎么使用枚举的方式来关联数据库字段的

1,编写枚举类
2,编写自定义枚举转换器,实现BaseTypeHandler接口,重写相应方法。
3,在mapper中的结果映射中的相应字段配置typeHandler。

代理模式的作用

对某些对象提供一种对外访问的接口,扩展实现类的功能。

静态代理:若代理类在程序运行前就已经存在,那么这种代理方式被成为静态代理。
优点:可以扩展原功能,不侵入原来的代码。
缺点:灵活性低,当需要扩展的对象多了之后,代理类就会随之改变。

动态代理:代理类在程序运行时创建的代理方式被成为动态代理。
优点:可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,
所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。

jdk动态代理和cglib动态代理的区别:
使用JDK动态代理,目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象,这也是jdk动态代理的缺点。
Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。
从执行效率上看,Cglib动态代理效率较高,所以spring的aop实现一般都用cglib。

工厂模式的作用

帮助我们创建实例,不需要我们去频繁的new实例。

简单工厂模式:不属于设计模式,是一种思想,由一个工厂决定创建哪一个对象。
优点:在工厂中包含了必要的逻辑,帮助我们去自动生成对应的实例。
缺点:当实例发生改变的时候,工厂也要发生响应的改变,并且工厂中的逻辑写死的,违反了高内聚低耦合的分配原则,违反了开放封闭原则和单一职责原则。

工厂设计模式:
优点:创建对象的接口,让子类去决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码。工厂方法克服了简单工厂违背开放-封闭原则和单一职责原则的缺点,又保持了封装对象创建过程的优点。
缺点:每增加一个产品,相应的也要增加一个子工厂,加大了额外的开发量。
注意:当业务复杂,自己创建对象很麻烦的时候,并且多个对象有相同的点的时候,可以考虑使用工厂模式。

抽象工厂模式:
其实就是在工厂模式的基础上,有多个产品的时候。就在抽象工厂的接口上加上新增的产品就行。

注意:当创建对象的构造函数的参数过多的时候,创建很复杂可以考虑使用工厂模式。

为什么class.forname(“com.mysql.jdbc.Driver”)加载后就能注册jdbc驱动

因为当Driver类被加载的时候,在Driver类中有一个static代码块,里面就是通过DriverManager.register(new Driver());将Driver驱动给注册了。
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值