//mybatis配置文件
String resource = "conf.xml"; InputStream is = TestMybatis.class.getClassLoader().getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try {
//environment表示要使用哪个db,properties 表示资源信息 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. } } }
//将xml中的所有节点都解析成对象信息
private void parseConfiguration(XNode root) { try { propertiesElement(root.evalNode("properties")); //issue #117 read properties first typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 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); } }
private void propertiesElement(XNode context) throws Exception { if (context != null) {
//获取xml里面设置的 Properties defaults = context.getChildrenAsProperties();
//获取指定的资源文件里的 String resource = context.getStringAttribute("resource"); String url = context.getStringAttribute("url"); if (resource != null && url != null) { throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other."); }
//覆盖掉了xml里配置的 if (resource != null) { defaults.putAll(Resources.getResourceAsProperties(resource)); } else if (url != null) { defaults.putAll(Resources.getUrlAsProperties(url)); } Properties vars = configuration.getVariables();
//覆盖掉了上面的 if (vars != null) { defaults.putAll(vars); } parser.setVariables(defaults); configuration.setVariables(defaults); } }
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)) {
//获取事物factory TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//获取datasourcefactory 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()); } } } }
private TransactionFactory transactionManagerElement(XNode context) throws Exception { if (context != null) {
//根据type来决定要实例化哪个factory出来 String type = context.getStringAttribute("type"); Properties props = context.getChildrenAsProperties(); TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance(); factory.setProperties(props); return factory; } throw new BuilderException("Environment declaration requires a TransactionFactory."); }
private DataSourceFactory dataSourceElement(XNode context) throws Exception { if (context != null) {
//根据type来决定实例化哪个factory String type = context.getStringAttribute("type"); Properties props = context.getChildrenAsProperties(); DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance(); factory.setProperties(props); return factory; } throw new BuilderException("Environment declaration requires a DataSourceFactory."); }
最重要的是mappers的转换,这里的方法就把所有的sql语句就转换过来了,将来要找的话,也是这里的源泉。
//返回sessionfactory public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
public void commit() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Committing JDBC Connection [" + connection + "]"); }
//这里就是直接使用的jdbc的提交 connection.commit(); } } public void rollback() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Rolling back JDBC Connection [" + connection + "]"); }
//这里就是直接使用的jdbc的回滚
connection.rollback(); } }
//提交和回滚什么都不做,让别人来管理
public void commit() throws SQLException { // Does nothing } public void rollback() throws SQLException { // Does nothing }
private Connection doGetConnection(Properties properties) throws SQLException {
//初始化驱动 initializeDriver();
//jdbc直接获取一个连接 Connection connection = DriverManager.getConnection(url, properties); configureConnection(connection); return connection; }
//方法内容过多,可以自己去看 这里是从一个集合中pop出来一个连接直接使用。
private PooledConnection popConnection(String username, String password) throws SQLException {
//从jndi上下文中直接获取数据源并返回
if (properties.containsKey(INITIAL_CONTEXT) && properties.containsKey(DATA_SOURCE)) { Context ctx = (Context) initCtx.lookup(properties.getProperty(INITIAL_CONTEXT)); dataSource = (DataSource) ctx.lookup(properties.getProperty(DATA_SOURCE)); } else if (properties.containsKey(DATA_SOURCE)) { dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE)); }
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); }
//这里查看是否二级缓存开启了,如果开启了,那么返回的是一个被装饰了的执行器 用来使用缓存 if (cacheEnabled) { executor = new CachingExecutor(executor, autoCommit); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { //得到db信息
final Environment environment = configuration.getEnvironment();
//得到事物factory final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//根据数据源得到事物 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//得到执行器 final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
//执行器和配置信息对象一起组装了session返回。 return new DefaultSqlSession(configuration, executor); } 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(); } }
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try {
//根据id找到对应的sql的封装对象 statement MappedStatement ms = configuration.getMappedStatement(statement);
//这里的执行器有可能是缓存执行器也可能是默认执行器 List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); return result; } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, parameterObject, boundSql); if (!dirty) { cache.getReadWriteLock().readLock().lock(); try {
//这里从二级缓存中找一下 @SuppressWarnings("unchecked") List<E> cachedList = (List<E>) cache.getObject(key); if (cachedList != null) return cachedList; } finally { cache.getReadWriteLock().readLock().unlock(); } }
//执行sql查询 List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks return list; } } return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
//一级缓存查找
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else {
//sqldb查找 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); }
mybatis 学习四 源码分析 mybatis如何执行的一条sql
原文:http://www.cnblogs.com/liouwei4083/p/6024038.html