我们熟悉的Mapper是mybatis帮我们实例化的接口(通过反射),前提是我们只使用了mybatis而没有与spring集成。如果我们将mybatis与spring进行集成,那么代理权就会到spring手里,并由ioc容器进行纳管。
因此,先不去管mybatis与spring集成的逻辑,会对任何一方的理解都产生干扰。
mybatis原生的开发逻辑是怎样的呢?
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
// 假设你有一个UserMapper接口
public interface UserMapper {
User selectUserById(int id);
}
public class MybatisManualDemo {
public static void main(String[] args) throws Exception {
// 1. 加载mybatis配置文件
String resource = "com/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2. 创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) { // 手动创建SqlSession
// 3. 获取UserMapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
// 4. 调用方法执行查询
User user = userMapper.selectUserById(1);
// 5. 处理结果
System.out.println("Selected User: " + user.getName());
// 6. 提交事务(如果需要)
session.commit();
} catch (Exception e) {
// 如果出现异常,则回滚事务
session.rollback();
throw e;
}
}
}
在这个例子中,sqlSessionFactory.openSession() 是用来获取SqlSession实例的关键步骤,然后通过这个SqlSession实例来获取Mapper接口的代理对象,并执行数据库操作。在try-with-resources语句中,SqlSession会在finally块中自动关闭,确保资源正确释放。
我们目前只关注核心对象:SqlSession。这个类里面的方法你会看到功能比较清晰,就是我们熟悉的各种数据库操作。它的默认实现只有一个:DefaultSqlSession。其内部存在如下属性:
private final Executor executor;
DefaultSqlSession所有的实现逻辑都会交给Executor执行器实现。因此DefaultSqlSession只是一个门面,真正干活的是Executor。
Executor主要有三个实现类和一个抽象类:其中BaseExecutor是一个抽象类,为一个模板类,提供了一级缓存的实现(会话级缓存)的实现,如果缓存中找不到,则会进入从数据库查找的逻辑,即
org.apache.ibatis.executor.BaseExecutor#query ——>
org.apache.ibatis.executor.BaseExecutor#doQuery
doQuery方法在BaseExecutor中是一个抽象方法,交由Executor的三个实现类之一进行实现,分别是:
SimpleExecutor、ReuseExecutor和BatchExecutor。
重点关注:
- 一级缓存的key是由什么决定的,关注
BaseExecutor中的createCacheKey方法。该方法决定了哪些场景可以命中缓存 - 一级缓存什么时候会被清空,关注
BaseExecutor中的clearLocalCache方法什么时候被调用 - 关注
ReuseExecutor重用了什么。重用的其实是预编译的sql。 - 关注
BatchExecutor批量更新的时候有什么特点(待完善)
而在Spring整合MyBatis后,通常会通过自动注入的方式得到SqlSessionTemplate或Mapper接口的代理对象,从而无需手动创建和关闭SqlSession。