抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

MYBATIS执行流程

Mybatis的主要成员

Configuration

​ MyBatis所有的配置信息都保存在Configuration对象中,配置文件中的大部分配置都会 存储到该类中

SqlSession

​ 作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能

​ 根据statement id,在mybatis配置对象configuration中获取到对应的mappedstatement对象,然后调用执行器来执行具体操作

Executor

​ MyBatis执行器,是MyBatis调度的核心,负责sql语句的生成和查询缓存的维护

  1. 根据传递的参数,完成sql语句的动态解析,生成BoundSql对象,供StatementHandler使用
  2. 为查询创建缓存,以提高性能
  3. 创建JDBC的Statement链接对象,传递给StatementHandler对象,返回List查询结果

StatementHandler

​ 封装了JDBC Statement操作,负责对JDBC statement的操作,如设置参数等

1. 对于JDBC的preparedStatement类型的对象,创建过程中,sql语句字符串会包含若干个?占位符,然后再赋值。
 2. StatementHandler通过parameterize(statement)方法对statement进行设值
 StatementHandler通过List query(Statement statement,ResultHandler resultHandler)方法来完成执行Statement,和将Statement对象返回的resultSet封装成List

ParameterHandler

​ 负责对用户传递的参数转换成JDBC Statement所对应的数据类型,对statement对象的?占位符进行赋值

ResultSetHandler

​ 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合

TypeHandler

​ 负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换

MappedStatement

​ MappedStatement维护一条<select|update|delete|insert>节点的封装

SqlSource

​ 负责根据用户传递的parameterObject,动态的生成SQL语句,将信息封装到BoundSql对象中并返回

BoundSql

​ 表示动态生成的SQL语句以及相应的参数信息

源码解析

SqlSession类

SqlSession位于mybatis包的org.apache.ibatis.session目录下,字面意思就是sql的会话,用于程序和数据库直接的sql会话,程序执行一次数据库操作就需要创建一个sqlSession,操作结束即关闭sqlSession;

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
* SqlSession 接口
*
* @author Clinton Begin
*/
public interface SqlSession extends Closeable {

//根据Sql语句查询单条记录
<T> T selectOne(String statement);

//根据Sql语句和参数查询单条记录
<T> T selectOne(String statement, Object parameter);

//根据Sql语句查询多条记录
<E> List<E> selectList(String statement);

//根据Sql语句和参数查询多条记录
<E> List<E> selectList(String statement, Object parameter);

//根据Sql语句和参数以及分页参数查询多条记录
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

//selectMap和selectList原理一样,只是将结果集映射成Map对象返回
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

//返回游标对象
<T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter);
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);

//查询的结果对象由指定的ResultHandler处理
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

//执行insert语句
int insert(String statement);
int insert(String statement, Object parameter);

//执行update语句
int update(String statement);
int update(String statement, Object parameter);

//执行delete语句
int delete(String statement);
int delete(String statement, Object parameter);

//提交事务
void commit();
void commit(boolean force);

//事务回滚
void rollback();
void rollback(boolean force);

//将请求刷新到数据库
List<BatchResult> flushStatements();

//关闭sqlSession
@Override
void close();

//清除缓存
void clearCache();

//获取Configuration对象
Configuration getConfiguration();

//获取Type对象的Mapper对象
<T> T getMapper(Class<T> type);

//获取sqlSession对象的数据库连接
Connection getConnection();
}

SqlSession中的方法全是和数据库相关的增删改查以及事务的提交方法。

sqlSession有三个实现类,除了默认的DefaultSqlSession之外,还有SqlSessionManager和SqlSessionTemplate

DefaultSqlSession类

类结构
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
/**
* The default implementation for {@link SqlSession}.
* Note that this class is not Thread-Safe.
*
* 默认的SqlSeesion
*
* @author Clinton Begin
*/
public class DefaultSqlSession implements SqlSession {
/**
* 全局配置信息
*/
private final Configuration configuration;
/**
* 执行器
*/
private final Executor executor;
/**
* 是否自动提交
*/
private final boolean autoCommit;
private boolean dirty;
//游标列表
private List<Cursor<?>> cursorList;

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}

/**
* 构造方法
* @param configuration
* @param executor
*/
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
}
查询单条数据

很明显selectOne的方法最终都是调用了selectList方法,然后取唯一的一条数据返回。那在看看selectList相关的代码

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
/**
* 单条查询
* @param statement
* @param <T>
* @return
*/
@Override
public <T> T selectOne(String statement) {
return this.selectOne(statement, null);
}

/**
* 单条查询
* 很明显selectOne的方法最终都是调用了selectList方法,然后取唯一的一条数据返回。
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @param <T>
* @return
*/
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
查询列表数据

共有三个selectList方法,最终都是调用了最后一个selectList方法,这里有三个参数:statement是sql语句;parameter是传入的参数;RowBounds是和分页相关的参数

最终调用的是executor.query的方法

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
 /**
* 查询列表数据
* @param statement Unique identifier matching the statement to use.
* @param <E>
* @return
*/
@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}

/**
* 查询列表数据
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @param <E>
* @return
*/
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

/**
* 查询列表数据
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @param rowBounds Bounds to limit object retrieval
* @param <E>
* @return
*/
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//获取MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
//通过executor执行器执行sql
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
//错误上下文实例重置
ErrorContext.instance().reset();
}
}

RowBounds类

该类不推荐使用,因为RowBounds类是内存分页推荐使用物理分页

RowBounds的两个属性:offSet是指查询数据时从多少位置开始查询,limit是指返回数据的条数,默认是从0位置开始查询到Integer的最大值,相关于默认是不做分页处理;

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
/**
* 内存分页对象
* @author Clinton Begin
*/
public class RowBounds {

public static final int NO_ROW_OFFSET = 0;
public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
public static final RowBounds DEFAULT = new RowBounds();
//指查询数据时从多少位置开始查询
private final int offset;
//返回数据的条数
private final int limit;

public RowBounds() {
this.offset = NO_ROW_OFFSET;
this.limit = NO_ROW_LIMIT;
}

public RowBounds(int offset, int limit) {
this.offset = offset;
this.limit = limit;
}

public int getOffset() {
return offset;
}

public int getLimit() {
return limit;
}

}
insert、update、delete方法

SqlSession的insert和delete的方法最终都是调用了update方法,而update方法最终也是调用了Executor的update

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
63
64
65
66
67
68
69
70
71
72
/**
* 插入
* @param statement Unique identifier matching the statement to execute.
* @return
*/
@Override
public int insert(String statement) {
return insert(statement, null);
}

/**
* 插入
* @param statement Unique identifier matching the statement to execute.
* @param parameter A parameter object to pass to the statement.
* @return
*/
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}

/**
* 更新
* @param statement Unique identifier matching the statement to execute.
* @return
*/
@Override
public int update(String statement) {
return update(statement, null);
}

/**
* 更新
* @param statement Unique identifier matching the statement to execute.
* @param parameter A parameter object to pass to the statement.
* @return
*/
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
//获取MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
//通过executor执行器执行sql
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

/**
* 删除
* @param statement Unique identifier matching the statement to execute.
* @return
*/
@Override
public int delete(String statement) {
return update(statement, null);
}

/**
* 删除
* @param statement Unique identifier matching the statement to execute.
* @param parameter A parameter object to pass to the statement.
* @return
*/
@Override
public int delete(String statement, Object parameter) {
return update(statement, parameter);
}
核心代码

sqlSession虽然叫程序和数据库之间的SQL会话,但是它并没有具体去执行sql语句,最终的sql语句的执行是由执行器Executor执行的,而SqlSession的作用只是创建了MappedStatement对象以及调用执行器去执行SQL,他的commit、rollback方法同样最终都是调用的执行器Executor的对应的方法

1
2
3
4
//获取MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
//通过executor执行器执行sql
return executor.update(ms, wrapCollection(parameter));

评论