目录
概述
前置内容主要包含三个部分:第一部分是针对SpringBoot整合MyBatis中一些比较重要的类进行讲解;第二部分是对这些类之间的关系进行一个梳理;最后一部分则是使用JDBC原生方式去执行SQL的示例,回顾一下基础。
链接跳转
(一)MyBatis整合SpringBoot源码解析——整体大纲
(二)MyBatis整合SpringBoot源码解析——前置内容
(三)MyBatis整合SpringBoot源码解析——配置初始化
(四)MyBatis整合SpringBoot源码解析——SQL执行流程
内容
一、重要的类
1.SqlSessionFactoryBean
FactoryBean,根据application.yml或mybatis的xml文件中的配置生成SqlSessionFactory,主要代码如下:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
// FactoryBean实例化方法
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
// 创建逻辑 略
}
}
2.SqlSessionFactory
MyBatis会话工厂接口,默认的实现类为DefaultSqlSessionFactory,用于创建一个会话(SqlSession),主要代码如下:
public interface SqlSessionFactory {
SqlSession openSession();
// 省略其他重载方法
SqlSession openSession(...);
}
3.SqlSession
MyBatis会话接口,提供CRUD的方法入口,默认的实现类是DefaultSqlSession,但是与SpringBoot整合后,会由SqlSessionTemplate进行代理,最终的调用链为SqlSessionTemplate => DefaultSqlSession,接口的主要代码如下:
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
// 省略其余CRUD方法..
void commit();
void rollback();
Connection getConnection();
}
4.Executor
MyBatis执行器接口,SqlSession会把CRUD的动作委托给执行器,主要代码如下:
public interface Executor {
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
}
5.SqlSessionTemplate
会话接口SqlSession的实现类之一,承担了与Spring事务集成的职责。
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory;
// 此处的SqlSession实现为DefaultSqlSession
private final SqlSession sqlSessionProxy;
}
6.TransactionFactory
MyBatis事务工厂接口,用于开启事务,与Spring集成后,实现类为SpringManagedTransactionFactory,接口主要代码如下:
public interface TransactionFactory {
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
7.Transaction
MyBatis事务接口,用于执行提交、回滚动作,与Spring集成后,实现类为SpringManagedTransaction,接口主要代码如下:
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
}
8.MapperProxy
Mapper代理类
9.MapperMethod
表示Mapper接口中的定义的某个方法
10.MappedStatement
表示Mapper接口中的定义的某个方法映射的SQL语句
二、类的关系
上述列举的几个类都是SpringBoot整合MyBatis中源码中常见的类,从功能上划分的话大致可以分为两个部分,一是会话创建;二是语句执行。
1.会话创建
会话创建相关的几个类关系如下:DefaultSqlSessionFactory(SqlSessionFactory的实现类)是默认的会话工厂,创建出的是代理会话对象SqlSessionTemplate(SqlSession的实现类),其主要的职责是与Spring的事务集成,真正的SQL执行逻辑还是由(SqlSession的实现类)DefaultSqlSession去完成。而在DefaultSqlSession又继续委托给Executor执行。
2.语句执行
语句执行相关的几个类关系如下:例如现在有一个Mapper接口ExampleMapper代码如下
public interface ExampleMapper {
// 此处简略成注解形式,该SQL也可以写在xml文件中。
@Select("select * from example")
List<Example> selectAll();
}
根据这个ExampleMapper,MyBatis会生成一个代理对象MapperProxy,在这个对象中会记录方法的映射关系,也就是有一个MapperMethod对象映射"selectAll"方法,同时还会有一个MappedStatement对象,这个对象映射了"select * from example"这个语句。
三、JDBC API
在不使用MyBatis框架的情况下,执行数据库CRUD的代码如下。
public static void main(String[] args) {
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库的连接
Connection conn = DriverManager.getConnection(URL, NAME, PASSWORD);
// 开始一个事务
conn.setAutoCommit(false);
try {
//3.通过数据库的连接操作数据库
String sql = "SELECT id, name FROM example";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id") + "," + rs.getString("name"));
}
// 提交事务
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
// 如果有异常,则回滚事务
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
// 不论是否发生异常,都需要关闭连接
try {
if(conn != null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}