Mybatis notes of the eight part script

Posted by feliperal on Sun, 13 Feb 2022 15:27:10 +0100

Recently, I went out for an interview and wrote some technical points about Mybatis in my resume, so the interviewer began to ask me constantly. This article specially records some problems encountered in the interview.

What is Mybatis

Mybatis is a persistent SQL framework that encapsulates SQL to a certain extent. It encapsulates the commonly used crud interface to a certain extent, which reduces the cumbersome SQL operation of developers.

Why do you choose to use this framework at work?

  • Simplifies the complexity of sql related operations
  • Automatically handle the creation and release of links and the parameter assembly of sql
  • Some third-party caching plug-ins can be introduced
  • Provides integration capabilities for Spring containers
  • The learning cost is low, and there are many materials and information on the market

Talk about the normal JDBC implementation specification?

First, you need to establish a link through DriverManager, and then get the Statement object.

public class JdbcApplication {
    static String driverName = "com.mysql.jdbc.Driver";
    static String username = "root";
    static String password = "test";
    static String url = "jdbc:mysql://cloud.db.com:3306/db_user";

    public static void main(String[] args) throws SQLException {
        Connection connection = DriverManager.getConnection(url,username,password);
        String sql = "select * from t_user";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            System.out.println(id);
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

General steps for establishing a data source:
1. Build data source
2. Create database links through drivermanager Getconnection()
3. Create and execute sql, for example, call the Statement interface for execution, the executeQuery() method defined in the JDBC api performs query operation, and the executeUpdate() method performs update operation
4. The processing of the result set is generally to perform operations such as getint and getString on the resultSet.
5. Release of links, for example close related operations.

You said you've seen the source code of MyBatis and listed some internal core classes?

Configuration

Manage MySQL config XML global configuration relation class

SqlSessionFactory

SqlSession management factory interface

SqlSession

It is an interface for users (programmers). SqlSession provides many methods to operate the database

Executor

The actuator is an interface (basic actuator, cache actuator)
Function: SqlSession operates the database through the executor internally

MappedStatement

Underlying encapsulated object
Function: store and package the operation database, including sql statements, input and output parameters

StatementHandler

Specific operations include the handler interface related to the database

ResultSetHandler

The handler interface of the returned result of the specific operation database

SQL object

The encapsulation object for splicing sql statement information in mybatis

ScriptRunner

mybatis is an internal script runner that can receive link parameter information.

SqlRunner

Using SqlRunner can simplify our jdbc operations. The code is as follows:

public static void main(String[] args) throws SQLException {
    Connection connection = DriverManager.getConnection(url,username,password);
    SqlRunner sqlRunner = new SqlRunner(connection);
    String querySql = new SQL(){{
        SELECT("*");
        FROM("t_user");
        WHERE("1=1");
    }}.toString();
    List<Map<String,Object>> resultMap = sqlRunner.selectAll(querySql);
    for (Map<String, Object> stringObjectMap : resultMap) {
        System.out.println(stringObjectMap.toString());
    }
}

MetaObject

A commonly used reflection tool class is often seen in the mybatis source code.

MetaClass

This includes an org apache. ibatis. reflection. Reflector object, which seems to contain more attribute values obtained by reflection, such as method information, field attributes, etc.

ObjectFactory

This is a factory design for creating objects. Before creating some objects, warrper will be wrapped in another layer, and the input parameter information can be adjusted appropriately.

ObjectFactory objectFactory = new DefaultObjectFactory();
List<Object> strs = new ArrayList<Object>();
List<Class<?>> classList = new ArrayList<>();
String str = objectFactory.create(String.class,classList,strs);

ProxyFactory

It is an agent factory, which mainly adapts to several agent mechanisms in mybatis. The ProxyFactory interface has two different implementations: CglibProxyFactory and JavassistProxyFactory

If the Spring framework is not used, how should the Mybatis framework be used?
Execution process of native mybatis1:

public static void main(String[] args) throws IOException {
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //The core point is here
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.selectAll();
    System.out.println(userList.toString());
}

First, create a sqlsession by combining the data of the configuration file (which can be io stream information) through the sqlsessionfactory, and then obtain the jdk proxy created through MapperProxy according to the sqlsession. When the corresponding sql statement is executed, the invoke statement in the invocationhandler will be called. Next is a series of crud encapsulated handler processing.

Talk about the internal cache design of MyBatis

Whenever we use MyBatis to open a session with the database, MyBatis will create a SqlSession object table
Show a database session. In a session to the database, we may repeatedly execute the same query
If we do not take some measures to query the database in a very short time
If you make exactly the same query, their results are likely to be exactly the same. Due to the high cost of querying the database once,
This may cause a great waste of resources.

In order to solve this problem and reduce the waste of resources, MyBatis will establish a session in the SqlSession object representing the session
Simple caching, which caches the results of each query. When the next query, if it is judged that there is an end in the past
For the same query, the results will be directly taken out from the cache and returned to the user without another database query
Yes.

The internal cache directory of mybatis contains a variety of cache designs, all of which are stored in a package. It mainly implements the cache interface.

L1 cache

L1 cache is a storage design associated with sqlsession. When the data is queried for the first time, it will be stored in a hashmap, and the corresponding cacheKey can be found in the source code org apache. ibatis. executor. Baseexecutor #createcachekey.

If you need to see more details of the cache, you can switch to org. Org in debug mode apache. ibatis. cache. impl. Check in the perpetual cache.

It contains a HashMap collection to store cached data. The so-called cache clearing is to clear the HashMap.

How does caching achieve unique values?

The unique value picture is realized through the function id + package name of the class:

Internal caching also distinguishes between environment types:

The environment id here exactly corresponds to the id filled in the configuration file:

Why is L1 cache also called query cache

Because the queried data will be put into a map. Once a write operation occurs, the cache will become invalid.

When will the L1 cache fail
Once the corresponding update operation is involved, the cache will be cleaned up.
The source code is as follows:

@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();
  return doUpdate(ms, parameter);
}

How does the framework identify which caches to clean up?

Since the cache key is built in the way of package name + class name + id, it is impossible to identify which cache to clean up. Therefore, once the update operation is carried out, the whole map is cleaned up directly.



Relationship between L1 cache and sqlsession

An sqlsession will have its own map as the first level cache, and the cache between different sqlsessions will not be shared.
In the case of multiple data sources, different sqlsessionfactories will be connected, and different sqlsessionfactories correspond to different sqlsessions. Therefore, the primary cache is different, so the query and update will not affect each other.

Can I clean up the cache manually?

You can use sqlsession clearCache(); Operation implementation

How to judge whether two queries are the same query:

According to the construction mechanism of cachekey:

The cached key is constructed by several parameters:

  • hashcode
  • Number range of queries: if it is selectall series, it is 0-2147483647 (about 2.1 billion)
  • sql statement
  • Configuration id of enviorment

L2 cache

The internal default of the framework is that the L2 cache is not enabled, which needs to be manually enabled by developers. The L2 cache is identified according to the sqlsession. The same mapper will share the cache in different sqlsessions.
Code case:
You need to perform a commit operation to write to the L2 cache

At the same time, additional configuration is required in xml configuration:
mybatis-config.xml file:

Corresponding to the configuration in mapper file:

Configuration items such as userCache and flushCache can also be configured in mybatis. userCache is used to set whether to disable the secondary cache. Setting useCache=false in the statement can disable the secondary cache of the current select statement, that is, sql will be issued for query every time. The default is true, that is, the sql uses the secondary cache.

Topics: Java JavaEE Mybatis Interview