Mybatis
从BindingTest开始debug,,,
配置初始化
@BeforeClass
public static void setup() throws Exception {
DataSource dataSource = BaseDataTest.createBlogDataSource();
BaseDataTest.runScript(dataSource, BaseDataTest.BLOG_DDL);
BaseDataTest.runScript(dataSource, BaseDataTest.BLOG_DATA);
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("Production", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setUseActualParamName(false); // to test legacy style reference (#{0} #{1})
//1、注册别名
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.getTypeAliasRegistry().registerAlias(Post.class);
configuration.getTypeAliasRegistry().registerAlias(Author.class);
// 2、Mapper接口注册
configuration.addMapper(BoundBlogMapper.class);
configuration.addMapper(BoundAuthorMapper.class);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
}
1、注册别名
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
TYPE_ALIASES.put(key, value);
}
2、在MapperRegistry中进行Mapper接口注册
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 解析mapper接口对应的Mapper.xml
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
knownMappers 在这个Map中存储了Mapper接口与其mapperProxyFactory的映射关系。将来MapperProxy-->invoke 中mapperMethod.execute(sqlSession, args) 是执行sql的关键。
继续Test测试类
@Test
public void shouldSelectBlogWithPostsUsingSubSelect() throws Exception {
// 获取sqlsession对象 可以commit rollback close(close conn归还给线程池)
SqlSession session = sqlSessionFactory.openSession();
try {
// 1、获取Mapper接口的代理类
BoundBlogMapper mapper = session.getMapper(BoundBlogMapper.class);
//2、通过代理Mapper执行sql
Blog b = mapper.selectBlogWithPostsUsingSubSelect(1);
assertEquals(1, b.getId());
session.close();
assertNotNull(b.getAuthor());
assertEquals(101, b.getAuthor().getId());
assertEquals("jim", b.getAuthor().getUsername());
assertEquals("********", b.getAuthor().getPassword());
assertEquals(2, b.getPosts().size());
} finally {
session.close();
}
}
1、获取Mapper接口的代理类,经过DefaultSqlSession--->getMapper(Class<T> type)与Configuration--->getMapper(Class<T> type, SqlSession sqlSession),最终调用mapperRegistry.getMapper(type, sqlSession)获取mapper代理。
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
2、通过代理Mapper执行sql
@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);
// 执行mapperMethod.execute方法
return mapperMethod.execute(sqlSession, args);
}
// mapperMethod.execute 部分代码
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
// Sqlsession 中执行insert 方法
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;
}
........
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// executor.update
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
3、Executor对象(以后对Executor进行分析)
Executor.png
BaseExecutor 执行update
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
// doUpdate 交给具体的子类执行 BaseExecutor 里边是个抽象方法
return doUpdate(ms, parameter);
}
//抽象方法 doUpdate 交给具体的子类执行
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
在SimpleExecutor中执行
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 获取 StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 获取Statement 对象
stmt = prepareStatement(handler, ms.getStatementLog());
// Statement处理器
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
// 获取Statement 对象
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
StatementHandler(简单语句处理器)进行处理 (以后对StatementHandler 进行分析)
StatementHandler.png
@Override
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
// 键值生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
// 键值生成器的类型
if (keyGenerator instanceof Jdbc3KeyGenerator) {
// 执行sql语句
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
// 如果不使用键值生成器 直接执行sql
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}
mybatis.png
网友评论