Heim >Java >javaLernprogramm >Wählen Sie eine Analyse und Zusammenfassung des Quellcodes aus
Beispielcode
Im vorherigen Artikel hieß es, dass für MyBatis Einfügen, Aktualisieren und Löschen eine Gruppe sind, denn für MyBatis heißt es dass sie alle aktualisiert sind; select ist eine Gruppe, da es sich bei MyBatis um select handelt.
Dieser Artikel untersucht den Implementierungsprozess von select. Der Beispielcode lautet:
1 public void testSelectOne() { 2 System.out.println(mailDao.selectMailById(8)); 3 }
Die Implementierung von Die Methode selectMailById lautet:
1 public Mail selectMailById(long id) {2 SqlSession ss = ssf.openSession();3 try {4 return ss.selectOne(NAME_SPACE + "selectMailById", id);5 } finally {6 ss.close();7 }8 }
Wir wissen, dass die von MyBatis bereitgestellte Auswahl zwei Methoden hat, selectList und selectOne, aber dieser Artikel analysiert nur und benötigt nur Um die SelectOne-Methode zu analysieren, wird der Grund erläutert.
selectOne-Methodenfluss
Schauen Sie sich zunächst den selectOne-Methodenfluss von SqlSession an Die Methode befindet sich in DefaultSqlSession:
1 public <T> T selectOne(String statement, Object parameter) { 2 // Popular vote was to return null on 0 results and throw exception on too many. 3 List<T> list = this.<T>selectList(statement, parameter); 4 if (list.size() == 1) { 5 return list.get(0); 6 } else if (list.size() > 1) { 7 throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); 8 } else { 9 return null;10 }11 }
Aus diesem Grund habe ich gesagt, dass die Methoden selectOne und selectList nur die Methode selectList analysieren müssen, weil In MyBatis werden alle selectOne-Operationen schließlich in selectList-Operationen umgewandelt. Es handelt sich lediglich um die Beurteilung der Anzahl der Ergebnismengen nach Abschluss der Operation Fehler wird gemeldet.
Dann schauen Sie sich die Code-Implementierung von selectList in Zeile 3 an. Die Methode befindet sich auch in DefaultSqlSession:
1 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 2 try { 3 MappedStatement ms = configuration.getMappedStatement(statement); 4 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 5 } catch (Exception e) { 6 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 7 } finally { 8 ErrorContext.instance().reset(); 9 }10 }
Ich werde nicht über die Erfassung von MappedStatement in Zeile 3 sprechen. Folgen wir der Implementierung der Abfragemethode von Executor in Zeile 4. Hier wird ein Dekoratormodus verwendet, um eine Caching-Funktion zu SimpleExecutor hinzuzufügen. Der Code befindet sich in CachingExecutor:
1 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {2 BoundSql boundSql = ms.getBoundSql(parameterObject);3 CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);4 return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);5 }
Der Code in Zeile 2 erhält BoundSql. Der Inhalt in BoundSql wurde oben erwähnt und wird am Ende zusammengefasst.
Der Code in Zeile 3 erstellt den Cache-Schlüssel basierend auf den Eingabeparametern.
Der Code in Zeile 4 führt die Abfrageoperation aus. Der Code befindet sich auch in CachingExecutor:
1 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) 2 throws SQLException { 3 Cache cache = ms.getCache(); 4 if (cache != null) { 5 flushCacheIfRequired(ms); 6 if (ms.isUseCache() && resultHandler == null) { 7 ensureNoOutParams(ms, parameterObject, boundSql); 8 @SuppressWarnings("unchecked") 9 List<E> list = (List<E>) tcm.getObject(cache, key);10 if (list == null) {11 list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);12 tcm.putObject(cache, key, list); // issue #578 and #11613 }14 return list;15 }16 }17 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);18 }
Es gibt keine Konfiguration und keinen Verweis auf Cache, daher wird das Urteil in Zeile 4 nicht ausgeführt und der Code in Zeile 17 befindet sich in BaseExecutor, der übergeordneten Klasse von SimpleExecutor Der Quellcode ist implementiert als:
1 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 2 ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); 3 if (closed) { 4 throw new ExecutorException("Executor was closed."); 5 } 6 if (queryStack == 0 && ms.isFlushCacheRequired()) { 7 clearLocalCache(); 8 } 9 List<E> list;10 try {11 queryStack++;12 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;13 if (list != null) {14 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);15 } else {16 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);17 }18 } finally {19 queryStack--;20 }21 if (queryStack == 0) {22 for (DeferredLoad deferredLoad : deferredLoads) {23 deferredLoad.load();24 }25 // issue #60126 deferredLoads.clear();27 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {28 // issue #48229 clearLocalCache();30 }31 }32 return list;33 }
Der Code in Zeile 16 wird hier ausgeführt. Die queryFromDatabase-Methode wird implementiert als:
1 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { 2 List<E> list; 3 localCache.putObject(key, EXECUTION_PLACEHOLDER); 4 try { 5 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); 6 } finally { 7 localCache.removeObject(key); 8 } 9 localCache.putObject(key, list);10 if (ms.getStatementType() == StatementType.CALLABLE) {11 localOutputParameterCache.putObject(key, parameter);12 }13 return list;14 }
Der Code erreicht Zeile 5 und führt schließlich die duQuery-Methode aus. Die Implementierung der Methode ist:
1 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); 6 stmt = prepareStatement(handler, ms.getStatementLog()); 7 return handler.<E>query(stmt, resultHandler); 8 } finally { 9 closeStatement(stmt);10 }11 }
Sehen Da die Codes in den Zeilen 4 bis 6 mit denen des vorherigen Updates identisch sind, werde ich nicht auf Details eingehen. Freunde, die einen Eindruck vom Handler haben, sollten sich daran erinnern, dass es sich um PreparedStatementHandler handelt Die Abfragemethode von PreparedStatementHandler ist implementiert.
Abfragemethodenimplementierung von PreparedStatementHandler
Folgen Sie der Abfragemethode von PreparedStatementHandler bis zum Ende . Die endgültige Implementierung lautet:
1 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {2 PreparedStatement ps = (PreparedStatement) statement;3 ps.execute();4 return resultSetHandler.<E> handleResultSets(ps);5 }
Beachten Sie, dass Zeile 3 die Abfrageoperation ausführt und der Code in Zeile 4 die Ergebnismenge verarbeitet und das Ergebnis konvertiert In eine Liste gesetzt, wird die Methode handleResultSets wie folgt implementiert:
1 public List<Object> handleResultSets(Statement stmt) throws SQLException { 2 ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); 3 4 final List<Object> multipleResults = new ArrayList<Object>(); 5 6 int resultSetCount = 0; 7 ResultSetWrapper rsw = getFirstResultSet(stmt); 8 9 List<ResultMap> resultMaps = mappedStatement.getResultMaps();10 int resultMapCount = resultMaps.size();11 validateResultMapsCount(rsw, resultMapCount);12 while (rsw != null && resultMapCount > resultSetCount) {13 ResultMap resultMap = resultMaps.get(resultSetCount);14 handleResultSet(rsw, resultMap, multipleResults, null);15 rsw = getNextResultSet(stmt);16 cleanUpAfterHandlingResultSet();17 resultSetCount++;18 }19 20 String[] resultSets = mappedStatement.getResultSets();21 if (resultSets != null) {22 while (rsw != null && resultSetCount < resultSets.length) {23 ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);24 if (parentMapping != null) {25 String nestedResultMapId = parentMapping.getNestedResultMapId();26 ResultMap resultMap = configuration.getResultMap(nestedResultMapId);27 handleResultSet(rsw, resultMap, null, parentMapping);28 }29 rsw = getNextResultSet(stmt);30 cleanUpAfterHandlingResultSet();31 resultSetCount++;32 }33 }34 35 return collapseSingleResultList(multipleResults);36 }
Fassen Sie diese Methode zusammen.
Zeile 7 des Codes ruft das ResultSet über die getResultSet-Methode von PreparedStatement ab und verpackt das ResultSet in einen ResultSetWrapper. Der ResultSetWrapper enthält nicht nur das ResultSet, sondern definiert auch jeden Teil davon Von der Datenbank zurückgegebene Daten, der JDBC-Typ, der der Spalte entspricht, und der Typ der Java-Klasse, der der Spalte entspricht. Das Wichtigste ist außerdem, dass sie auch TypeHandlerRegister (Typprozessor, alle Parameter) enthält werden über TypeHandler festgelegt).
Die 9. Codezeile erhält die Definition im
Das obige ist der detaillierte Inhalt vonWählen Sie eine Analyse und Zusammenfassung des Quellcodes aus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!