helloWorld示例源码分析
public class test {
@Test
public void testHelloWorld() throws IOException {
// 1.使用Mybatis的Resources类读取Mybatis全局配置文件
InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
// 2.使用InputStream创建sqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3.调用builder对象的build方法创建SqlSessionFactory对象
SqlSessionFactory build = builder.build(stream);
// 4.通过SqlSessionFactory对象开启一个从Java程序到数据库的会话
SqlSession sqlSession = build.openSession();
//5.在通过SqlSession对象找到Mapper配置文件中可以执行的sql语句
//两个参数,分别是statement、parameter
// statement参数格式:Mapper配置文件namespace属性.SQL标签的id属性
//parameter参数;给SQL语句传入的参数
Object one = sqlSession.selectOne("dao.ACicpTest1Dao.findOneById","978");
//6.直接打印查询结果
System.out.println(one);
//7.提交事务
sqlSession.commit();
//8.关闭sqlsession
sqlSession.close();
}
}
读取mybatis-config.xml文件源码分析
在builder.build(stream)处打一个断点。
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
下一处:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//parser :解析器的意思
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.
}
}
}
parser.parse()方法:
public Configuration parse() {
//已经被解析过parsed则为ture报异常,未被解析过为false,则往下进行
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//解析配置文件的节点configuration,正是mybatis-config.xml的根节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
parseConfiguration()方法:
//此时root内容就是mybatis-config.xml的全部文件内容,除了文件头
private void parseConfiguration(XNode root) {
try {
//接下来解析各个节点
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(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);
}
}
environmentsElement()方法
//此时对数据源节点信息进行解析
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
return build(parser.parse());中build方法
SqlSessionFactory 是一个接口,此处的只是将Configuration 传进去,赋值给final修饰的私有属性
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
工厂模式:configuration就是解析过后封装的对象
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
由此看出,解析的xml文件最终都转换为configuration对象
build.openSession();源码分析
configuration.getDefaultExecutorType() 获取默认执行器的类型,
第三个参数为:autoCommit设置为false。
@Override
public SqlSession openSession() {
//configuration.getDefaultExecutorType() 获取默认执行器的类型,
//第三个参数为:autoCommit设置为false。
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
下一步:
autoCommit设置为false、level为null
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();
}
}
重点看: tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
事务是如何创建的。
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
Object one = sqlSession.selectOne(“dao.ACicpTest1Dao.findOneById”,“978”);源码分析
可以看出selectOne也是调用selectList,进行list查找返回。如果查找结果大于1,就抛出异常。
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
selectList,调用的selectList方法,其中rowBounds传的默认值,最后还是要归结于configuration对象。
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
id为statement,就是配置的namepace.方法id,validateIncompleteStatements为上个方法传的true源码写死的。 就会进入buildAllStatements();
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);
}
buildAllStatements(),这里面各个都是空的,没做什么操作。
protected void buildAllStatements() {
if (!incompleteResultMaps.isEmpty()) {
synchronized (incompleteResultMaps) {
// This always throws a BuilderException.
incompleteResultMaps.iterator().next().resolve();
}
}
if (!incompleteCacheRefs.isEmpty()) {
synchronized (incompleteCacheRefs) {
// This always throws a BuilderException.
incompleteCacheRefs.iterator().next().resolveCacheRef();
}
}
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) {
// This always throws a BuilderException.
incompleteStatements.iterator().next().parseStatementNode();
}
}
if (!incompleteMethods.isEmpty()) {
synchronized (incompleteMethods) {
// This always throws a BuilderException.
incompleteMethods.iterator().next().resolve();
}
}
}
mappedStatements是个长度为2的Map。中存了两个值,一个key是mapper.xml文件中的id,一个key是namespace+id。但是这两个key指向的是同一个MappedStatement对象。在mappedStatement对象中的存在sqlSource属性。里边存的是对应sql语句。
意味着使用id,和namesapce+id都能够使用?
经过试验,依然能够输出想要的结果。
Object one = sqlSession.selectOne("findOneById","978");