1 前言
mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句,最后由框架执行sql并将结果映射为java对象并返回。
采用ORM(Object Relational Mapping)思想解决了实体和数据库映射的问题,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
评论领取源码
2 Mybatis框架快速入门
2.1 搭建Mybatis开发环境(使用.xml配置)
数据库准备
1 | mysql复制代码USE DATABASE eesy; |
2.1.1 添加Mybatis3.4.5的坐标
首先创建maven工程,之后在pom.xml中添加坐标,如下:
1 | xml复制代码<dependencies> |
2.1.2 数据库User表对应的实体类
1 | java复制代码package domain; |
2.1.3 dao层
1 | java复制代码package dao; |
2.1.4 编写Dao层接口的映射文件UserDao.xml
创建位置:必须和dao接口在相同的包中。
名称:必须以持久层接口名称命名文件名,扩展名是.xml
)
mapper标签namespace属性的取值必须是dao接口的全限定类名;
操作配置(select),id属性的取值必须是dao接口的方法名
1 | xml复制代码<?xml version="1.0" encoding="UTF-8"?> |
2.1.5 编写 SqlMapConfig.xml 配置文件
1 | xml复制代码<?xml version="1.0" encoding="UTF-8"?> |
2.1.6 测试类
程序套路比较固定,基本步骤如下:
- 读取配置文件
- 创建SqlSessionFactory工厂
- 创建SqlSession
- 创建dao接口的代理对象 getMapper()
- 执行dao中的方法
- 释放资源
1 | java复制代码package test; |
2.2 使用注解开发方法
使用注解时,就不需要 resources/dao/UserDao.xml 文件了
在dao接口的方法上使用@Select注解,并且指定SQL语句
UserDao.java 中
1 | java复制代码package dao; |
SqlMapConfig.xml 全局配置文件里,如果使用注解来配置的话,应该是用class属性指定被注解的dao全限定类名
1 | xml复制代码<mappers> |
2.3 设计模式分析
在编写测试类时,按照了六个步骤来进行的,其中涉及到了构建者、工厂、代理等设计模式。
1 | java复制代码SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); |
创建工厂时使用了构建者模式,可以把对象的创建细节隐藏,使得使用者直接调用方法即可拿到对象。
1 | java复制代码SqlSession session = factory.openSession(); |
生产SqlSession使用了工厂模式,可以降低类之间的依赖关系(解耦)。
1 | java复制代码UserDao userDao = session.getMapper(UserDao.class); |
创建Dao接口实现类使用了代理模式,可以在不修改源码的基础上对已有方法增强。
注意:
实际应用时,绝对路径和相对路径都不可用,(在部署成webapp后src目录没了)
所以实际中只用两种方法:
- 类加载器,但只能读取类路径的配置文件
- 使用ServletContext的getRealPath()获得绝对路径
mybatis在使用代理dao的方式实现增删改查时:
- 创建代理对象
- 在代理对象中调用selectList
3 自定义Mybatis框架
3.1 查询所有分析
selectList方法大致分为五步:
- 根据配置文件创建Connection对象
- 获取预处理对象PreparedStatement
- 执行查询操作
- 遍历查询结果集并封装为List
- 返回List对象
其中第一步需要配置文件SqlMapConfig.xml中的信息,解析xml的技术已经成熟,这里不做赘述。
1 | xml复制代码<property name="driver" value="com.mysql.jdbc.Driver"/> |
第二步获取预处理对象PreparedStatement
1 | java复制代码conn.prepareStatement(queryString); |
需要传入sql语句,需要用到UserDao.xml中定义的sql语句
1 | xml复制代码<mapper namespace="dao.UserDao"> |
第四步进行数据的封装,需要知道数据库中存储的数据对应的java中的类
对应上面代码中的 resultType
纵观整个解析的过程,如果想要让selectList方法执行,还必须要提供映射信息,映射信息包含两部分:sql和封装结果的实体类名,可以将这两个信息封装成一个映射类Mapper作为map的value,其中map的key为类似于”dao.UserDao.findAll”的字符串。
具体流程如下图:
)
总结一下:
SqlMapConfig.xml 中包含连接数据库的信息、映射配置信息
UserDao.xml 中包含sql语句和封装的实体类信息
可以使用dom4j技术来解析xml
3.2 创建代理对象的分析
1 | java复制代码// 使用SqlSession创建Dao接口的代理对象 |
getMapper的具体实现如下:
1 | java复制代码public <T> T getMapper(Class<T> daoInterfaceClass) { |
使用代理
第一个参数是类加载器:使用和被代理对象相同的类加载器
第二个参数是代理对象要实现的接口:和被代理对象实现相同的接口
第三个参数是如何代理:我们自己提供一个增强的方法
3.3 使用Mybatis时用到的类(接口)
class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
interface SqlSession
3.4 准备工作
将之前写的Mybatis测试类中所需要的方法创建出来
)
3.4.1 Resources 类
1 | java复制代码package mybatis.io; |
3.4.2 SqlSession 接口
1 | java复制代码package mybatis.sqlsession; |
3.4.3 SqlSessionFactory 接口
1 | java复制代码package mybatis.sqlsession; |
3.4.4 SqlSessionFactoryBuilder 类
1 | java复制代码package mybatis.sqlsession; |
3.5 解析XML的工具类介绍
1 | java复制代码package mybatis.utils; |
需要在 pom.xml 中导入 dom4j、jaxen
1 | xml复制代码<dependency> |
3.5.1 在 mybatis.cfg 包下创建Configuration类和Mapper类
Configuration类中存储了”dao.UserDao.findAll”与一个Mapper对象的映射
Mapper对象中封装 执行的SQL语句 以及 结果类型的全限定类名
由于可能有多条sql语句,所以Configuration中的setMappers方法应该不断地往map中追加数据,而不是替换,使用 putAll 追加数据时必须先把map new出来,不然空指针。
1 | java复制代码package mybatis.cfg; |
1 | java复制代码package mybatis.cfg; |
3.6 SqlSessionFactoryBuilder 类的实现
1 | java复制代码package mybatis.sqlsession; |
SqlSessionFactoryBuilder 类中有一个 public SqlSessionFactory build(InputStream config)方法,需要返回一个SqlSessionFactory的对象。
3.6.1 SqlSessionFactory 接口的实现类
1 | java复制代码package mybatis.sqlsession.defaults; |
SqlSessionFactory 中有一个 public SqlSession openSession() 方法,需要返回一个SqlSession的对象。
3.6.2 SqlSession 接口的实现类
1 | java复制代码package mybatis.sqlsession.defaults; |
DefaultSqlSession 中使用到的工具类 DataSourceUtil 为:
1 | java复制代码package mybatis.utils; |
该类的 public T getMapper(Class daoInterfaceClass) 方法通过代理模式来实现
1 | java复制代码public static Object newProxyInstance(ClassLoader loader, |
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
需要定义一个类 MapperProxy 来作为上面的h,该类必须实现 InvocationHandler 接口:
1 | java复制代码package mybatis.sqlsession.proxy; |
MapperProxy 中的使用到的工具类 Execute 为(中间定义了selectList方法):
1 | java复制代码package mybatis.utils; |
3.7 基于注解的查询所有
修改 resources.SqlMapConfig.xml 中的语法为注解相应的形式:
1 | xml复制代码<mappers> |
给 dao.UserDao 添加注解:
1 | java复制代码@Select("select * from user") |
新建一个 mybatis.annotations.Select 注解:
1 | java复制代码package mybatis.annotations; |
在 utils.XMLConfigBuilder 中添加根据传入的参数,得到dao中所有被select注解标注的方法:
基于反射的原理,传入一个全限定类名,再通过这个类名获取字节码对象、方法,将带有注解的方法的相关信息加入到Mapper对象中。
1 | java复制代码/** |
此时运行test程序即可看到查询数据库的结果。
本文转载自: 掘金