Mybatis(一)

Mybatis官网

Mybatis教程(W3C)

人人编程网:MyBatis 教程

框架概述

框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。

简而言之,框架其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。

框架是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题

使用框架的好处:框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率

这里就不得不提一下之前笔记提到过的三层架构了:

  • 表现层:是用于展示数据的
  • 业务层:是处理业务需求
  • 持久层:是和数据库交互的

三层架构

分层开发下的常见框架:

  • MyBatis:解决数据持久化问题的框架
  • SpringMVC:解决Web层问题的MVC框架
  • Spring:解决技术整合问题的框架

在我们之前的学习中,已经接触过一些和持久层技术解决方案的相关知识或概念。如:

  • 在JDBC技术中:Connection,PreparedStatement,ResultSet
  • Spring的JdbcTemplate:Spring中对jdbc的简单封装
  • Apache的DBUtils:它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装

但是这些都不是框架——JDBC是规范,而Spring的JdbcTemplate和Apache的DBUtils都只是工具类

在之前的学习中(JDBC笔记),我们可以发现有大量无需我们关注的代码。

Mybatis框架

mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。

采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

视频讲解

Mybatis的概述:Mybatis是一个持久层框架,用java编写的。Mybatis封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程。Mybatis使用了ORM思想实现了结果集的封装。

ORM全称是:Object Relational Mapping(对象关系映射),其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。

对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。

简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术

ORM:Object Relational Mappging 对象关系映射

简单的说:就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。

Mybatis入门

步骤:

  1. 创建maven工程并导入坐标
  2. 创建实体类和dao的接口
  3. 创建Mybatis的主配置文件:SqlMapConfig.xml
  4. 创建映射配置文件:UserDao.xml

环境准备

视频讲解

创建数据库表

创建user表,user表sql如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 插入数据
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');

创建后user表为:

user表结果

配置pom.xml

在生成的空Maven工程中添加<packaging>jar</packaging>,并写入相关依赖。

完整pom.xml文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>top.qing</groupId>
<artifactId>Mybatis01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencies>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>

<!--mysql连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>

<!--log4j日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
</dependencies>

</project>

创建User实体类和UserDao接口

在domain包下创建User类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package top.qing.domain;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}

Serializable接口概述:Serializable是java.io包中定义的、用于实现Java类的序列化操作而提供的一个语义级别的接口。 Serializable序列化接口没有任何方法或者字段,只是用于标识可序列化的语义。

Serializable接口

在dao包下创建UserDao接口,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package top.qing.dao;

import top.qing.domain.User;

import java.util.List;

public interface UserDao {
/**
* 查询所有结果
* @return
*/
List<User> findAll();
}

创建SqlMapConfig.xml和UserDao.xml

  • Mybatis的主配置文件:SqlMapConfig.xml
  • 映射配置文件:UserDao.xml

关于配置Xml的详细内容,可参考官网:

在resources目录下创建SqlMapConfig.xml,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的主配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!--配置连接数据库的四个基本信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置。映射配置文件指的是每个dao独立的配置文件
如果是有注解来配置的话,此处应该使用class属性指定被注解的dao全限定类型-->
<mappers>
<mapper resource="top/qing/dao/UserDao.xml"></mapper>
</mappers>
</configuration>

创建UserDao.xml代码如下:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.qing.dao.UserDao">
<!--配置查询所有结果-->
<select id="findAll" resultType="top.qing.domain.User">
select * from user
</select>
</mapper>

注意文件路径:

目录结构

这里记录一下Mybatis的Config约束和Mapper约束:

Config约束:

1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

Mapper约束:

1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

配置log4j.properties

在resources目录下创建log4j.properties代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

环境搭建的注意事项

注意事项:

  1. 创建UserDao.xml 和 UserDao.java时名称是为了和我们之前的知识保持一致。在Mybatis中持久层的操作接口名称和映射文件也叫做Mapper。所以,UserDao 和 UserMapper是一样的
  2. 在idea中创建目录的时候,它和包是不一样的。包在创建时:top.qing.dao它是三级结构。目录在创建时:top.qing.dao是一级目录
  3. Mybatis的映射配置文件位置必须和dao接口的包结构相同(如UserDao.java和UserDao.xml的包结构相同)
  4. 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名(如:<mapper namespace="top.qing.dao.UserDao">
  5. 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名(如<select id="findAll">

遵从了第3,4,5点之后,我们在开发中就无须再写dao的实现类

Mybatis入门程序

通过Xml文件方式

步骤:

  1. 读取配置文件
  2. 创建SqlSessionFactory工厂
  3. 创建SqlSession
  4. 创建Dao接口的代理对象
  5. 执行dao中的方法
  6. 释放资源

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	@Test
public void test1() throws IOException {
// 1.读取配置文件
InputStream inputStream = Resources.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
System.out.println(inputStream);
// 2.创建 SqlSessionFactory 的SqlSessionFactoryBuilder对象builder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3.使用builder创建工厂对象 SqlSessionFactory
SqlSessionFactory factory = builder.build(inputStream);
//4.使用 SqlSessionFactory 生产 SqlSession 对象
SqlSession session = factory.openSession();
//5.使用 SqlSession 创建 dao 接口的代理对象userDao
UserDao userDao = session.getMapper(UserDao.class);
//6.使用刚刚创建的代理对象userDao执行查询所有方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//7.释放资源
session.close();
inputStream.close();
}

结果如下:

查询结果

通过注解方式

MyBatis 注解方式的基本用法

MyBatis的常用注解以及简单使用

使用注解方式,就不需要配置UserDao.xml了。直接在UserDao接口上添加注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package top.qing.dao;

import org.apache.ibatis.annotations.Select;
import top.qing.domain.User;

import java.util.List;

public interface UserDao {
/**
* 查询所有结果
* @return
*/
@Select("select * from user")
List<User> findAll();
}

同时在SqlMapConfig.xml的mapper配置时,使用class属性指定dao接口全限定类名:

1
2
3
4
5
<!--指定映射配置文件的位置。映射配置文件指的是每个dao独立的配置文件
如果是有注解来配置的话,此处应该使用class属性指定被注解的dao全限定类型-->
<mappers>
<mapper class="top.qing.dao.UserDao"></mapper>
</mappers>

结果是一样的:

注意事项

在通过xml文件方式时:

  • 不要忘记在映射配置中告知mybatis要封装到哪个实体类中(如在UserDao.xml中:<select id="findAll" resultType="top.qing.domain.User">,即表明要将结果封装到User实体类中)
    • 配置的方式:指定实体类的全限定类名(resultType="top.qing.domain.User

mybatis基于注解的入门案例:

  • 把UserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句(如@Select("select * from user")

  • 同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。例如:

    1
    2
    3
    <mappers>
    <mapper class="top.qing.dao.UserDao"></mapper>
    </mappers>

我们在实际开发中,都是越简便越好。所以不管使用XML还是注解配置,都是采用不写dao实现类的方式。(但其实是可以写dao的实现类的)

视频讲解

小结:

通过入门示例,我们发现使用 mybatis 是非常容易的一件事情,因为只需要编写 Dao 接口并且按照mybatis 要求编写两个配置文件,就可以实现功能。远比我们之前的 jdbc 方便多了。(我们使用注解之后,将变得更为简单,只需要编写一个 mybatis 配置文件就够了。)

但是,这里面包含了许多细节,比如为什么会有工厂对象(SqlSessionFactory),为什么有了工厂之后还
要有构建者对象(SqlSessionFactoryBuilder),为什么 IUserDao.xml 在创建时有位置和文件名的要求等等。这些问题我们在将在下面的自定义 mybatis 框架中,通过层层剥离的方式,继续学习。

请注意:这里我们学习自定义 Mybatis 框架,不是让大家回去自己去写个 mybatis,而是让我们能更好地了解mybatis 内部是怎么执行的,在以后的开发中能更好的使用 mybatis 框架,同时对它的设计理念(设计模式)有一个认识。

入门案例设计模式分析

视频讲解

入门案例的分析

自定义Mybatis

自定义Mybatis的分析:mybatis在使用代理dao的方式实现增删改查时做什么事呢?

只有两件事:

  1. 创建代理对象

  2. 在代理对象中调用selectList

Mybatis分析

在自定义Mybatis之前,我们要先分析一下Mybatis的入门程序

  • 执行查询所有的分析
  • 创建代理对象的分析

执行查询所有的分析

视频讲解

执行查询所有的分析

创建代理对象的分析

视频讲解

创建代理对象的分析

自定义Mybatis分析

开始自定义Mybatis

此案例所在仓库地址:https://gitee.com/qingyu1011/springboot_study/tree/master/SSM/Mybatis/Mybatis01_design

这里我们将使用前面所学的基础知识来构建一个属于自己的持久层框架,将会涉及到的一些知识点:工厂模式(Factory 工厂模式)构造者模式(Builder 模式)代理模式,反射,自定义注解,注解的反射,xml 解析,数据库元数据,元数据的反射等

Java设计模式:23种设计模式全面解析(超级详细)

视频讲解

自定义mybatis能通过入门案例看到类:

  • class Resources
  • class SqlSessionFactoryBuilder
  • interface SqlSessionFactory
  • interface SqlSession

准备工作

首先要创建一个Maven工程,大体和上述Mybatis入门程序(通过xml文件解析)相同,但是在pom.xml文件中的<dependencies>标签要进行修改,改为以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<dependencies>
<!-- 日志坐标 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>

<!-- 解析 xml 的 dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>

<!-- mysql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>

<!-- dom4j 的依赖包 jaxen -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>

<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>

<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>

</dependencies>

因为这里我们要自定义Mybatis,所以就没有添加Mybatis依赖。

同时将Mybatis入门程序的src下的两个文件夹复制到我们的自定义程序中,同时将SqlMapConfig.xml和UserDao.xml文件的约束删掉。

可以发现由于没有导入mybatis依赖(因为我们要自定义嘛),之前的测试类中已经开始报错了:

基于Xml的自定义Mybatis框架

创建测试类中缺少的接口和类

在top.qing.mybatis.io包下创建Resources类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package top.qing.mybatis.io;

import java.io.InputStream;

/**
* 使用类加载器读取配置文件(用于读取配置文件)
*/
public class Resources {
/**
* 用于加载xml文件,并且得到一个流对象
* @param xmlPath
* @return
*/
public static InputStream getResourceAsStream(String xmlPath){
return Resources.class.getClassLoader().getResourceAsStream(xmlPath);
}
}

在实际开发中读取配置文件,有以下两种方式:

  • 使用类加载器(getClassLoader())。但是有要求:a 文件不能过大。 b 文件必须在类路径下(classpath)
  • 使用 ServletContext 的 getRealPath()

深入理解Java类加载器(ClassLoader)

然后在top.qing.sqlsession包下创建SqlSessionFactoryBuilder类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package top.qing.mybatis.sqlsession;

import top.qing.mybatis.config.Configuration;
import top.qing.mybatis.sqlsession.impl.SqlSessionFactoryImpl;
import top.qing.mybatis.utils.XMLConfigBuilder;

import java.io.InputStream;

/**
* 用于创建SqlSessionFactory对象
*/
public class SqlSessionFactoryBuilder {
/**
* 根据字节流参数,实现对SqlSessionFactory对象的创建
* @param config 其实就是SqlMapConfig.xml和UserDao.xml的配置
* @return
*/
public SqlSessionFactory build(InputStream config){
Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
return new SqlSessionFactoryImpl(cfg);

}
}

同时创建SqlSessionFactory接口和实现类,代码分别如下:

1
2
3
4
5
6
7
8
9
10
11
12
package top.qing.mybatis.sqlsession;

/**
* SqlSessionFactory接口
*/
public interface SqlSessionFactory {

/**
* 创建一个SqlSession对象
*/
SqlSession openSession();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package top.qing.mybatis.sqlsession.impl;

import top.qing.mybatis.config.Configuration;
import top.qing.mybatis.sqlsession.SqlSession;
import top.qing.mybatis.sqlsession.SqlSessionFactory;


public class SqlSessionFactoryImpl implements SqlSessionFactory {
private Configuration cfg;

public SqlSessionFactoryImpl(Configuration cfg) {
this.cfg = cfg;
}

/**
* 创建一个SqlSession对象(数据库连接对象)
* @return
*/
@Override
public SqlSession openSession() {
return new SqlSessionImpl(cfg);
}
}

然后创建SqlSession接口和实现类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package top.qing.mybatis.sqlsession;

/**
* 操作数据库的核心对象
* 自定义Mybatis中和数据库交互的核心类,里面可以创建dao接口的代理对象
*/
public interface SqlSession {
/**
* 根据参数(dao接口的字节码)创建一个Dao接口的代理对象
* @param daoInterfaceClass
* @param <T>
* @return
*/
<T> T getMapper(Class<T> daoInterfaceClass);

/**
* 释放资源
*/
void close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package top.qing.mybatis.sqlsession.impl;

import top.qing.mybatis.config.Configuration;
import top.qing.mybatis.sqlsession.SqlSession;
import top.qing.mybatis.sqlsession.proxy.MapperProxy;
import top.qing.mybatis.utils.DataSourceUtil;

import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

public class SqlSessionImpl implements SqlSession {

private Configuration cfg;
private Connection connection;

public SqlSessionImpl(Configuration cfg) {
this.cfg = cfg;
connection = DataSourceUtil.getConnection(cfg);
}

/**
* 创建代理对象
* @param daoInterfaceClass dao接口的字节码
* @param <T>
* @return
*/
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
}

/**
* 释放资源
*/
@Override
public void close() {
if(connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}

解析xml的工具类

这里我们在utils包下创建XMLConfigBuilder工具类,使用dom4j+xpath技术解析xml。具体代码就不在此展开了,可去代码仓库查看。

由于直接导入了XMLConfigBuilder工具类,相应的也出现了一些错误,需要我们解决一下

在mybatis.config包下创建Configuration类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package top.qing.mybatis.config;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
* 自定义Mybatis的核心配置类
* 1.数据库信息
* 2.sql的map集合
*/

public class Configuration {
private String username; //用户名
private String password;//密码
private String url;//地址
private String driver;//驱动

//map 集合 Map<唯一标识,Mapper> 用于保存映射文件中的 sql 标识及 sql 语句
private Map<String,Mapper> mappers = new HashMap<String, Mapper>();

public Map<String, Mapper> getMappers() {
return mappers;
}

public void setMappers(Map<String, Mapper> mappers) {
this.mappers.putAll(mappers); // 此处需要使用追加的方式
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getDriver() {
return driver;
}

public void setDriver(String driver) {
this.driver = driver;
}
}

创建Mapper类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package top.qing.mybatis.config;

import lombok.Data;

/**
* 用于封装查询时的必要信息:
* 1.要执行的sql语句
* 2.实体类的全限定类名
*/
@Data
public class Mapper {
private String queryString; //sql
private String resultType; //结果类型的全限定类名
}

执行结果

其他上述没有说明的代码可自行查看仓库。

所有代码完成后,我们执行测试类,发现成功运行:

基于Xml的自定义Mybatis成功运行

基于注解的自定义Mybatis框架

这里就不多说了

视频讲解

自定义Mybatis流程分析

流程分析

视频讲解

自定义 Mybatis 的设计模式说明

Java设计模式:23种设计模式全面解析(超级详细)

设计模式菜鸟教程

  • 工厂模式(Factory Pattern):在自定义Mybatis中体现在SqlSessionFactory
  • 代理模式(Proxy Pattern):在自定义Mybatis中体现在MapperProxyFactory
  • 构建者模式(Builder Pattern):在自定义Mybatis中体现在SqlSessionFactoryBuilder

工厂模式(Factory Pattern)

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

工厂模式的原理如下图:

工厂模式原理

代理模式(Proxy Pattern)

所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。

组成:

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法
  • 代理角色:实现抽象角色,是真实创建者模式是java23种设计模式之一,英文叫Builder Pattern。其核心思想是将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构件算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用

代理模式分为静态和动态代理。

  • 静态代理:有一个写好的代理类,实现与要代理的类的一个共同的接口,目的是为了约束也为了安全。
  • 动态代理:在程序运行时,运用反射机制动态创建而成

我们知道静态代理若想代理多个类,实现扩展功能,那么它必须具有多个代
理类分别取代理不同的实现类。这样做的后果是造成太多的代码冗余。那么我们会思考如果做,才能既满足需求,又没有太多的冗余代码呢?——动态代理。通过前面的课程我们已经学过了基于 JDK 的动态代理实现方式,今天我们就会使用 JDK 动态代理方式来编写 MapperProxyFactory 类。

动态代理模型图:

构建者模式(Builder Pattern)

创建者模式其核心思想是将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构件算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。

具体设计模式的模型图如下:

从图中我们可以看出,创建者模式由四部分组成:

  • 抽象创建者角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体创建者角色。具体创建者必须实现这个接口的两种方法:
    1. 建造方法,比如图中的 buildPart1 和 buildPart2 方法
    2. 结果返回方法,即图中的 getProduct 方法。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少零件,就有多少相应的建造方法
  • 具体创建者角色:他们在应用程序中负责创建产品的实例。这个角色要完成的任务包括:
    1. 实现抽象创建者所声明的抽象方法,给出一步一步的完成产品创建实例的操作
    2. 在创建完成后,提供产品的实例
  • 导演者角色:这个类调用具体创建者角色以创建产品对象。但是导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体创建者角色
  • 产品角色:产品便是建造中的复杂对象。一般说来,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以使不相关联的