成都java开发培训
达内成都高升桥中心

18011516507

热门课程

成都学JAVA哪家好?mybatis-执行getById

  • 时间:2020-03-04 15:31
  • 发布:成都达内
  • 来源:成都达内

1. getById 的执行

前面一篇 提到过, Mapper.java 创建的时候, 会通过jdk代理的方式来创建, 且代理处理类为: MapperProxy .

所以当执行 UserMapper 的 getById 方法的时候, 就会去 MapperProxy 中执行 invoke 方法.

//MapperProxy.java

@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);

}

cachedMapperMethod 方法是做了一层缓存处理. 先从缓存中获取, 如果获取不到, 再创建 MapperMethod 对象.

private MapperMethod cachedMapperMethod(Method method) {

MapperMethod mapperMethod = methodCache.get(method);

if (mapperMethod == null) {

mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());

methodCache.put(method, mapperMethod);

}

return mapperMethod;

}

接下来看一下 MapperMethod.execute() 方法. 这个方法中, 会看到我们期待的东西.

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);

}

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;

}

getById 在这里会调用 SqlSessionTemplate 的 selectOne 方法.

//SqlSessionTemplate.java

@Override

public T selectOne(String statement, Object parameter) {

return this.sqlSessionProxy. selectOne(statement, parameter);

}

前面解析过, sqlSessionProxy.selectOne 的时候, 会去 SqlSessionInterceptor 中执行 invoke() 方法.

private class SqlSessionInterceptor implements InvocationHandler {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

SqlSession sqlSession = getSqlSession(

SqlSessionTemplate.this.sqlSessionFactory,

SqlSessionTemplate.this.executorType,

SqlSessionTemplate.this.exceptionTranslator);

try {

Object result = method.invoke(sqlSession, args);

if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {

// force commit even on non-dirty sessions because some databases require

// a commit/rollback before calling close()

sqlSession.commit(true);

}

return result;

} catch (Throwable t) {

Throwable unwrapped = unwrapThrowable(t);

if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {

// release the connection to avoid a deadlock if the translator is no loaded. See issue #22

closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

sqlSession = null;

Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);

if (translated != null) {

unwrapped = translated;

}

}

throw unwrapped;

} finally {

if (sqlSession != null) {

closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

}

}

}

}

这里有两个方法需要重点关注, 一个是 getSqlSession() , 另一个是 invoke() 方法.

1.1 getSqlSession()

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);

notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

SqlSession session = sessionHolder(executorType, holder);

if (session != null) {

return session;

}

if (LOGGER.isDebugEnabled()) {

LOGGER.debug("Creating a new SqlSession");

}

session = sessionFactory.openSession(executorType);

registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

return session;

}

这里的 SqlSessionFactory 就是配置类中创建的 默认的实现类: DefaultSqlSessionFactory

//DefaultSqlSessionFactory.java

@Override

public SqlSession openSession(ExecutorType execType) {

return openSessionFromDataSource(execType, 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 的实例返回.

1.2 method.invoke()

回到 SqlSessionInterceptor 中来, 继续看下面的执行代码:

Object result = method.invoke(sqlSession, args);

sqlSession 就是上面创建的 DefaultSqlSesion 实例. 我们知道 Method.invoke(obj, args) 是反射调用方法的一种方式.

此处的Method是 getById 的方法反射类型. 所以, 会调用 obj 的 getById() 方法, 即 DefaultSqlSession 的 getById() 方法.

@Override

public T selectOne(String statement, Object parameter) {

// Popular vote was to return null on 0 results and throw exception on too many.

List list = this.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;

}

}

@Override

public List selectList(String statement, Object parameter) {

return this.selectList(statement, parameter, RowBounds.DEFAULT);

}

@Override

public List 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();

}

}

此例中, statement = "com.study.demo.mybatis.mapper.UserMapper.getById"

这里是通过statement 拿 MappedStatement, 而 MappedStatement 中, 就有 mapper.xml 中对应的 sql 语句.

后续过程中, 就可以拿着 sql 去数据库执行了.

到这里, 主体流程其实已经走通了.

上一篇:成都Java开发工程师:什么是JWT令牌认证?
下一篇:mapper.java 的创建,培训java多少钱成都?

成都java培训怎么样?达内java培训班靠谱吗?

成都哪家java培训好?推荐达内Java软件开发培训学校

成都java培训学费-达内教育Java培训费用是多少钱?

成都数据分析师培训班:关于什么是大数据和数据分析?

选择城市和中心
江西省

贵州省

广西省

海南省