Objective
This article debug MyBatis source version: 3.2.7
MyBatis provides JDBC and managed two transaction management, this article mainly discusses the JDBC transaction management mode.
If you don't understand this article enough, look at another blog post to simulate the implementation of MyBatis data sources and transactions: Dynamic proxy +threadlocal for data sources and transaction management.
This article mainly discusses the content:
1. Start, Commit, rollback, and shutdown of the MyBatis JDBC transaction
2. Multithreading security for connection in MyBatis JDBC transactions
First, the mybatis of the initialization core: Abandoned engine Sqlsessionmanager
It can be so illusion that the whole mybatis frame is sqlsessionmanager, he is both MyBatis "engine" and mybatis "steering wheel". But this class seems to have been deprecated, replaced by defaultsqlsessionfactory and defaultsqlsession, but in fact they are almost equal, nearly 1=2 concepts. I am also actively looking for reasons to be deprecated, at least for now, from the results of the debug framework, this class is not really being made. But this kind of thought is very helpful for a better understanding of factory and the session.
1. Sqlsessionfactorybuilder and Configuration
MyBatis's starting point is Sqlsessionfactorybuilder, which uses the builder method to load the Mybatis-config.xml configuration file, thus enabling the entire framework to get "running" environmental conditions. The Sqlsessionfactorybuilder has 9 builder methods, four are related to the byte stream, four are related to the character stream, the complete one by one corresponds, and the final placement of all the stream-related builder methods is build (Configuration config), that is, whether it is a byte stream or a character stream, they end up sending a stream of XML configuration files to the parsed object of XML Xmlconfigbuilder, The ultimate goal of the Xmlconfigbuilder object is that the parse-injected stream becomes a configuration object, and the configuration object parses almost the same object as the config tag one by one in the configuration file. He is the configuration center of the MyBatis framework.
Package Org.apache.ibatis.session;import Java.io.ioexception;import Java.io.inputstream;import java.io.Reader; Import Java.util.properties;import Org.apache.ibatis.builder.xml.xmlconfigbuilder;import Org.apache.ibatis.exceptions.exceptionfactory;import Org.apache.ibatis.executor.errorcontext;import Org.apache.ibatis.session.defaults.defaultsqlsessionfactory;public class Sqlsessionfactorybuilder {/** * The final placement of all character stream Builder is that the method * eventually injects the Stream builder method into the Xmlconfigbuilder object and parses the stream into a configuration object through its parser method * The resulting configuration object is eventually passed into the last builder method construct sqlsessionfactory */public sqlsessionfactory build (Reader reader, String Environment, properties properties) {try {xmlconfigbuilder parser = new Xmlconfigbuilder (reader, Environment, properties ); return build (Parser.parse ());} catch (Exception e) {throw exceptionfactory.wrapexception ("Error building sqlsession.", e);} finally { Errorcontext.instance (). Reset (), try {reader.close ();} catch (IOException e) {//intentionally ignore. Prefer previous error.}}} /** * All byte stream related to the final placement of the builder method, the function of the method and the character stream consistent, but the flow is different just passed in */public sqlsessionfactory build (InputStream InputStream, String Environment, properties properties) {try {xmlconfigbuilder parser = new Xmlconfigbuilder (InputStream, Environment, properties); return build (Parser.parse ());} catch (Exception e) {throw exceptionfactory.wrapexception ("Error building sqlsession.", e);} finally { Errorcontext.instance (). Reset (), try {inputstream.close ();} catch (IOException e) {//intentionally ignore. Prefer previous error.}}} /** * The final placement of all stream-related builder methods, passing in a configuration object generated by Xmlconfigbuilder.parser * Eventually generate sqlsessionfactory through the configuration object * Actually Sqlsessionfactory has two subclasses, one is Defaultsqlsessionfactory, And the other is Sqlsesisonmanager * The next section details the two objects */public sqlsessionfactory build (Configuration config) {return new Defaultsqlsessionfactory (config);}}
Summary: All 8 builder methods that are related to the flow, just to inject the stream into the Xmlconfigbuilder object, parse the build configuration, and from the final builder (configuration config) The method constructs the Sqlsessionfactory (actually the Defaultsqlsessionfactory object, the next section is detailed).
2. Sqlsessionfactory and sqlsession: dual-spec engine Sqlsessioinmanager
Sqlsessionfactory is a factory, while Sqlsessio N is a session, the factory means the production center, and the conversation means the Operation center.
Sqlsessionmanager not only implements the Sqlsessionfactory specification, but also implements the Sqlsession specification, in fact the factory and the session in addition to the Sqlsessionmanager, there is a default subclass, The Defaultsqlsessionfactory and defaultsqlsession (the relationship as shown) are respectively. The relationship between the three of them: Sqlsessionmanager through the adorner mode to obtain all the defaultsqlsessionfactory ability, that is, the ability of opensession, The sqlsession obtained through Sqlsessionmanager are actually all from defaultsqlsessionfactory Sqlsessionmanager is constructed by the JDK dynamic agent to obtain the Defaultsqlsession proxy object, the content of the agent is a judge whether there is a local sqlsession generation logic, Furthermore, all the capabilities of defaultsqlsession and database interaction are obtained.
Because of the reason for being discarded, this no longer discusses the idea of the Origin code, but it is recommended that if you want to learn more, you can cooperate with Defaultsqlsessionfactory and defaultsqlsession to study together, the effect is even more!
In fact, the whole mybatis framework is really used defaultsqlsessionfactory and Defaultsqlsession, the former for the production of the latter, that is, through the factory opensession got Defaultsqlsession , and Defaultsqlsession encapsulates all the logic that interacts with the database, noting that all logic except the open transaction.
Ii. JDBC Transaction IUD (INSERT, UPDATE, DELETE)
---------------------------------------------------------
A. When the transaction opens: Where does the transaction start?
B. Does the select have an open transaction?
C. What is the transaction of multiple select in the business layer?
D. When did the IUD operation start?
E. What is the transaction of multiple IUD operations in the operational layer?
........
---------------------------------------------------------
If you want to know, please look down. For an example of insert operation, the Insert sample source code is as follows, and everything in this section is expanded around this sample code.
sqlsession session = Factory.opensession (), Session.insert ("Test.insertuser", new User (null, "Zhangsan", "123", "Male", ), Session.insert ("Test.insertuser", new User (null, "Lisi", "123", "Male", "()"); Session.commit (); Session.close ();
As in the example code above, two inserts are made (explicitly, the transaction is not open in opensession), but the transaction is only opened once, and if you do not want to know more, you can look directly at the debug log validation logic (such as debug log), if you want to know more, Look down, why does MyBatis know only to open the business at the time of the first IUD?
Csdn picture upload, I will 艹 ... The log excerpt information is shown below.
2015-05-10 01:24:54,209 Debug jdbctransaction:132-opening JDBC connection2015-05-10 01:24:54,647 Debug pooleddatasource:380-created connection 319977154.2015-05-10 01:24:54,647 DEBUG jdbctransaction:98-setting Autocommit to False on JDBC Connection [[email protected]]2015-05-10 01:24:54,647 DEBUG insertuser:139-==> Prep Aring:insert into Tbl_user (username, password, gender, age) VALUES (?,?,?,?) 2015-05-10 01:24:54,710 DEBUG insertuser:1 ==> Parameters:zhangsan (String), 123 (String), male (String), (Integer) 2015-05-10 01:24:54,725 DEBUG Insertuser : 139-<== updates:12015-05-10 01:24:54,725 DEBUG insertuser:139-==> preparing:insert into Tbl_user (username , password, gender, age) VALUES (?,?,?,?) 2015-05-10 01:24:54,725 DEBUG insertuser:139-==> parameters:lisi (String) , 123 (String), male (string), 01:2 (Integer) 2015-05-10 01:24:54,725 DEBUG insertuser:139-<== updates:12015-05-10 4:54,725 DEBUG jdbctransaction:69-committing JDBC Connection [[email protected]]2015-05-10 01:24:54,756 DEBUG jdbctransaction:120-resetting autocommit to True on JDBC Connection [[email protected]]2015-05-10 01:24:54,756 DEBUG jdbctransaction:88-closing JDBC Connection [[email&] nbsp;protected]]2015-05-10 01:24:54,756 DEBUG pooleddatasource:334-returned connection 319977154 to pool.
1. Build sqlsession to do database operations, first to obtain sqlsession objects, so what did Factory.opensession do? In order to better understand the following code, you also need to first understand jdbctransactionfactory, Jdbctransaction, Baseexecutor, Simpleexecutor, defaultsqlsession source code, Fortunately, these classes of source code are not too difficult to express the logic.
Package Org.apache.ibatis.session.defaults;import Java.sql.connection;import Java.sql.sqlexception;import Org.apache.ibatis.exceptions.exceptionfactory;import Org.apache.ibatis.executor.errorcontext;import Org.apache.ibatis.executor.executor;import Org.apache.ibatis.mapping.environment;import Org.apache.ibatis.session.configuration;import Org.apache.ibatis.session.executortype;import Org.apache.ibatis.session.sqlsession;import Org.apache.ibatis.session.sqlsessionfactory;import Org.apache.ibatis.session.transactionisolationlevel;import org.apache.ibatis.session.defaults.DefaultSqlSession ; Import Org.apache.ibatis.transaction.transaction;import Org.apache.ibatis.transaction.transactionfactory;import Org.apache.ibatis.transaction.managed.managedtransactionfactory;public class Defaultsqlsessionfactory Implements sqlsessionfactory {/** * get Sqlsession method, transpose private method */public sqlsession opensession () {return Opensessionfromdatasource (Configuration.getdefaultexecutortype (), null, FALSE);} /** *In fact, when Opensession did not get connection, nor did it open the transaction (set Autocommit to False) * Just initialize the database operation must be object (and MyBatis schema related) * 1. The transaction object was initialized according to the configuration file, but transaction * 2 was not turned on. Based on the called Opensession method, the executor is initialized, and the default is simpleexecutor executor * mybatis all transaction control (open, Commit, rollback, close) The final placement is in executor * actually, Executor is not just the final point of transaction control, actually the cache, SQL statement generation is here, he is the real "engine" */private sqlsession Opensessionfromdatasource (executortype Exectype, Transactionisolationlevel level, Boolean autocommit) {Transaction tx = null;try {FINAL Environment environment = Configuration.getenvironment ();//Get the transaction factory based on the type configured in the configuration file: Jdbctransactionfactory and managedtransactionfactory//transaction factories are simple , the main logic falls in transactions (Jdbctranasaction and Managedtransaction)//factory specification: Org.apache.ibatis.transaction.TransactionFactoryfinal Transactionfactory transactionfactory = gettransactionfactoryfromenvironment (environment);// Gets the transaction object from the transaction factory (Jdbctranasaction or managedtransaction)//Here just gets the transaction object, does not open the transaction, and does not get the connection tx = Transactionfactory.newtransaction (Environment.getdatasource (), level, autocommit);//Get the Actuator object, the transaction is injected into the actuator, All operations of subsequent transactions end up in the actuator//microscopic view, the actuator is MyBatis "Engine "final Executor Executor = Configuration.newexecutor (TX, exectype);//Return Sqlsessionfactory object return new Defaultsqlsession (configuration, executor, autocommit);} catch (Exception e) {closetransaction (TX);//May has fetched a connection so lets call//close () throw EXCEPTIONFACTORY.W Rapexception ("Error opening session. Cause: "+ E, e);} finally {errorcontext.instance (). reset ();}}}
This article mainly discusses the affairs,
then in the OpenConnection not to get the connection, but not to open the transaction, just based on the configuration file to build a transaction object, the more critical point is the constructor of the executor, the constructed transaction object is injected into the executor through the construction method, This is very important for the subsequent MyBatis transaction system.
2. One commit: Opening of a transaction
Connections and transactions are not opened and opened in OpenConnection, but are deferred to the first operation. The opening of the transaction is actually in the actuator
Package Org.apache.ibatis.session.defaults;import Java.sql.connection;import Java.sql.sqlexception;import Java.util.hashmap;import Java.util.list;import Java.util.map;import org.apache.ibatis.binding.BindingException; Import Org.apache.ibatis.exceptions.exceptionfactory;import Org.apache.ibatis.exceptions.TooManyResultsException ; Import Org.apache.ibatis.executor.batchresult;import Org.apache.ibatis.executor.errorcontext;import Org.apache.ibatis.executor.executor;import Org.apache.ibatis.executor.result.defaultmapresulthandler;import Org.apache.ibatis.executor.result.defaultresultcontext;import Org.apache.ibatis.mapping.mappedstatement;import Org.apache.ibatis.session.configuration;import Org.apache.ibatis.session.resulthandler;import Org.apache.ibatis.session.rowbounds;import Org.apache.ibatis.session.sqlsession;public class DefaultSqlSession Implements sqlsession {/** * Database operation top-level interface */public int Insert (String statement, Object parameter) {return update (statement, parameter);} /** * Eventually, allIUD operation all fall in here. * True execution of parameter mappings, SQL parsing, SQL execution has returned value mappings, or whether the executor is finally opening the transaction or the executor, so will go to the executor to continue tracing */public int update (String statement, Object parameter) {try {dirty = true; Mappedstatement ms = Configuration.getmappedstatement (statement); return executor.update (MS, Wrapcollection ( parameter));} catch (Exception e) {throw exceptionfactory.wrapexception ("Error updating database. Cause: "+ E, e);} finally {errorcontext.instance (). reset ();}}}
The following starts the tracking of transaction opening, note the number in the source code comment.
3. Rollback
4. Close
5. Security guarantee mechanism of connection in multi-threading
If it's Sqlsessionmanager, it's based on threadlocal, but it's been abandoned. Sqlsessionmanager was replaced by Defaultsqlsessionfactory and Defaultsqlsessoin, and is now a multi-threaded data security for the method stack.
Third, JDBC Transaction select
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
"MyBatis" fully interprets MyBatis JDBC transaction