在学习mybatis之前,首先回忆传统jdbc如何访问数据库。传统jdbc 访问数据库首先需要导入驱动jar包,然后在后端的持久层进行访问数据库,具体步骤为:
注册驱动。根据不同的数据库注册不同的驱动,例如mysql、oracle等
获取数据库连接。获取连接是利用DriverManage生成Connection类型连接。在此处需要填写数据库的账号密码和地址。
定义Sql语句。例如在此处编写好字符串类型的增删改查Sql语句。
获取执行Sql对象。执行sql语句的是Statement对象,而获取Statement对象是通过第二步的Connection获取。Mybatis其本质也是通过Statement操作数据库。但是Mybatis与传统jdbc不同,不同在于不需要重复的申请数据库连接。
执行sql语句。执行sql语句是利用Statement对象执行,Statement对象有executeQuery、executeUpdate 和execute。executeQuery执行数据库查询,executeUpdate 执行数据库增删改。Mybatis底层依旧使用的是这些方式操作数据库。
接受返回集,处理数据,关闭连接。
不同于传统jdbc,Mybatis是将传统jdbc进行封装,例如传统jdbc第1、2步,只需要配置xml文件即可,同时编程人员操作数据库时不同频繁的操作java类,使编程人员从底层重复代码中脱离出来,更多的关注程序的逻辑实现。对于Mybatis,它更多采用了配置xml文件的形式操作数据库和配置自己。与传统jdbc执行步骤相比,Mybatis具体的执行流程如图1。
图1 Mybatis执行流程
在MyBatis启动的时候,主要任务是解析配置文件。配置文件来源于全局配置文件(Mybatis-config.xml)、映射器配置文件(Mapper.xml),Mapper.xml包含如何控制MyBatis的行为和Sql语句,以及入参类型,返回值映射。解析配置文件后,程序会把这些信息解析成一个Configuration对象,由Configuration统一管理配置信息。
在程序调用数据库操作的时候,Mybaits它在应用程序和数据库之间建立连接,就是创建了SqlSession对象。SqlSession对象由会话工厂SqlSessionFactory创建,SqlSessionFactory包含所有的配置信息,在容器初始化的时候由SqlSessionFactoryBuilder创建。此处可以类比传统jdbc中的Connection,只是获取了数据库连接,但是并未向数据库发出具体的执行语句指令。
在执行数据库操作的时候,SqlSession将具体操作委托于Executor对象,由Executor执行操作。在此处Executor会解析Sql语句,Executor对象利用StatementHander操作动态Sql,将参数等与动态Sql结合,生成可执行的Sql语句。同时也将在这里完成结果集映射,将数据库中的字段与java类一一对应。此处对应传统jdbc操作的c、d、e步骤。
从上文的步骤可以发现,在实际的开发中,我们只需要关注配置文件和编写少量的Sql语句即可以完成操作数据库。并且在返回值类型中,以封装对象的形式存在,方便了我们的日常开发。从Mybatis执行流程也可以发现,整个Mybatis的执行流程从SqlSession开始,到StatementHande结束,与程序员接触的只是SqlSession接口。SqlSession是每个mapper.xml文件共有的数据会话接口,也即即使有很多mapper.xml文件,而SqlSession只有一个。也区别与传统的jdbc,每一次访问数据库都需要创建新的数据库连接,而造成的资源浪费。
依靠Mybatis 的执行流程,Mybatis 框架结构可以总结为如图2所示。
图2 Mybatis框架结构
Mybatis 框架结构大体与执行流程相类似。 Mybatis有众多优点,其中最重要的是节约资源,原生jdbc除了代码大量复写的缺点,最大的缺点是与数据库连接的重复申请,造成了数据库资源的浪费。在节省资源方面,Mybatis采用了数据库连接池,数据库连接池是负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个,这项配置在Mybatis中也有明显的体现。另外,Mybatis也采用了缓存机制,将频繁访问的数据存放到缓存中,避免了重复访问数据库。
Mybatis 是操作数据库的框架,数据的安全是很重要的。Mybatis 提供了数据库防注入的措施。数据库注入是常见的数据库安全问题,原因是在sql语句预编译阶段插入了其他sql语句,导致数据库执行了错误指令。在Mybatis 里,通过底层实现预编译而避免发生数据注入,具体用法是#和$的区别。#在底层通过prepareStatement预编译实现类对当前传入的sql进行了预编译,避免错误指令产生。而$首先进行字符串拼接,再进行编译,如此就容易产生数据注入。