MyBatis Principle Analysis 3 - Data Operation

foreword

In the previous article "MyBatis Principle Analysis - Basic Principles", the implementation principle of MyBatis is briefly analyzed. The database operation of MyBatis is performed through Executor. Executor is an interface with three implementation classes, namely SimpleExecutor, ReuseExecutor and BatchExecutor.

 

Process of querying data

Querying data is achieved through the method of SqlSession, which encapsulates the related operations of Executor. Taking select as an example, first obtain the MappedStatement object from the configuration according to the statement associated with the SQL statement, and then call the query method of the Executor to execute the query operation. The format of statement is namespace + ID, ID is the id attribute of select tag in XML. The MappedStatement object stores the SQL configuration in XML, such as ParameterMap, ResultMap, and so on.

 

@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}

 

 By default, the SimpleExecutor implementation of the Executor interface is used. SimpleExecutor inherits the abstract class BaseExecutor. BaseExecutor implements the methods of the Executor interface and implements the cache mechanism, which can directly return query results from the cache, but more specific database operations are handed over to the subclass SimpleExecutor for implementation. The doQuery method that executes the query in the SimpleExecutor class is shown below. First create an instance of the StatementHandler interface from Configuration, which is implemented by RoutingStatementHandler by default. Then get the database connection, initialize Statement, set parameters, etc. in the prepareStatement method. Then call the query method of StatementHandler, execute data query, and hand over the query result to resultHandler for processing. Finally close the Statement.

 

@Override
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(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
}

 

In RoutingStatementHandler, an implementation of StatementHandler will be selected for further data processing according to the configuration. The default is the PreparedStatementHandler class. In the query method of this class, the Statement data query request will be executed, and after the request is completed, the ResultSetHandler will be called to process and encapsulate the query result. The ResultSetHandler interface defines the method for processing the returned result set. The default implementation class is DefaultResultSetHandler, and the result set to Java Bean mapping is completed in the handleResultSets method.

 

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
}

 

 

Cache of query results

MyBatis supports caching of query results to reduce database operations and improve efficiency. By default, operations such as insert, update, and delete will clear the cache. Before executing the query operation, first create the CacheKey object, and update the CacheKey object according to the SQL statement, id, offset, limit and parameters. The CacheKey object will record these data and update the hashcode, checksum, count several integers, these data are used to determine the CacheKey object are equal.

 

public void update(Object object) {
    int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
    count++;
    checksum += baseHashCode;
    baseHashCode *= count;
    hashcode = multiplier * hashcode + baseHashCode;
    updateList.add(object);
}

  

The query result of the select statement is stored in the PerpetualCache class in the form of a Map. The key of the Map is the CacheKey object, and the value of the Map is the query result.

 

Process for updating data

The insert and delete operations of DefaultSqlSession are implemented by multiplexing the update operation. The operation process of update is similar to that of select, so I won't elaborate too much. The difference is that the cache needs to be cleaned up before the update operation is performed. After the update operation is completed, the number of affected rows and the self-increment of the KeyGenerator configuration need to be returned.

 

Transaction commit and rollback

The commit and rollback operations of DefaultSqlSession are implemented in BaseExecutor, first clear the cache, then clear the Statement, and then call the related methods of Transaction if necessary. If it is required to be enforced, or if it is not automatically committed and there is dirty data, the commit or rollback operation of the Transaction will be performed.

 

3 study notes or technical summaries per week, aimed at Java programmers with a certain foundation, covering Java advanced, virtual machine, MySQL, NoSQL, distributed computing, open source framework and other fields. Follow the author or WeChat public account backend-develop to get the latest content as soon as possible.

MyBatis Principle Analysis 3 - Data Operation

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326595654&siteId=291194637