MyBatis是一个流行的Java持久层框架,它封装了JDBC操作,使开发者可以通过XML或注解的方式映射SQL语句,并将POJO与数据库表之间进行映射。了解MyBatis的执行流程,可以帮助开发者更好地理解其内部工作机制,优化代码并解决可能出现的问题。
配置解析:
MyBatis启动时,首先加载mybatis-config.xml
配置文件,以及映射器(mapper)XML文件,解析配置信息并创建SqlSessionFactory
。
SqlSessionFactory创建:
通过解析后的配置信息,构建SqlSessionFactory
实例。它是创建SqlSession
的工厂。
SqlSession创建:
通过SqlSessionFactory
创建SqlSession
实例。SqlSession
是一个面向用户的接口,它封装了数据库操作的会话。
Mapper接口绑定:
MyBatis使用JDK动态代理或者CGLIB代理,为Mapper接口生成代理对象。当调用Mapper接口方法时,实际是调用代理对象的相应方法。
SQL执行:
代理对象将调用MappedStatement
,它包含了SQL语句、输入参数映射和输出结果映射信息,执行相应的SQL操作。
结果映射:
执行完SQL后,MyBatis将结果集映射成用户定义的POJO对象,然后返回。
SqlSession关闭:
操作完成后,需要关闭SqlSession
来释放资源。
接下来我们将结合MyBatis的源码来详细分析其执行流程。
1. 配置解析(XMLConfigBuilder):
当我们启动MyBatis时,首先是通过XMLConfigBuilder解析配置文件。
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
在这个过程中,MyBatis解析mybatis-config.xml
文件,并初始化配置信息到Configuration
对象中。
2. SqlSessionFactory创建(SqlSessionFactoryBuilder):
一旦Configuration
对象被创建和配置,SqlSessionFactoryBuilder
会使用这个对象来创建SqlSessionFactory
。
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
3. SqlSession创建(DefaultSqlSessionFactory):
数据库操作是通过SqlSession
进行的,它是通过SqlSessionFactory
创建的。
public SqlSession openSession() {
return new DefaultSqlSession(configuration, executor);
}
4. Mapper接口绑定(SqlSessionManager):
Mapper接口没有实现类,当我们使用它们的时候,MyBatis会动态生成一个代理对象。
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
5. SQL执行(MapperProxy):
调用Mapper接口中的方法实际上是调用MapperProxy中的invoke方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return sqlSession.selectOne(mapperMethod.getCommandName(), args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
这个方法会找到对应的MappedStatement
对象,并执行对应的SQL语句。
6. 结果映射(DefaultResultSetHandler):
执行SQL后,需要处理结果集,这是通过DefaultResultSetHandler
来完成的。
public <E> List<E> handleResultSets(Statement stmt) throws SQLException {
...
final List<E> resultList = new ArrayList<E>();
while (resultSet.next()) {
E rowValue = getRowValue(rsWrapper, resultMap);
resultList.add(rowValue);
}
...
}
上面的getRowValue
方法将会根据配置,将结果集映射成相应的POJO对象。
7. SqlSession关闭:
操作完成后,需要关闭SqlSession
。
sqlSession.close();
关闭操作会释放数据库连接等资源。
通过以上步骤和源码分析,我们可以看到MyBatis内部是如何工作的。理解这一流程对于排查问题和优化性能都是非常有帮助的。在实际的项目开发中,对这一流程的深入了解将使开发者能够更加精细地控制数据库操作和事务管理。