DefaultSqlSessionFactory
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
/**
核心方法,DefaultSqlSessionFactory其他方法都是调用此方法
**/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置(从上面的配置可以看出)
final Environment environment = configuration.getEnvironment();
//通过环境配置获取事务工厂,如果没有配置默认是 new ManagedTransactionFactory();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//通过配置创建一个Executor,Executor是对jdbc中Statement的封装
final Executor executor = configuration.newExecutor(tx, execType);
//此处也是写死的,创建一个DefaultSqlSession对象
return new DefaultSqlSession(configuration, executor);
} catch (Exception e) {
//可能已经获取了一个连接,所以此处调用close事务
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return managedTransactionFactory;
}
return environment.getTransactionFactory();
}
DefaultSqlSession
非mapper接口方式
代码案例
@Test public void testFindUserMessageIdForSession(){ //mybatis的配置文件 String resource = "Configuration.xml"; //使用类加载器加载mybatis的配置文件(它也加载关联的映射文件) InputStream is = UserMessageTest.class.getClassLoader().getResourceAsStream(resource); //构建sqlSession的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) //Reader reader = Resources.getResourceAsReader(resource); //构建sqlSession的工厂 //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); //创建能执行映射文件中sql的sqlSession SqlSession session = sessionFactory.openSession(); /** * 映射sql的标识字符串, * me.gacl.mapping.userMapper是userMapper.xml文件中mapper标签的namespace属性的值, * getUser是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL */ String statement = "com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById";//映射sql的标识字符串 //执行查询返回一个唯一user对象的sql UserMessage user = session.selectOne(statement, 7777); System.out.println(user); }
分析session.selectOne
/*** selectOne调用的额是selectList **/ 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; } } public <E> List<E> selectList(String statement, Object parameter) { return this.<E>selectList(statement, parameter, RowBounds.DEFAULT); } public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { /**statement是com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById 在Configuration中通过id为com.jannal.mybatis.pojo.UserMessageMapper.findUserMessageById获取MappedStatement **/ MappedStatement ms = configuration.getMappedStatement(statement); //调用Executor接口的query执行 List<E> result = executor.<E>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(); } }
CachingExecutor
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, key, parameterObject, boundSql); cache.getReadWriteLock().readLock().lock(); try { @SuppressWarnings("unchecked") List<E> cachedList = dirty ? null : (List<E>) cache.getObject(key); if (cachedList != null) { return cachedList; } else { List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); return list; } } finally { cache.getReadWriteLock().readLock().unlock(); } } } //委托类是SimpleExecutor return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
/** SimpleExecutor中的<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); */ public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
mapper接口方式
案例代码
@Test public void testFindUserMessageIdForMapper(){ String resource = "Configuration.xml"; InputStream is = UserMessageTest.class.getClassLoader().getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession session = sessionFactory.openSession(); UserMessageMapper userMessageMapper = session.getMapper(UserMessageMapper.class); UserMessage userMessage = userMessageMapper.findUserMessageById(7777L); System.out.println(userMessage); }
源码分析
/**session.getMapper(UserMessageMapper.class);是调用DefaultSqlSession中的如下方法。 DefaultSqlSession从Configuration中获取mapper **/ public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); } /** 此方法是Configuration中个getMapper(),可以看出Configuration委托MapperRegistry **/ public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } /** 此方法是MapperRegistry下的getMapper()方法 ***/ public <T> T getMapper(Class<T> type, SqlSession sqlSession) { if (!knownMappers.contains(type)) throw new BindingException("Type " + type + " is not known to the MapperRegistry."); try { //MapperProxy动态代理Mapper接口(每个MapperProxy对应一个mapper接口) return MapperProxy.newMapperProxy(type, sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
MapperProxy
/** 1. UserMessageMapper userMessageMapper = session.getMapper(UserMessageMapper.class); UserMessage userMessage = userMessageMapper.findUserMessageById(7777L); userMessageMapper此时是MapperProxy。此时通过MapperProxy去调用findUserMessageById 2. **/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } //找到method对应的接口 final Class<?> declaringInterface = findDeclaringInterface(proxy, method); //委托给MapperMethod去处理sql的执行 final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession); final Object result = mapperMethod.execute(args); if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) { throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; } /** 以下是MapperMethod方法,可以看到MapperMethod采用命令模式 **/ public Object execute(Object[] args) { Object result = null; if (SqlCommandType.INSERT == type) { Object param = getParam(args); result = sqlSession.insert(commandName, param); } else if (SqlCommandType.UPDATE == type) { Object param = getParam(args); result = sqlSession.update(commandName, param); } else if (SqlCommandType.DELETE == type) { Object param = getParam(args); result = sqlSession.delete(commandName, param); } else if (SqlCommandType.SELECT == type) { if (returnsVoid && resultHandlerIndex != null) { executeWithResultHandler(args); } else if (returnsMany) { result = executeForMany(args); } else if (returnsMap) { result = executeForMap(args); } else { Object param = getParam(args); //可以看到调用的还是sqlSession.selectOne,即调用非Mapper接口处理的方式 result = sqlSession.selectOne(commandName, param); } } else { throw new BindingException("Unknown execution method for: " + commandName); } return result; }