从HelloWorld来分析Mybatis配置文件的加载过程
包含了所有代码和配置文件以及DB.sql
Mybatis的启动流程大概分为几部分
1.通过Resources处理得到一个字节流或者字符流的处理类
2.通过SqlSessionFactoryBuilder构建一个SqlSessionFactory
3.通过SqlSessionFactory得到SqlSession
4.通过SqlSession执行相关Mapper文件的sql语句
这篇文章主要分析第2个步骤中的SqlSessionFactoryBuilder,SqlSessionFactory的一些源码
通过SqlSessionFactoryBuilder构建一个SqlSessionFactory
首先看下SqlSessionFactoryBuilder的源码
/**
* Builds {@link SqlSession} instances.
*
* @author Clinton Begin
*/
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
里面为我们提供了9个方法
前面8个方法在最后都会生成一个Configuration然后去调用第九个方法。
生成一个SqlSessionFactory对象
| 方法名 | 参数 |
|---|---|
| build(Reader reader) | reader:字符流处理类 |
| build(Reader reader, String environment) | environment:数据源ID |
| build(Reader reader, Properties properties) | properties:配置文件,一般是数据库配置文件 |
| build(Reader reader, String environment, Properties properties) | |
| build(InputStream inputStream) | inputStream:字节流处理类 |
| build(InputStream inputStream, String environment) | |
| build(InputStream inputStream, Properties properties) | |
| build(InputStream inputStream, String environment, Properties properties) | |
| build(Configuration config) | config:mybatis核心配置 |
下面对这些方法进行一个简单的实验
CreateDB.sql
--
-- Copyright 2009-2018 the original author or authors.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
create database mybatis;
use mybatis;
drop table if exists student;
CREATE TABLE student (
id INT primary key ,
name VARCHAR(255),
age INT
);
INSERT INTO student VALUES
(1, 'mybatis', 10);
CreateDB2.sql
--
-- Copyright 2009-2018 the original author or authors.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
create database mybatis2;
use mybatis2;
drop table if exists student;
CREATE TABLE student
(
id INT primary key,
name VARCHAR(255),
age INT
);
INSERT INTO student
VALUES (1, 'mybatis2', 10);
db.properties
db.username=root
db.password=root
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false
db.url2=jdbc:mysql://localhost:3306/mybatis2?useSSL=false
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"./mybatis-3-config.dtd">
<configuration>
<!--引入外部资源 -->
<!-- <properties resource="org/apache/ibatis/basebuilder/db.properties"/>-->
<!-- <properties>-->
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>-->
<!-- </properties>-->
<typeAliases>
<typeAlias alias="student" type="org.apache.ibatis.mytest.StudentDto"/>
</typeAliases>
<!--设置默认的环境为开发环境 -->
<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>
<environment id="development2">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url2}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <package name="com.zzz.mybatis.mapper"/> -->
<mapper resource="org/apache/ibatis/mytest/StudentMapper.xml"/>
</mappers>
</configuration>
StudentDto.java
package org.apache.ibatis.mytest;
import lombok.Data;
/**
* @author yangqiang
* @date 2021-07-20 23:06
*/
@Data
public class StudentDto {
private Integer id;
private String name;
private Integer age;
}
StudentMapper.java
package org.apache.ibatis.mytest;
import org.apache.ibatis.annotations.Mapper;
import java.util.*;
/**
* @author yangqiang
* @date 2021-07-20 23:08
*/
@Mapper
public interface StudentMapper {
public List<StudentDto> getStudentsByAlias();
}
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
<mapper namespace="org.apache.ibatis.mytest.StudentMapper">
<cache-ref namespace="org.apache.ibatis.mytest.StudentMapper"/>
<cache type="PERPETUAL" eviction="LRU" flushInterval="60000" readOnly="true" size="512" blocking="false">
<property name="name" value="zhangsan"/>
</cache>
<select id="getStudentsByAlias" resultType="student" useCache="false" >
select id,name,age from student
</select>
</mapper>
SqlSessionFactoryBuilderTest.java
package org.apache.ibatis.mytest;
import org.apache.ibatis.BaseDataTest;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
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 org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
import java.util.Properties;
/**
* @author yangqiang
* @date 2021-07-20 23:14
*/
public class SqlSessionFactoryBuilderTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeAll
static void setUp() throws Exception {
//准备工作 创建数据库和表插入一条数据
Properties properties = Resources.getResourceAsProperties("org/apache/ibatis/mytest/db.properties");
String driver = properties.getProperty("db.driver");
String url = properties.getProperty("db.url");
String url2 = properties.getProperty("db.url2");
String userName = properties.getProperty("db.username");
String password = properties.getProperty("db.password");
DataSource mybatisDS = new PooledDataSource(driver, url, userName, password);
DataSource mybatis2DS = new PooledDataSource(driver, url2, userName, password);
BaseDataTest.runScript(mybatisDS,"org/apache/ibatis/mytest/CreateDB.sql");
BaseDataTest.runScript(mybatis2DS,"org/apache/ibatis/mytest/CreateDB2.sql");
}
@Test
public void readerTest() throws IOException {
//得到一个Reader处理类(字符流)
try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/mytest/mybatis-config.xml")) {
// environment:数据源ID 在mybatis-config.xml <environments> 标签里面配置的 id 为development的数据源信息(非必传)
// properties :配置文件信息。一般是数据库配置信息。可以在这里进行配置 也可以在mybatis-config.xml 通过<properties> 标签进行引入properties配置文件
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,"development", Resources.getResourceAsProperties("org/apache/ibatis/mytest/db.properties"));
}
SqlSession sqlSession = sqlSessionFactory.openSession();
List<StudentDto> rs = sqlSession.selectList("org.apache.ibatis.mytest.StudentMapper.getStudentsByAlias", null);
System.out.println(rs.toString());
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
rs = mapper.getStudentsByAlias();
System.out.println(rs.toString());
}
@Test
public void streamTest() throws IOException {
//得到一个InputStream处理类(字节流)
try (InputStream inputStream = Resources.getResourceAsStream("org/apache/ibatis/mytest/mybatis-config.xml")) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "development2",Resources.getResourceAsProperties("org/apache/ibatis/mytest/db.properties"));
}
SqlSession sqlSession = sqlSessionFactory.openSession();
List<StudentDto> rs = sqlSession.selectList("org.apache.ibatis.mytest.StudentMapper.getStudentsByAlias", null);
System.out.println(rs.toString());
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
rs = mapper.getStudentsByAlias();
System.out.println(rs.toString());
}
}
结果1:
[StudentDto(id=1, name=mybatis, age=10)]
[StudentDto(id=1, name=mybatis, age=10)]
结果2
[StudentDto(id=1, name=mybatis2, age=10)]
[StudentDto(id=1, name=mybatis2, age=10)]
这样就完成了一个Mybatis整个启动流程以及调用。 下一篇将研究SqlSessionFactoryBuilder.builder中的parser.parse()方法