MyBatis 所有的 CURD 操作都是在一个会话中完成的,本文简单介绍一下 MyBatis 会话相关的知识。
如何创建一个会话
在不与 Spring 结合的情况下,我们需要自己手动创建会话,看示例:
public static void main(String[] args) {
String resourceLocation = "config/mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resourceLocation);
//①解析 xml 配置文件,创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//②从工厂中获取会话实例
SqlSession sqlSession = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
创建会话工厂
首先通过 SqlSessionFactoryBuilder#build
方法解析配置文件获取会话工厂实例,正常情况下这个步骤只会在服务启动时执行一次。具体构造逻辑:
// org.apache.ibatis.session.SqlSessionFactoryBuilder
//重载方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//①构建一个XML配置类解析器
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//②首先解析 XML 配置文件中各节点信息,创建一个全局唯一的 Configuration 实例
//然后调用重载方法创建一个 DefaultSqlSessionFactory
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.
}
}
}
其实这一步最关键的地方就是执行 XMLConfigBuilder#parse
方法解析配置文件各个节点信息,创建一个全局唯一的 Configuration
实例,具体逻辑就不贴了,有点复杂,反正就是把 xml 文件中配置的信息转换为 Java 对象存在 Configuration
实例中。
创建会话实例
获得会话工厂后我们就能很轻松的创建一个会话实例了,调用SqlSessionFactory#openSession
方法即可。常用的 SqlSessionFactory
实现是 DefaultSqlSessionFactory
,先贴一下它创建会话的逻辑。
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//环境信息
final Environment environment = configuration.getEnvironment();
//事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//事务
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();
}
}
逻辑很清晰,首先从配置类中获取当前环境信息,然后从环境信息中获取事务工厂,再数据源、事务隔离级别、是否自动提交等参数创建当前事务实例。有了事务实例,再结合执行器类型创建一个执行器实例(执行器作为核心组件之一,后面单独介绍)。最后一步创建会话实例,其持有全局唯一的配置对象和执行器实例,用于后续的 CURD 操作。
有了会话能干什么
SqlSession
提供了 select
insert
update
delete
等操作方法,具备 CURD 的能力。不过这些都是需要指定 statemet
才能运行,不太方便,它还额外提供了 getMapper
方法获取 Mapper
接口的代理对象,这样就能直接调用对应的方法完成操作了。并且它还提供了 commit
rollback
方法用来支持事务操作。
public static void main(String[] args) {
String resourceLocation = "config/mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resourceLocation);
//解析 xml 配置文件,创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//从工厂中获取会话实例
SqlSession sqlSession = sqlSessionFactory.openSession();
//1. 指定 statement 查询
Object result = sqlSession.selectOne("club.wyc1856.mybatisspringboot.mapper.wyc1856.UserMapper.findById", 1);
System.out.println(result);
//2.通过 Mapper 接口代理类查询
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.findById(1);
System.out.println(user);
} catch (IOException e) {
e.printStackTrace();
}
}
注意
Sqlsession
不是线程安全的,不能作为类的静态变量或者实例变量,最好每次用的时候在方法中调用 Sqlsessionfactory#opensession
获取会话实例,用完关闭。