代码片段
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--定义数据库信息, 默认使用development数据库构建环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--配置数据库连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!--定义映射器-->
<mappers>
<mapper resource="mapper/UserMapping.xml"/>
</mappers>
</configuration>
User
package com.lalala.lightning.model;
import lombok.Data;
import javax.annotation.sql.DataSourceDefinition;
@Data
public class User {
private String name;
private Integer age;
}
UserDao
package com.lalala.lightning.dao;
import com.lalala.lightning.model.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserDao {
List<User> selectByName(String name);
}
UserMapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lalala.lightning.dao.UserDao">
<resultMap id="BaseResultMap" type="com.lalala.lightning.model.User">
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="age" jdbcType="VARCHAR" property="age"/>
</resultMap>
<select id="selectByName" resultType="com.lalala.lightning.model.User">
select * from user where name = #{name}
</select>
</mapper>
主方法
//定义SqlSessionFactory
SqlSessionFactory sqlSessionFactory = null;
//定义SqlSession
SqlSession sqlSession = null;
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//打开session会话
sqlSession = sqlSessionFactory.openSession();
//获取映射器mapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> users = userDao.selectByName("小黑");
System.out.println(users);
//事务提交
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
//事务回滚
assert sqlSession != null;
sqlSession.rollback();
} finally {
//关闭sqlSession,将连接归还给数据库,防止资源耗尽
if (sqlSession != null) {
sqlSession.close();
}
}
源码解读
读取配置文件
第一步通过方法获取文件流,为后续读取配置做准备
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder
[图片上传失败...(image-f9c187-1566646246760)]
SqlSessionFactoryBuilder是用来创建SqlSessionFactory,通过上图可以看出SqlSessionFactoryBuilder通过build方法传入配置信息可以创建SqlSessionFactory。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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.
}
}
}
在SqlSessionFactoryBuilder中所有的build方法最终都会调用这个方法去构建SqlSessionFactory。
SqlSessionFactoryBuilder在build方法中传入配置信息创建一个XMLConfigBuilder对象。接下来 我们看下XMLConfigBuilder的体系结构。
BaseBuilder.png不同的Builder类用来解析不同的XMl文件或者针对XMl中的特定信息进行解析。
- XMLConfigBuilder:解析mybatis-config.xml文件。
- XMLMapperBuilder:解析Mapping.xml文件。
- XMLStatementBuilder:解析文件中的SQL语句。
- SqlSourceBuilder:替换SQL语句中的占位符。
- MapperBuilderAssistant:用于缓存、sql参数、查询返回的结果集处理。
- XMLScriptBuilder:真正负责在背后解析mapper文件中的每个节点。
接下来我们从XMLConfigBuilder的构造方法开始分析,从这里开始读取配置信息。
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
首先创建一个Configuration在对象,在Configuration的构造方法中注册一些Class对象。
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
在创建好XMLConfigBuilder对象之后,调用了parse方法。
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
在parseConfiguration方法中,开始解析xml中节点的信息。最终这些配置信息都会存储在Configuration对象中维护。通过读取配置,XMLConfigBuilder的parse方法会返回一个携带配置的Configuration。
到此为止整个mybatis-config.xml配置信息都已经全部获取到了。
接下来开始创建SqlSessionFactory。
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
在DefaultSqlSessionFactory方法中比较简单,只是把具体配置信息的Configuration对象赋予DefaultSqlSessionFactory中。
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
整个Mybatis的初始化过程到这里就全部结束了。
网友评论