0%

mybatis之SqlSession

SqlSession是mybatis的核心接口,SqlSessionFactory负责创建SqlSession对象,包含多个openSession()方法的重载。
在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
public interface SqlSession extends Closeable {
// 参数为sql语句,返回查询的结果对象
<T> T selectOne(String statement);
// 第二个参数为实参对象
<T> T selectOne(String statement, Object parameter);

<E> List<E> selectList(String statement);

<E> List<E> selectList(String statement, Object parameter);
// 第三个参数为查询结果集的范围
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

<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);

int insert(String statement);

int insert(String statement, Object parameter);

int update(String statement);

int update(String statement, Object parameter);

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();

// 关闭当前session
@Override
void close();

// 清空缓存
void clearCache();

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

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

// 获取该SqlSession对应的数据库连接
Connection getConnection();
}

MyBatis为SqlSession提供了默认实现,DefaultSqlSession类,

1
2
3
4
5
6
7
8
9
10
// Configuration配置对象
private final Configuration configuration;
// 底层依赖的Executor对象
private final Executor executor;
// 是否自动提交事务
private final boolean autoCommit;
// 当前缓存中是否存在脏数据
private boolean dirty;
// 防止用户忘记关闭已打开的游标,cursorList收集由该SqlSession对象生成的游标对象,在DefaultSqlSession.close()方法统一关闭
private List<Cursor<?>> cursorList;

所有的数据库相关操作全部封装到了Executor接口实现中,DefaultSqlSession类中查询方法的调用关系如下图

查询最终都是调用Executor.query(MappedStatement, Object, RowBounds, ResultHandler)方法实现数据库查询操作的 对返回对象进行调整 selectOne()方法从结果集中获取第一个元素返回 selectMap()方法将List集合转为Map集合返回 select()方法将结果对象集合交由用户指定的ResultHandler对象处理,且没有返回值 selectList()方法直接将集合返回

DefaultSqlSession中的insert()、update()、delete()方法最后通过调用DefaultSqlSession.update(String,Object)方法,然后调用Executor.update(MappedStatement, Object)方法完成数据库的修改操作。

DefaultSqlSessionFactory

DefaultSqlSessionFactory实现了SqlSessionFactory接口,提供了两种创建DefaultSqlSession的方式

方式一

通过数据源获取数据库连接,并创建Executor对象以及DefaultSqlSession对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ExecutorType是一个枚举
// SIMPLE, 为每个语句的执行创建一个新的预处理语句
// REUSE, 复用预处理语句
// BATCH 批量执行所有更新语句
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获取mybatis-config.xml的配置中的Environment对象
final Environment environment = configuration.getEnvironment();
// 获取TransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建Transaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
方式二

用户提供数据库连接,根据数据库连接创建Executor对象以及DefaultSqlSession对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

SqlSessionManager

SqlSessionManager同时实现了SqlSessionFactory和SqlSession接口,也提供了SqlSessionFactory创建SqlSession对象以及SqlSession操作数据库的功能。

1
2
3
4
5
private final SqlSessionFactory sqlSessionFactory;
// localSqlSession中记录的sqlSession对象的代理对象,SqlSessionManager初始化时会使用JDK动态代理的方式创建
private final SqlSession sqlSessionProxy;
// 记录当前一个与当前线程绑定的SqlSession对象
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal();

SqlSessionManager与DefaultSqlSessionFactory主要不同点是SqlSessionManager提供了两种模式:第一种模式和DefaultSqlSessionFactory的行为相同,同一个线程每次通过SqlSessionManager对象访问数据库时,都会创建新的DefaultSession对象完成数据库操作

第二种模式是SqlSessionManager通过localSqlSession这个ThreadLocal变量,记录当前线程绑定的SqlSession对象,供当前线程循环使用,从而避免在同一个线程多次创建SqlSession对象带来的性能损失.

1
2
3
4
5
// 通过构造函数可以看出,sqlSessionProxy是代理类,会执行SqlSessionManager.SqlSessionInterceptor中的方法
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionManager.SqlSessionInterceptor());
}
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
private class SqlSessionInterceptor implements InvocationHandler {
public SqlSessionInterceptor() {
// Prevent Synthetic Access
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
// 会使用第二种模式
if (sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {// 第一种模式
try (SqlSession autoSqlSession = openSession()) {
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
}
}

四大对象

sqlSession真正的执行时通过Executor、StatementHandler、ParameterHandler、ResultHandler来完成数据库操作和结果返回

  • Executor 执行器,通过执行器来调度StatementHandler、ParameterHandler和ResultHandler等来执行对应的sql
  • StatementHandler 使用数据库的Statement/PreparedStatement执行操作
  • ParameterHandler 用于sql对参数的处理
  • ResultSetHandler 进行最后结果集ResultSet的封装和返回的