O BatchExecutor da análise de código-fonte do Executor no MyBatis não consegue entender ou entender o jdbc, e a análise do código-fonte do Mybatis? Ex, consulte o agente dinâmico JDK da origem de mybatis

Para facilitar a análise do código fonte, vamos primeiro a uma demonstração do MyBatis

mybatis-mysql-config.xml

<? xml version = "1.0" encoding = "UTF-8"?> 
<! DOCTYPE configuration PUBLIC "- // mybatis.org//DTD Config 3.0 // PT" 
        "http://mybatis.org/dtd/mybatis -3-config.dtd "> 

<configuração> 
    <propriedades> 
        <nome da propriedade =" driver "value =" com.mysql.cj.jdbc.Driver "/> 
        <nome da propriedade =" url "value =" jdbc: mysql: //127.0.0.1:3306/gys?serverTimezone=UTC "/> 
    </properties> 
    <settings> 
        <nome da configuração =" defaultExecutorType "value =" SIMPLE "/> 
    </settings> 
    <! - 环境 配置 , 的MySQL -> 
    <ambientes padrão = "dev">
        <ID do ambiente = "dev">  
            <! - Especifique o tipo de gerenciamento de transações, aqui, basta usar as configurações de envio e reversão JDBC do Java->
            <transactionManager type = "JDBC" />
            <! - dataSource indica POOLED ou JDBC - - 
            <dataSource type = "POOLED"> 
                <nome da propriedade = "driver" value = "$ {driver}"> < / propriedade> 
                <nome da propriedade = "url" value = "$ {url}"> </property> 
                <nome da propriedade = "nome de usuário" value = "root"> </property> 
                <nome da propriedade = "senha" value = " gys "> </property> 
            </dataSource> 
        </environment>        
    </environments> 
    <mappers>    
        <mapper resource =" mapper / user.xml "> </mapper> 
    </ mappers> 
</configuration>

user.xml

<? xml version = "1.0" encoding = "UTF-8"?> 
<! DOCTYPE mapper PUBLIC "- // mybatis.org//DTD Mapper 3.0 // PT" 
        "http://mybatis.org/dtd/mybatis -3-mapper.dtd "> 
<mapeador namespace =" dao.IUserMapper ">   

    <insert id =" insertUser" parameterType = "model.User"> 
        INSERT INTO usuário 
        (nome, idade) 
        valores 
        (# {name}, # { idade}) 
    </insert> 

</mapper>

Método de entrada main:

1 public static void main (String [] args) lança a exceção { 
 2 SqlSessionFactory sqlSessionFactory1 = new SqlSessionFactoryBuilder (). Build (Resources.getResourceAsStream ("mybatis-mysql-config.xml"), "dev" ); 
 3 SqlSession sqlSession1 = sqlSessionFactory1.openSession (true ); 
 4 IUserMapper userMapper = sqlSession1.getMapper (IUserMapper.class );  5 Usuário usuário = novo Usuário ();  6 user.setAge (28 ); 7 user.setName ("a" ); 8 int i = userMapper.insertUser (usuário); 9 System.out.println ("受 影响 的 行 数" + i); 10 sqlSession1.close (); 11}

O código do Executor ainda está muito longe do código de execução Demo acima. Se você analisar o Executor, deverá analisar e analisar esse código muito longo;

Como esse código-fonte pode começar a fazer com que as pessoas se sintam naturais e o deixem ir?

Esqueça, vamos fazer passo a passo;

A primeira etapa: como obter a configuração defaultExecutorType durante o processo de compilação

 

  A linha 75 instancia um objeto XMLConfigBuilder, que é um analisador xml.

A linha 78 chama o método de construção na linha 91. O parâmetro deste método é um objeto de Configuração; portanto, o método parser.parse () deve retornar um objeto de Configuração;

Em outras palavras, é o arquivo de configuração lido em parser.parse () e atribuído ao objeto de configuração.

Código fonte Parser.parse ():

 código fonte parseConfiguration ()

1 private void parseConfiguration (raiz do XNode) { 
 2 tenta {      
 3 propertiesElement (root.evalNode ("properties" )); 
 4 Configurações de propriedades = settingsAsProperties (root.evalNode ("settings" ));  5  loadCustomVfs (configurações);  6 loadCustomLogImpl (configurações); 7 typeAliasesElement (root.evalNode ("typeAliases" )); 8 pluginElement (root.evalNode ("plugins" )); 9 objectFactoryElement (root.evalNode ("objectFactory" )); 10 objectWrapperFactoryElement (root.evalNode ("objectWrapperFactory" )); 11 reflectorFactoryElement (root.evalNode ("reflectorFactory" )); 12 // 解析 configurações 内容 13settingsElement (configurações); 14 environmentElement (root.evalNode ("environment" )); 15 databaseIdProviderElement (root.evalNode ("databaseIdProvider" )); 16 typeHandlerElement (root.evalNode ("typeHandlers" )); 17 mapperElement (root.evalNode ("mappers" )); 18} catch (Exceção e) {19 lança nova BuilderException ("Erro ao analisar a Configuração do Mapeador SQL. Causa:" + e, e); 20 } 21}

Com base no nome do método, pode-se inferir que a configuração é tratada; consulte as 13 linhas de código diretamente.

Código fonte SettingsElement ():

1 private void settingsElement (Propriedades props) { 
 2 configuration.setAutoMappingBehavior (AutoMappingBehavior.valueOf (props.getProperty ("autoMappingBehavior", "PARTIAL" ))); 
 3 configuration.setAutoMappingUnknownColumnBehavior (AutoMappingUnknownColumnBehavior.valueOf (props.getProperty ("autoMappingUnknownColumnBehavior", "NONE" ))); 
 4 configuration.setCacheEnabled (booleanValueOf (props.getProperty ("cacheEnabled"), true ));  5 configuration.setProxyFactory ((ProxyFactory) createInstance (props.getProperty ("proxyFactory" )));  6 configuration.setLazyLoadingEnabled (booleanValueOf (props.getProperty ("lazyLoadingEnabled"), false))); 7 configuration.setAggressiveLazyLoading (booleanValueOf (props.getProperty ("aggressiveLazyLoading"), false )); 8 configuration.setMultipleResultSetsEnabled (booleanValueOf (props.getProperty ("multipleResultSetsEnabled"), true )); 9 configuration.setUseColumnLabel (booleanValueOf (props.getProperty ("useColumnLabel"), true )); 10 configuration.setUseGeneratedKeys (booleanValueOf (props.getProperty ("useGeneratedKeys"), false )); // 
11 configuração.setDefaultExecutorType (ExecutorType.valueOf (props.getProperty ("defaultExecutorType", "SIMPLE"))); 12 configuration.setDefaultStatementTimeout (integerValueOf (props.getProperty ("defaultStatementTimeout"), null )); 13 configuração.)); 14 configuration.setDefaultResultSetType (resolveResultSetType (props.getProperty ("defaultResultSetType" ))); 15 configuration.setMapUnderscoreToCamelCase (booleanValueOf (props.getProperty ("mapUnderscoreToCamelCase"), false )); 16 configuration.setSafeRowBoundsEnabled (booleanValueOf (props.getProperty ("safeRowBoundsEnabled"), false )); 17 configuration.setLocalCacheScope (LocalCacheScope.valueOf (props.getProperty ("localCacheScope", "SESSION" ))); 18 configuration.setJdbcTypeForNull (JdbcType.valueOf (props.getProperty ("jdbcTypeForNull", "OTHER" ))); 19 configuration.setLazyLoadTriggerMethods (stringSetValueOf (props.getProperty ("lazyLoadTriggerMethods"), "é igual a, clone, hashCode, toString")); 20 configuration.setSafeResultHandlerEnabled (booleanValueOf (props.getProperty ("safeResultHandlerEnabled"), true )); 21 configuration.setDefaultScriptingLanguage (resolveClass (props.getProperty ("defaultScriptingLanguage" )))); 22 configuration.setDefaultEnumTypeHandler (resolveClass (props.getProperty ("defaultEnumTypeHandler" ))); 23 configuration.setCallSettersOnNulls (booleanValueOf (props.getProperty ("callSettersOnNulls"), false )); 24 configuration.setUseActualParamName (booleanValueOf (props.getProperty ("useActualParamName"), true )); 25 configuration.setReturnInstanceForEmptyRow (booleanValueOf (props.getProperty ("returnInstanceForEmptyRow"), false )); 26 configuration.setLogPrefix (props.getProperty ("logPrefix")); 27 configuration.setConfigurationFactory (resolveClass (props.getProperty ("configurationFactory" ))); 28}

Olhe para a 11ª linha de código é dar à configuração um valor defaultExecutorType claro.

getProperty (key, defaultValue) possui dois parâmetros: o primeiro parâmetro é o valor da chave da propriedade. De acordo com esse valor da chave, o valor da propriedade é obtido. Se não for obtido, o segundo parâmetro será usado como o valor padrão. 
Se nenhum valor de <nome da configuração = "defaultExecutorType" = "SIMPLE" /> estiver configurado, o valor SIMPLE será usado.
Falando nisso, vamos falar sobre quais parâmetros o defaultExecutorType possui
SIMPLES: É um executor comum 
REUTILIZAR: O executor irá repetir (leia-se: bug) com instruções preparadas (PreparedStatements) O
executor BATCH repetirá (bug) instruções e executará atualizações em lote.

No começo, vi que o conteúdo oficial não sabia o que os três significavam, nem sabia se deveria ler chong ou zhong.
Altere os parâmetros primeiro e execute Demo para ver o resultado.
<nome da configuração = "defaultExecutorType" value = "SIMPLE" />
<nome da configuração = "defaultExecutorType" value = "REUSE" />
Depois que essas duas configurações são configuradas separadamente, você pode inserir normalmente alguns dados no banco de dados e o número de linhas afetadas é 1, apenas
<nome da configuração = "defaultExecutorType" value = " BATCH " /> Os dados retornados por esta configuração são os seguintes itens estranhos: não insere dados no banco de dados nem gera uma exceção.

Número de linhas afetadas -2147482646
1. As configurações SIMPLE e REUSE podem ser executadas normalmente, então qual é a diferença? 
2. Quais são os dados estranhos retornados pela configuração do BATCH e por que eles não são bem-sucedidos.

Eu não disse o que o Executor faz por tanto tempo.
Executor significa executor, e é usado para agendar StatementdHandler, ParameterHandler, ResultHandler, etc. para executar o SQL correspondente.Aqueles
familiarizados com o JDBC devem estar familiarizados com os nomes dos manipuladores acima. Se você esqueceu o JDBC, dê uma olhada neste blog: Se você não entende o jdbc, e a análise do código-fonte do Mybatis?
Como o Ex ecutor é o planejamento total, ele deve ser chamado no local do proxy dinâmico do Mapper JDK no MyBatis.
Se você não tiver certeza sobre esse proxy dinâmico, poderá dar uma olhada neste blog: No código-fonte mybatis
, é possível ver que o proxy dinâmico do JDK pode ser rastreado a partir da quarta linha de código na demonstração, o método getMapper ().

 

 

 

 

 

 

 

 

 

1 execução pública de objeto (SqlSession sqlSession, Object [] args) { 
 2     resultado do objeto; 
 3 switch (command.getType ()) { 
 4 case INSERT: {// inset 语句
 5 Objeto param = method.convertArgsToSqlCommandParam (args);  6 resultado = rowCountResult (sqlSession.insert (command.getName (), param));  7 intervalos ; 8 } 9 case UPDATE: {// atualização 语句 10 Objeto param = method.convertArgsToSqlCommandParam (args); 11 resultado = rowCountResult (sqlSession.update (command.getName (), param)); 12 intervalos ; 13 } 14 case DELETE: {// delete] 15 Objeto param = method.convertArgsToSqlCommandParam (args); 16 resultado =rowCountResult (sqlSession.delete (command.getName (), param)); 17 intervalos ; 18 } 19 case SELECT: // seleciona 20 if (method.returnsVoid () && method.hasResultHandler ()) {21 executeWithResultHandler (sqlSession, args); 22 resultado = nulo ; 23} senão if (method.returnsMany ()) {24 result = executeForMany (sqlSession, args); 25} senão if (method.returnsMap ()) {26 result = executeForMap (sqlSession, args); 27} else if (method.returnsCursor ()) {28 result = executeForCursor (sqlSession, args); 29} else {30 Objeto param = method.convertArgsToSqlCommandParam (args); 31 resultado = sqlSession.selectOne (command.getName (), param); 32 se(method.returnsOptional () 33 && (result == null ||! method.getReturnType (). equals (result.getClass ()))) {34 result = Optional.ofNullable (resultado); 35 } 36 } 37 ; 38 } 39 40 resultado do retorno ; 41}

 

A sequência de chamada de getMapper (): 

defaultSqlSession.getMapper () ==》 configuration.getMapper () ==> MapperRegistry.getMapper () ==> MapperProxyFactory.newInstance () ;

De acordo com as 46 e 47 linhas de código da última figura, combinadas com as regras de chamada do proxy dinâmico JDK, pode-se inferir que a interface InvocationHandler deve ser implementada no MapperProxy e o método invoke é implementado.

1   @Override 
 2 public A chamada de objeto (proxy de objeto, método Method, Object [] args) lança Throwable { 
 3 try { 
 4 // 调用 objeto 中 的 方法
 5 if (Object.class .equals (method.getDeclaringClass ())) {  6 método de retorno.invoke (this , args);  7} else if (method.isDefault ()) {// 调用 接口 中 的 默认 方法 8 if (privateLookupInMethod == null ) {9 retorna invokeDefaultMethodJava8 (proxy, método, args); 10} else {11 return invokeDefaultMethodJava9 (proxy, método, args); 12 } 13 } 14} catch (Throwable t) {15 throw ExceptionUtil.unwrapThrowable (t); 16} 17 // Descubra se existe esse método no cache e envolva-o em um objeto MapperMethod 18 final MapperMethod mapperMethod = cachedMapperMethod (método); 19 // Não sei o que executar temporariamente, só posso continuar perseguindo 20 retornos mapperMethod.execute (sqlSession, args); 21}

código fonte execute ():

 



 

 



Acho que você gosta

Origin www.cnblogs.com/guoyansi19900907/p/12691459.html
Recomendado
Clasificación