Foreword
Part of our success notes loaded Configuration, and writes the information of all we need. According to this Configuration created DefaultSqlSessionFactory. This article, we realize build a sql session SqlSession That mybatis and get into our usual proxy mapper interface class. Before the first piece of code placed before the body
@Autowired private SqlSessionFactory sqlSessionFactory; @GetMapping("/get") public List<AssetInfo> get(){ SqlSession sqlSession = sqlSessionFactory.openSession(); AssetInfoMapper mapper = sqlSession.getMapper(AssetInfoMapper.class); List<AssetInfo> test = mapper.get("测试删除" , "123123123"); System.out.println(test); return test; }
public interface AssetInfoMapper { List<AssetInfo> get(@Param("name") String name, @Param("id")String id); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mapper.AssetInfoMapper"> <select id="get" resultType="com.entity.AssetInfo"> select * from asset_info where id =#{id} and `name` = #{name} </select> </mapper>
This is considered a more classic case of mybatis execution, according to SqlSessionFactory get to SqlSession, and then build a proxy class specifies the mapper interface, and end up calling execute the corresponding xml sql, packaging and return the results to return. This article is based on this case to illustrate. Note that this SqlSessionFactory That is our first step in the final build DefaultSqlSessionFactory
text
1.sqlSessionFactory.openSession();
According to the code map can get to know that we are SqlSession According to this method, we look at the main contents of the method. Conducted a number of overloaded methods, we look directly at the final approach
/ * * ExecType Actuator Type Default passed the ExecutorType.SIMPLE; * default isolation level level things pass null * autoCommit things to submit it automatically defaults to false * * / Private SqlSession openSessionFromDataSource (ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { tx Transaction = null ; the try { // obtain the current environment configuration settings database which contains environmental information and things id information // when we have constructed a building of environment Final environment environment = configuration.getEnvironment (); / / environment get their things level according to the environment if it is empty or is empty things level default ManagedTransactionFactory return, //So we will use the integrated use of SPring Spring things Manager SpringManagedTransactionFactory Final TransactionFactory TransactionFactory = getTransactionFactoryFromEnvironment (Environment); // According to the data source, the isolation level things, submit it automatically generates thing manager here will generate Spring things SpringManagedTransaction tx = TransactionFactory. newTransaction (environment.getDataSource (), Level, the autoCommit); // category generating the actuator and actuator in accordance things // Since the secondary cache turned on by default so SimpleExecutor here will be packaged as CacheExecutor Final the executor executor = configuration.newExecutor (TX , execType); // returns DefaultSqlSession return new new DefaultSqlSession (Configuration, Executor, the autoCommit); } the catch(Exception E) { // capture the exception of the closing things closeTransaction (TX); // On May SO lets have have fetched A Call Connection Close () the throw ExceptionFactory.wrapException ( "Error Opening the session the Cause:." + E, E); } the finally { ErrorContext.instance () RESET ();. } }
Important operations of the method has two steps, the first step is to obtain according to Environment we set the corresponding things, a second step is to construct things and executor Executor according to the type. Two steps of the code we have a look.
The first step method to get things in the factory to see if we can not set Environment, or Environment is not something the factory, will produce a default, in this case using a Spring thing factory. Finally, of course, also have a SpringManagedTransaction
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) { if (environment == null || environment.getTransactionFactory() == null) { return new ManagedTransactionFactory(); } return environment.getTransactionFactory(); }
public class SpringManagedTransactionFactory implements TransactionFactory { ... public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) { return new SpringManagedTransaction(dataSource); } ... }
The second step is configured the Executor, here, that is, whether empty, then select the corresponding processor, here selected common actuator, and the package is about CacheExecutor , here will remember the last executed once all plugin method interceptors can interceptor in Executor to do their own processing
public Executor newExecutor (Transaction Transaction, ExecutorType ExecutorType) { // if null is set as the default type that is ExecutorType.SIMPLE ExecutorType = ExecutorType == null ? defaultExecutorType: ExecutorType; // if the default or is null (config the default type is modified) is then manually set ExecutorType.SIMPLE ExecutorType = ExecutorType == null ? ExecutorType.SIMPLE: ExecutorType; the Executor Executor; // batch mode of operation IF (ExecutorType.BATCH == ExecutorType) { Executor = new new BatchExecutor ( the this , Transaction); } // reuse PreparedStatements the else if (ExecutorType.REUSE == ExecutorType) { Executor = new new ReuseExecutor ( the this , Transaction); } // Common actuators the else { Executor = new new SimpleExecutor ( the this , Transaction); } // if the two cache turned on by default if (cacheEnabled) { // once packaging CachingExecutor Executor = new new CachingExecutor (Executor); } // Note that the method here will be executed once all plugin interceptor Executor = (the Executor) interceptorChain.pluginAll (Executor); return executor; }
After a two-step operation is complete we need to get to the Executor, and have passed through the reference structure, constructed and return to the default DefaultSqlSession
2.sqlSession.getMapper(Class<?> class)
According to the code, we can see that the system is finally get to our agents mapper based on this method. SqlSession note here is DefaultSqlSession, we probably look at DefaultSqlSession construction
Look under their inheritance diagram, you can see it implements the interface SqlSession, in fact, the main method we use a method that is its interface. Through the interface method may comprise a process that mainly operate things, changes, omissions and additions database search.
We also believe that in accordance with the method name can understand the meaning. The specific methods and the like used when later re-analysis
Then look at the member variable DefaultSqlSession contained
private final Configuration configuration; private final Executor executor; private final boolean autoCommit; private boolean dirty; private List<Cursor<?>> cursorList;
- a configuration that is we start building the config class, which contains all the configuration information and mapper information mybatis
- That we are here executor actuator is packed SimpleExecutor of CachingExecutor, in order to support secondary cache
- Whether autoCommit automatically commit the transaction, the default is false
- dirty records whether there have been changes to the operation of this process executor execution
- When using the new features in batches reading cursorList
Once you understand the general structure SqlSession, we began analysis getMapper ie get mapper interfaces proxy class
2.getMapper
Acting in accordance with 2.1 to get our build configuration
@Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
2.2 configuration acquired according to mapperRegistry.getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
2.3 mapperRegistry last acquisition logic
Private Final the Configuration config; // initialize namely mybatis config Private Final the Map <Class <>, MapperProxyFactory <>> knownMappers =?? new new HashMap <> (); // memory mapper interface and its proxy factories in the Map @SuppressWarnings ( " an unchecked " ) public <T> T getMapper (Class <T> type, the SqlSession SQLSESSION) { // storage interface which acquires MapperProxyFactory The Final MapperProxyFactory <T> = mapperProxyFactory (MapperProxyFactory <T> ) knownMappers.get (type); IF ( == mapperProxyFactory null ) { the throw new new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { //根据MapperProxyFactory获取代理类并返回 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
We can see, the final acquisition operation of the proxy class or use the config MapperRegistry we build in to get. The above process is the key knownMappers mapper.xml reflected in nameSpace interfaces generated class attribute, value proxy factory is constructed in accordance with the current interface. SqlSessionFactory resolve in building methods in mapper.xml file will be cached all the xml information in this knownMappers. This is the first article analysis have been analyzed, not repeat them here. This method is the final call newInstance method MapperProxyFactory, we then look
3.MapperProxyFactory.newInstance
public class MapperProxyFactory <T> { // proxy factory interface corresponding Private Final Class <T> mapperInterface; // method corresponding cache Private Final the Map <Method,, MapperMethod> = methodCache new new of ConcurrentHashMap <> (); public MapperProxyFactory (Class < T> mapperInterface) { the this .mapperInterface = mapperInterface; } public Class <T> getMapperInterface () { return mapperInterface; } public the Map <Method,, MapperMethod> getMethodCache () { return methodCache; } // The proxy class construct and return MapperProxy @SuppressWarnings ( "an unchecked" ) protected T the newInstance (MapperProxy <T> mapperProxy) { return (T) the Proxy.newProxyInstance (mapperInterface.getClassLoader (), new new Class [] { } mapperInterface, mapperProxy); } // this method is mainly constructed according to a mapperProxy passed the SqlSession public T the newInstance (the SqlSession SQLSESSION) { Final mapperProxy <T> = mapperProxy new new mapperProxy <> (SQLSESSION, mapperInterface, methodCache); return the newInstance ( mapperProxy); } }
This class of agents that is each mapper class factory interface. Note methodCache of them, this in order to support mybatis cache created. This class has two newInstance method, according to the above it is to create a proxy incoming mapperProxy, we all know jdk create proxy need InvocationHandler a class that implements the interface as a parameter, and the following newInstance is mainly to create an implementation of the interface MapperProxy InvocationHandler instance , passed a note SqlSession, on behalf of this mapper interface, as well as caching method
4.MapperProxy
We all know jdk dynamic proxy class final execution is to achieve a method of a class InvocationHandler interface. Therefore, the final inlet mapper method performed according to the type considered. Let's look at a few more core properties
private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache;
- SqlSession that is a conversation that we created
- mapperInterface that we would interface agent
- methodCache i.e., the cache method MethodProxyFactory
We look at its construction method, that is, do a simple assignment
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; }
InvocationHandler this interface implementation class is created, and then return to step 3 in as a parameter passed to the method jdk dynamic proxy, the final configuration of the mapper proxy class and return to our main method.
Below with reference to a flowchart as
end
You can see, we construct through before initialization SqlSessionFactory created in addition to SqlSession, contains internal actuator Executor, and based on this we initialization to create a proxy class for the proxy class factory proxyFactory each interface created by and returned SqlSession, we mapper final the method of execution is also invoke the method mapperProxy.
About mapper way to do that is to perform the process of mapperProxy invoke method involves the sql execution of content mybatis, this will be resolved in the next chapter