- mybatis的核心模块
- 注解注入方式(入口)这里用的是Hikari连接,其它连接方式道理一样
@Bean(name = "dataSource")
public DataSource dataSource() {
System.out.println("============== url " + url );
if (maxpoolsize < 10) {
maxpoolsize = 10;
}
if (maxpoolsize > 100) {
maxpoolsize = 100;
}
final HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(maxpoolsize);
ds.setDriverClassName(driverClassName);
ds.setJdbcUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
org.apache.ibatis.logging.LogFactory.useStdOutLogging();
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
关键在于:
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
sessionFactory.setDataSource(dataSource);
是在进行数据库配置项初始化。
sessionFactory.getObject();
在mybatis-spring.jar中存在SqlSessionFactoryBean。
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
this.sqlSessionFactory = buildSqlSessionFactory();
}
getObject()中的afterPropertiesSet方法调用buildSqlSessionFactory()才是进行mybatis的初始化。
mybatis的真正的入口
sqlSessionFactoryBuilder.build(configuration);
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
加载config配置文件:这里给注入到DefaultSqlSessionFactory的config, openSession的时候config才会有值。openSessionFromDataSource()方法加载对应的exector,获取对应的sqlSession。
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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();
}
}
拿到DefaultSqlSession 对象后采用反射的方式 mapperProxyFactory.newInstance(sqlSession) 获取mapper对象,mapperRegistry中存在 Map<Class>, MapperProxyFactory>> knownMappers = new HashMap<>(),存放相应的代理工厂类,可以获取到相应的代理对象
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
MapperProxy是代理类,invoke方法执行相应的sql,MapperMethod.execute(sqlSession, args);执行相应的方法
/**
* 反射入口
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
mapperMethod.execute(sqlSession, args):是相应的插入,更新,删除,查询方法。
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
以select查询为例,真正执行sql的是sqlSession.selectList方法
@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();
}
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
真正核心的是doQuery方法,其实也是对于jdbc的连接做了一次二次封装。
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
//获取Statementhandle对象--->对jdbc的statement的封装
Connection connection = getConnection(ms.getStatementLog());
//获取连接
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
//执行 statement.executeQuery(sql);,resultHandler 是对结果集的封装,这倆步都在handler.query()里进行处理。
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
//执行 statement.executeQuery(sql);
statement.execute(sql);
//这里是在处理结果集,对结果集的封装
return resultSetHandler.handleResultSets(statement);
}
总结:
mybatis的实际操作过程就是jdbc的连接过程,只不过中间用到了代理模式,对mybatis的接口文件进行一个代理,解析sql语句,执行响应的jdbc流程,中间对statement,resultSet等进行了封装。