IT评测·应用市场-qidao123.com技术社区
标题:
Mybatis源码分析
[打印本页]
作者:
河曲智叟
时间:
2025-4-1 21:30
标题:
Mybatis源码分析
Mybatis解析
0.引入
Mybatis源码也是对Jbdc的再一次封装,不管怎么进行包装,还是会有获取链接、preparedStatement、封装参数、执行这些步调的。本文来探索一下其运行原理。下面从最简单的mybatis利用案例,来看看mybatis的步调。
public class Test01 {
// 测试方法!============
public static void main(String[] args) {
String configFile = "mybatis-config.xml";
try (
// 1. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream(configFile)) {
// 2. 创建 SqlSessionFactory 对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 获取 SqlSession 对象
SqlSession sqlSession = sessionFactory.openSession();
// 获取mapper
InventoryMapper inventoryMapper = sqlSession.getMapper(InventoryMapper.class);
// 调用mapper的方法
List<Inventory> allInventory = inventoryMapper.getAllInventory();
for (Inventory inventory : allInventory) {
System.out.println(inventory);
}
// System.out.println(inventoryMapper.getInventoryById(1));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// 实体类对象
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Inventory implements Serializable {
private static final long serialVersionUID = 1L;
private Integer goodsId;
private String goodsName;
private Date createTime;
private Date modifyTime;
private Integer inventory;
}
复制代码
数据库配置文件
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/trans_inventory?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
db.username=root
db.password=123456
复制代码
配置文件如下:
<?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>
<properties resource="db.properties" />
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="jdbc" />
<dataSource type="pooled">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/InventoryMapper.xml" />
</mappers>
</configuration>
复制代码
mapper接口和xml文件
public interface InventoryMapper {
List<Inventory> getAllInventory();
Inventory getInventoryById(@Param("id") Integer id);
}
复制代码
<?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.feng.mapper.InventoryMapper">
<select id="getAllInventory" resultType="com.feng.entity.Inventory">
select *
from inventory
</select>
<select id="getInventoryById" resultType="com.feng.entity.Inventory">
select *
from inventory
where goods_id = #{id}
</select>
</mapper>
复制代码
1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream(configFile)
可以看到是这一行代码。其中Resources是Mybatis的工具类。从这个开始一层一层往下看
public class Resources {
// new 了一个ClassLoaderWrapper对象
private static final ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
public static InputStream getResourceAsStream(String resource) throws IOException {
return getResourceAsStream(null, resource);
}
// loader = null, resource = "xxxx.xml"
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
// ====================== 这一行
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
}
public class ClassLoaderWrapper {
ClassLoader defaultClassLoader;
ClassLoader systemClassLoader;
// --------- 构造函数
ClassLoaderWrapper() {
try {
// jdk的方法,得到系统类加载器
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
// getResourceAsStream()方法里面用到了 getClassLoaders(null)
return getResourceAsStream(resource, getClassLoaders(classLoader));
}
// 得到所有的类加载器:::classLoader = null
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(), systemClassLoader };
}
// 遍历所有的类加载器,谁加载到了就返回谁的inputStream
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);
// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
}
复制代码
主要是通过ClassLoader.getResourceAsStream()方法
获取指定的classpath路径下的Resource
2.创建SqlSessionFactory
// 2. 创建 SqlSessionFactory 对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
复制代码
第一步,无参构造函数创建了一个SqlSessionFactoryBuilder对象,然后调用其build方法。这很明显是“建造者设计模式”。
主要来看后面的build(inputStream)方法
[code]public class SqlSessionFactoryBuilder { public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //1.创建一个xml解析的builder,是建造者模式 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 2.上面创建的parser.parse()【可以理解为创建Configuration对象,并设置其属性】 return build(parser.parse()); // 3.build出SqlSessionFactory } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } // 3.我们发现SqlSessionFactory默认是DefaultSqlSessionFactory类型的 public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }}// XMLConfigBuilder.java内里public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) { this(Configuration.class, inputStream, environment, props); }public XMLConfigBuilder(Class
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4