mybatis是什么

mybatis是什么,第1张

MyBatis是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

引入了以下包

其中自动装配的包就是mybatis-spring-boot-autoconfigure。

META-INF下有一个springfactories文件

导入了这个类MybatisAutoConfiguration

注册MapperScannerConfigurer的Bean定义到Spring容器中,并设置扫描包的路径

MapperScannerConfigurer 实现BeanDefinitionRegistryPostProcessor接口,实例化的时候会调到postProcessBeanDefinitionRegistry方法,这个方法里会创建一个ClassPathMapperScanner对象,然后去扫描

扫描到之后修改BeanDefinition

@MapperScan注解,会import进来MapperScannerRegistrar这个类

MapperScannerRegistrar类实现ImportBeanDefinitionRegistrar接口,实例化的时候会调用registerBeanDefinitions方法

和@Mapper一样,同样会创建MapperScannerConfigurer的BeanDefition,用于后续实例化

只不过要扫描的包路径变了,不再是默认的,而是@MapperScan配置的包路径

后面的话则和@Mapper扫描到之后的工作原理是一样的,扫描到之后,更改BeanDefinition,一毛一样的。

==可以看出@MapperScan最主要的工作原理除了提供BasePackage的值之外,就是用@Import注解导入MapperScannerRegistrar所以这个注解打在任何可以被spring扫描到的类上都可以,并不一定要打在启动类上(大多数为了只是为了看起来方便,把全局性的配置注解打在启动类上而已)==

前面提到,注册扫描@Mapper接口的MapperScannerConfigurer实例的类是AutoConfiguredMapperScannerRegistrar,那么这个类是如何被导入进来的呢

MybatisAutoConfiguration还有一个静态内部类,@Import了AutoConfiguredMapperScannerRegistrar类,但是有@ConditionalOnMissingBean,即spring容器中不存在MapperFactoryBean,MapperScannerConfigurer的实例。

如果@MapperScan注解生效,并且扫描到任意一个Mapper接口(前面被改造成MapperFactoryBean类型的了),那么就不满足注册这个类MapperScannerRegistrarNotFoundConfiguration的实例的条件,继而不会导入AutoConfiguredMapperScannerRegistrar类。

前面提到,所有的Mapper接口被扫描到,封装成BeanDefinition,还经历了一次改造,

最主要的就是将mapper接口BeanDefination的beanClass改成了orgmybatisspringmapperMapperFactoryBeanclass

并且将mapper接口BeanDefination的名称作为构造函数的入参传入进去

并讲BeanDefinition的autowireMode属性改成 AUTOWIRE_BY_TYPE ,后面实例化该bean的时候会调用属性的描述器,用write的方式注入属性值,最重要的那个属性那就是SqlSessionTemplate 会通过这种方式将前面MybatisAutoConfiguration中@Bean出来的SqlSessionTemplate注入到其中。

类图:

这里他实现了FactoryBean,

FactoryBean有以下方法

这里是spring的一个拓展点,实现了FactoryBean接口的类,将可以实现getObject() 和getObjectType来实例化额外的一个bean并装到spring容器中

好吧,其实Mapper代理对象的创建就是在MapperFactoryBean的getObject方法中返回的

这里就是熟悉的原生Mybatis创建Mapper接口的味道了。

附上调用的类时序图,回过头来看一下调用的整体流程。

MappedStatement维护了一条<select|update|delete|insert>节点的封装

比如Mapperxml中一个<select />节点

转换成Java类就是一个MappedStatement

使用Configuration的getMappedStatement方法来获取MappedStatement对象

获取的方式key的组成为 命名空间+id

负责根据用户传递的parameterObject, 动态地生成SQL语句 ,将信息封装到BoundSql对象中,并返回

表示动态生成的SQL语句以及相应的参数信息

当调用SqlSource的getBoundSql方法,传入的就是parameterMappings相对应的参数,最终生成BoundSql对象,有了BoundSql就可以执行sql语句了

MeatObject是Mybatis的工具类,通过MetaObject获取和设置对象的属性值。

返回结果:

基本的pojo对象:

MetaObject提供了一个工具类:

当调用 SystemMetaObject 获取 MetaObject 对象时,每次均 new DefaultReflectorFactory() 了一个反射工厂类。

继续查看:

这个类并没有做很复杂的 *** 作,就是获取object的type类型,且存储到Map中。当同一个object调用 forObject() 时,后续调用可以在缓存中获取反射对象。

但注意: SystemMetaObject 方法因为每次均new了一个新的 DefaultReflectorFactory 工厂。若每次在方法中调用 SystemMetaObjectforObject 获取 MetaObject 对象。同一个对象可能不会走缓存。

推荐做法: 将 DefaultReflectorFactory 声明为静态变量:

在创建 MetaObject 对象的时候,就会将传入的Object对象的所有反射对象都缓存起来。后续调用 metaObjectsetValue 等方法时,直接在缓存中获取到反射对象,然后执行反射 *** 作。

创建MetaObject对象时,选择不同的Wrapper进行包装。

以普通的pojo为例,创建 BeanWrapper 对象,在 forClass 方法中会遍历object的所有方法。获取反射对象。

到此处:

到达此处,判断 缓存 中是否存在某对象的解析结果:

注意: MetaObjectforObject 会将object结果缓存起来,后续在使用MetaObjectforObject创建对象时,直接在缓存中获取。

若没有存在,则调用 new Reflector(type); 去创建cache对象。

总方法:

2 删除方法的前缀,获取属性名:

3 key为属性名,value是集合:

4 将局部变量放入到属性集合中:

5 放入到属性变量中

设置分词器:

>

*** 作。具体的步骤如下:

获取 MyBatis 中的 MappedStatement 对象。可以通过 SqlSession 的 getConfiguration() 方法获取 Configuration 对象,然后再通过 Configuration 对象的 getMappedStatement() 方法获取 MappedStatement 对象。

从 MappedStatement 对象中获取 BoundSql 对象,即 SQL 语句绑定的参数对象。

从 BoundSql 对象中获取 SQL 语句字符串。可以通过调用 getSql() 方法获取 SQL 语句字符串。

对 SQL 语句进行相应的 *** 作。例如,可以对 SQL 语句进行修改、输出等 *** 作。

Java 通过反射获取 MyBatis 中的 SQL 语句的代码示例:

SqlSession sqlSession = sqlSessionFactoryopenSession();

try {

// 获取 MappedStatement 对象

MappedStatement mappedStatement = sqlSessiongetConfiguration()getMappedStatement("comexamplemapperselectUser");

// 获取 BoundSql 对象

BoundSql boundSql = mappedStatementgetBoundSql(paramObject);

// 获取 SQL 语句字符串

String sql = boundSqlgetSql();

// 对 SQL 语句进行相应的 *** 作

//

} finally {

sqlSessionclose();

}

需要注意的是,在使用反射获取 SQL 语句时,要注意保护用户隐私和安全,以免发生 SQL 注入等问题。

  在对 ObjectWrapper 类的介绍中,除了 #hasGetter 、 #hasSetter 、 #getGetterType 、 #getSetterType 这几个方法,其余带 PropertyTokenizer 类型参数的方法中,参数代表的表达式已经是经过解析没有子表达式的形式了如 order[0] ,最终在 ObjectWrapper 中完成功能实现的最后一环,而表达式带多层子表达式的初始状态的解析过程正是在 MetaObject 类中进行的,对 MetaObject 的分析,聚焦于这个属性表达式的解析过程。

解析

  如果传入的对象是一个 ObjectWrapper 则直接使用,否则尝试用 ObjectWrapperFactory 创建 ObjectWrapper(假如用户自定义实现可用),如果以上情况都不满足,则先后尝试创建与对象类型相匹配的 ObjectWrapper,可选类型为 MapWrapper CollectionWrapper BeanWrapper

功能创建 MetaObject 对象的静态方法,也是唯一调用途径,因为构造方法为 private。

源码与注解

解析

  如果原始Java对象不为空,则调用构造方法创建对象,否则,使用特殊的用来表达原始对象为空的 SystemMetaObjectNULL_META_OBJECT , SystemMetaObject 类的定义如下:

功能获取表达式指定的原始对象中属性的值。

源码与注解

解析

  递归处理表达式的处理跟 ObjectWrapper 中的 #hasGetter 、 #hasSetter 、 #getGetterType 、 #getSetterType 类似,MetaClass 类中有个方法 #metaClassForProperty() 用来为对象属性创建对应的 MetaClass 对象,同样的 MetaObject 类中也有方法 #metaObjectForProperty() 用来为对象属性创建对应的 MetaObject 对象,其源码如下:

功能为表达式指定的原始对象中属性设置值。

源码与注解

解析

   #setValue() 跟 #getValue() 差别在于:如果顶层属性为空,肯定无法获取值,直接返回null;但是设置属性值,即使顶层属性为空,也可以先初始化顶层属性,再赋值。比如 userorderamount ,属性 user 是一个 User 对象,order 是其成员,类型为 Order,如果 order 为空,获取值时 order 的 amount 成员也必为空,但是设置值时,即使 order 为空,也可以先创建对象 order = new Order() 再给 orderamount 赋值。

  除了上述方法,其他方法只是类中定义属性的一个简单的 getter,或者是对 ObjectWrapper 接口方法的一个代理,方便外部程序直接调用 MetaObject 类中的方法就可以实现相应的功能。

以上就是关于mybatis是什么全部的内容,包括:mybatis是什么、springboot中,mybatis的mapper接口是如何生成代理对象的、mybatis笔记-MappedStatement等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9344710.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存