Java框架MyBatis工作流程是怎样的

Java框架MyBatis工作流程是怎样的,第1张

MyBatis-plus是完全基于MyBatis开发的一个增强工具,是在MyBatis的基础上做增强的框架,为简化开发、提高效率而生。

它在MyBatis原本的框架上增加了很多实用性功能,比如乐观锁插件、字段自动填充功能、分页插件、条件构造器、sql 注入器等等。使用 MyBatis-plus 可以完全不写任何 XML 文件,直接使用继承了BaseMapper 接口的类对象完成对数据库的映射 *** 作

基于映射的原理,MyBatis-plus 必然要实现 Mapper中的方法与 SQL 语句的对应转化,以下即为 MyBatis-plus 重要流程图例

1在 MyBatis-plus 中, MybatisPlusAutoConfiguration 自动配置类的 sqlSessionFactory() 方法为 Spring提供创建 sqlSession 的工厂类对象,对 sqlSessionFactory 进行定义的定义类变为了 MybatisSqlSessionFactoryBean 。

在 sqlSessionFactory() 方法中,除了注入 MyBatis本身的组件,还会注入MyBatis-plus 的 主键生成器、SQL 注入器等组件,最后通过 MybatisSqlSessionFactoryBean#getObject() 方法获取到 sqlSessionFactory 对象

2 MybatisSqlSessionFactoryBean#getObject() 执行懒加载策略,最后通过 buildSqlSessionFactory() 方法创建 SqlSessionFactory 工厂类对象。这个方法的流程很长,不过大致可以分为两个步骤:

3 MybatisXMLConfigBuilder#parse() 会去解析配置文件,最后会调用到其内部方法 mapperElement() 。这个方法完成解析 Mapper工作,并将其添加到配置类 MybatisConfiguration 中

4 MybatisConfiguration#addMapper() 方法其实是去调用 MybatisMapperRegistry#addMapper() 方法,其核心是 MybatisMapperAnnotationBuilder#parse()

5 MybatisMapperAnnotationBuilder#parse() 方法真正开始完成 Mapper 接口中的方法与 SQL 语句的映射,其中 parseStatement() 方法是解析 @Select/@Update 等注解写入的 SQL语句,而代码 GlobalConfigUtilsgetSqlInjector(configuration)inspectInject(assistant, type ) 通过 MaBatis-plus的 SQL 注入器完成 Mapper 方法与 SQL 语句的转化

6 AbstractSqlInjector#inspectInject() 会完成 BaseMapper 接口中提供的通用方法对应的 SQL 语句准备,这部分主要通过 AbstractMethod#inject() 方法完成

7 AbstractMethod#inject() 方法并没有什么特别的 *** 作,只是调用其子类实现 injectMappedStatement() 方法。以 SelectOne#injectMappedStatement() 为例,其 SQL 语句的核心在于 SqlMethod 类,这个枚举类中缓存了可以动态拼接的 SQL 语句脚本,只需要填上参数 format 就可以得到 SQL 语句的执行脚本。

以上过程结束,只需要将所有信息通过 addInsertMappedStatement() 方法封装成 MappedStatement 对象并将其加入到容器中,这样 Mapper接口方法调用时,就可以通过 动态代理 的方式找到其对应执行的 SQL 脚本,至此 SQL 语句准备及配置解析就完成了。

最后拼接的 SQL 语句 脚本形式如下示例,实际执行数据库 *** 作时会解析这个脚本完成变量替换,从而得到可执行的 SQL 语句

8 SqlSessionFactory 对象的创建需要回到 MybatisSqlSessionFactoryBean#buildSqlSessionFactory() 方法中,很容易追踪到 MybatisSqlSessionFactoryBuilder#build() 方法,最后其实是通过 SqlSessionFactoryBuilder#build() 方法创建了一个 DefaultSqlSessionFactory 对象返回

1 @MapperScan 注解通过 @Import(MapperScannerRegistrarclass) 引入扫描注册的类 MapperScannerRegistrar ,该类实现了 ImportBeanDefinitionRegistrar 接口并重写 registerBeanDefinitions() 方法,在该方法中注册了 MapperScannerConfigurer 类

2 MapperScannerConfigurer 是 Mapper接口的扫描配置类,实现了 BeanDefinitionRegistryPostProcessor 接口,其 postProcessBeanDefinitionRegistry() 方法会在容器启动过程中被回调,通过 ClassPathMapperScanner#scan() 方法完成 Mapper 的扫描注册

3 ClassPathMapperScanner#processBeanDefinitions() 将扫描到的 Mapper接口生成的对应 BeanDefinition 的 beanClass 属性替换为 MapperFactoryBean ,这样每次获取 Mapper 实例实际是通过 MapperFactoryBean 的实例去获取

此处体现了 FactoryBean 的定位,即用于获取同一类 bean 的工厂 bean。

4 @Autowired 自动注入 Mapper 触发容器获取 bean 的方法,调用到 MapperFactoryBean#getObject() 方法,最终调用到 sqlSessionTemplate#getMapper() 方法

5MyBatis-plus 使用的配置类是 MybatisConfiguration ,最终调用到 MybatisMapperRegistry#getMapper() 方法,这里就进入了动态代理获取 MapperProxy 实例的流程

6 MybatisMapperProxyFactory#newInstance() 方法给自动注入返回一个 MybatisMapperProxy 代理对象

7调用 Mapper 接口的方法触发代理对象的 MybatisMapperProxy#invoke() ,此时根据 Mapper 对象被调用的方法生成 MybatisMapperMethod 对象,通过 MybatisMapperMethod#execute() 去真正地执行 SQL 语句,从而完成数据库 *** 作。

import javasqlConnection ;

import javasqlDriverManager ;

import javasqlSQLException ;

public class ConnectionDemo{

// 定义MySQL的数据库驱动程序

public static final String DBDRIVER = "orggjtmmmysqlDriver" ;

// 定义MySQL数据库的连接地址

public static final String DBURL = "jdbc:mysql://localhost:3306/mldn" ;

// MySQL数据库的连接用户名

public static final String DBUSER = "root" ;

// MySQL数据库的连接密码

public static final String DBPASS = "mysqladmin" ;

public static void main(String args[]){

Connection conn = null ; // 数据库连接

try{

ClassforName(DBDRIVER) ; // 加载驱动程序

}catch(ClassNotFoundException e){

eprintStackTrace() ;

}

try{

conn = DriverManagergetConnection(DBURL,DBUSER,DBPASS) ;

}catch(SQLException e){

eprintStackTrace() ;

}

Systemoutprintln(conn) ; // 如果此时可以打印表示连接正常

try{

connclose() ; // 数据库关闭

}catch(SQLException e){

eprintStackTrace() ;

}

}

};

比如我们在引入了jdbc的配置文件使用了properties标签,引入jdbc有什么好处?,可以在配置文件中统一管理

内容而不是在很多个文件改来改去,而且在核心配置文件中把数据库连接相关的写死,显然是硬编码的所以我们用配置文件代替 nice!!!

你可能注意到了上面的写法 用前缀jdbc 可以很好地将他们与其他的变量区分开,(可以从名字很容易看出是jdbc相关的数据,不至于和同名变量搞混因为username这种可能

不止会出现在数据库的连接)

上面的代码中引入配置文件的部分为

可以从上面看到写法:

下面这段就是用来设置类的别名:

那么问题来了,为什么要有类的别名这种 *** 作??

因为在映射文件中每次都要写全类名显然有点麻烦比如下面这样:

一个项目是会有很多个映射文件的为了方便,所以类别名就出现了。可以在核心配置文件写接口类和对应的别名

这样就可以在映射文件的命名空间里可以直接写User(对大小没有要求也可以是user; 其实可以比这更加简单,也是我们在实际开发中常用的写法

就是将整个包写成别名的形式,如果不写alias属性默认为类名(不区分大小写),这样就容易多了,我们只需一行代码,便可以在所有的映射文件命名空间

中直接写对应的类名

引入核心的配置文件

首先需要思考的这里是映射文件的引入,我们正常的一个项目的数据库是有很多个表组成的那么每一张表对应一个mapper接口,每个接口对应一个映射文件,那么就需要导入大量的映射文件,还容易漏掉-->

上面这种以包的形式的导入非常方便,不用每次新建一个接口就要导入它的映射文件,但是上面这种写法需要 注意 一些问题:

如果你在映射文件中编写查询语句的sql,但是粗心的你忘记了设置返回类型会在控制台抛异常且会看到这样的说明:

It's likely that neither a Result Type nor a Result Map was specified

下面只是指定返回类型的一种方式:resultType,还有 resultMap

它们的区别:

查询的标签必须指定resultType或resultMap

comkobedumybatis 获取参数的两种方式:${} 和 #{}

上面是使用了 #{}写法相当于原生jdbc的占位符,这个前面已经提到过了所以不多赘述, 需要注意的是#{}里面的变量名可以是任意的username规范显然很好,但是aaaa也没错因为只是用来占位的;

还有就是在使用${}时注意''单引号问题,因为${}是字符拼接的方式,所以需要注意!!

传输参数时有多个参数时

在测试代码里通过传入两个参数分别为 username和password 但是在上面代码的(映射文件里的部分代码)执行失败,(sql语句未能解析)

报错:

Cause: orgapacheibatisbindingBindingException: Parameter 'username' not found Available parameters are [arg1, arg0, param1, param2]

可以从错误提示的信息不难发现我们的参数在映射文件里未能真正地接受到,可以用[arg1, arg0, param1, param2] 的方式获取,mybatis将参数放到map容器可以通过建arg0,agr1的方式

获取参数(也可以是param1,param2)

将上面的代码改动:

需要注意的是:使用${}时需要手动添加''才能正常访问,因为他的处理方式是字符串的拼接

做了改动之后结果很感人!!

User{id=6, userName='旺财', age=20, password='cwlz'}

可以直接通过键访问相对应的值(通过自己的方式访问到数据,上面的形式是mybatis默认提供的map和mybatis默认的提取指的方式 arg0,arg2)

当需要传多个参数时将他们放到一个map容器,然后将map传给对应的方法(模拟mybatis的做法,就可以在sql语句中直接通过键访问到值)代码如下:

映射文件中的部分代码 :

通过键直接获取值,注意:使用${}时不要忘了单引号!!!!

当参数以实体对象的形式传参时如何解决?

只需要通过#{}以属性名的方式访问!

所以代码的编写一定要规范,才能减少这种错误!!!

一定要和注解中的参数名一一对应!!!

如果查询的结果只有一个,也可以通过Map集合接收,字段名为键字段的值为值:{password=0000, id=3, userName=图区, age=20}

javalangIngeger --> int ,Integer

int --> _int,_Integer

Map --> map

String --> string

注意:

所以在批量删除的案例:需要注意的是不能使用#{} 因为它是会自动添加'' 所以在批量删除的语句中我们要使用${}

若字段和属性名不一致 ,则可以通过resultMap设置自定义映射

在mybatis的核心配置文件用下面的代码将 数据库中命名的规范 (user_name) 转换为 java中的命名规范 (userName)

就是手动设置属性与字段的映射关系:

如果设置了手动的设置属性和字段的映射关系,注意主键使用 id 标签,普通字段使用 result标签,就算属性和字段名一一对应,只要

用了这种方式就 必须要写全 !!!

一对多的查询:

通过分步查询实现:

多条件的查询

if 根据标签中test的属性所对应的表达式决定标签中的内容是否拼接到sql语句中

上面的where后面的 1=1 是细节,因为当where后面的条件都为空时就成了 select from t_user where

显然这种sql语句是有问题的,还有一种情况就是当userName为null时语句就成了 select from t_user where and age=#{age}

这也是错的,所以在where后加一个恒成立的条件不仅不会影响查询结果,而且没有会在特定情况时sql语句是会报错的所以很有必要

where 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and 或者or去掉

当where中没有内容时,此时where标签没有任何效果 就是不会生成关键字 注意:在写条件时不能在后面加and or 这个在下一条语句无效时mybatis不会帮你去掉!

相当于 if else

一个案例 -->就是当我们需要批量删除一些东西时(参数以数组的形式传入)

sql 片段: 在我们的查询语句不能在实际开发中也一直写 ;因为我们要按需查找,不必将不需要的也查询出来,我们可以将我们平常查询次数较多的字段

放在sql片段内,可以在需要查询时直接进行引用!

缓存,这个术语我们听过很多次,在web阶段时访问网页时有缓存机制!

现在sql的查询时也有缓存机制,有一级缓存,一级缓存是默认开启的,一级缓存的范围时sqlSession,将我们查询到的数据先进行缓存,若下次有相同的查询时不用重新

访问数据库,可以直接从缓存中取出!!!!

手动清空缓存 sqlSessionclearCache();

在mapper配置文件中添加cache标签可以设置一些属性:

逆向工程就是不难理解,我们之前都是由实体类到数据库,而逆向类就是通过数据库表生成实体类,

以上就是关于Java框架MyBatis工作流程是怎样的全部的内容,包括:Java框架MyBatis工作流程是怎样的、spring mvc中的mybatis怎么使用、MyBatis-Plus 使用这么方便,底层是如何处理的呢等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址: http://outofmemory.cn/sjk/10189015.html

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

发表评论

登录后才能评论

评论列表(0条)

保存