Mybatis3源码分析:前期准备
回复“1024”获取最新大厂面试资料
背景
Mybatis应该是国内最流行的ORM框架,大多项目中我们应该都是使用的 Mybatis。Mybatis 中的 sql 大多都是配置在 xml 文件中的,我们为了方便 dba 对 sql 统一的管理需要将 sql 保存在数据库中。这样就要求 Mybatis 从数据库中加载配置,同时 dba 优化 sql 之后还得实现让 Mybatis 在不重启应用的情况下动态加载。要实现这些功能,需要对 Mybatis 进行扩展,所以本人花了一些时间分析一 Mybatis3 源码,在此记录。
分析计划
主要分析如下三大内容:
-
分析 Mybatis 是怎么解析配置文件 -
分析 Mybatis 是如何执行 Sql 并映射结果 -
分析 Mybatis 是如何使用缓存的
技术要求
-
core java。尤其是 jdbc 部分。 -
基本的 xml 知识。 -
以上都具备的话,还需要花点时间看看 Mybatis
环境准备
在 IDEA 中新建一个普通的 maven 工程,并加上 Mybatis 的依赖
<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>com.zzw</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>
数据模型
用户定义
package com.zzw.mybatis.entity;
import java.util.List;
public class User {
private long id;
private String username;
private List<Account> accounts;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
}
账户定义
package com.zzw.mybatis.entity;
public class Account {
private String id;
private String payName;
private String bankNo;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPayName() {
return payName;
}
public void setPayName(String payName) {
this.payName = payName;
}
public String getBankNo() {
return bankNo;
}
public void setBankNo(String bankNo) {
this.bankNo = bankNo;
}
}
Mybatis 配置
mybatis-config.xml
<?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">
<configuration>
<!--引入mysql配置-->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<!--事务管理-->
<transactionManager type="JDBC"/>
<!--数据库连接处-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--映射器-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.xml
<?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="com.zzw.mybatis.dao.UserMapper">
<resultMap id="UserMap" type="com.zzw.mybatis.entity.User">
<id property="id" column="uid"/>
<result property="username" column="username"/>
<collection property="accounts" ofType="com.zzw.mybatis.entity.Account">
<id property="id" column="aid"/>
<result property="payName" column="payName"/>
<result property="bankNo" column="bankNo"/>
</collection>
</resultMap>
<select id="get" resultMap="UserMap">
SELECT u.id uid, u.username,a.id as aid,a.payName,a.bankNo FROM t_user u,t_account a where u.id=#{id} and u.acctid = a.id
</select>
</mapper>
跑跑试试看有没有问题
package com.zzw.mybatis;
import com.google.gson.Gson;
import com.zzw.mybatis.dao.UserMapper;
import com.zzw.mybatis.entity.User;
import com.zzw.mybatis.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
public class SqlSessionFactoryTest {
public static void main(String[] args) throws IOException {
SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSession();
//获取对应的mapper
UserMapper paymentMapper = sqlSession.getMapper(UserMapper.class);
User user = paymentMapper.get(1);
System.out.println(new Gson().toJson(user));
}
}
SqlSessionFactoryUtil
package com.zzw.mybatis.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory;
//静态代码块,保证线程安全
static {
String resource = "mybatis-config.xml";
try {
InputStream is = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
运行没有异常说明配置 OK!
其他说明
搭建这个环境的作用是为了在分析代码过程中进行 Debuger,有些时候源代码很难明白,Debuger 一下能知道代码的走向,有时源代码看明白了,Debuger 一下也能帮助验证自己的理解是否有错。Debuger 对分析源码非常有用。
使用 Maven 构建这个工程除了方便 jar 导入之后,还有一个用处就是在 eclipse 中查看源代码非常方便。在 eclipse 使用 maven 工程,eclipse 会自动下载并关联源代码。