MyBatis in-depth access to the database connection

Source: Internet
Author: User
Tags connection pooling

MyBatis in-depth access to database connections

The main record mybatis when to get a database connection and get a database connection. The challenge is to understand the process of obtaining a database connection using the MyBatis database connection pool.

When to get a database connection

MyBatis only gets the database connection when the SQL operation is actually performed. As for how to verify:

Not in-depth source

Simply put, it is intentional to write the database configuration information, in one SQL execution process to see which step to throw the database connection exception.

 public   Static  void  main  (string[] args) throws        Exception {String Mybatisconfigpath =  "Config/mybatis/mybatis.xml" ;        InputStream InputStream = Resources.getresourceasstream (Mybatisconfigpath);        Sqlsessionfactory = new  sqlsessionfactorybuilder (). Build (InputStream);        Sqlsession sqlsession = Sqlsessionfactory.opensession (); int  count = (Integer) sqlsession.selectone ( "        Org.alien.mybatis.samples.mapper.AuthorMapper.getAllAuthorsCount "); System.    out . println (count); }
    • Above is a section of MyBatis execution code
    • We can write the information about the MyBatis connection database intentionally wrong
    • Debug mode step by step debugging to see which step will throw an exception
    • The next step in throwing an exception is to actually get a database connection.

Exception information:

Deep source

Here is a simple mention, the specific later there will be. The most confusing thing is that when you openSession() get a database connection, you don't:
Opensession () Eventually simply returns a session in the operations database, does not include a database connection, defaultsqlsession (this is a sqlsession returned when MyBatis was initialized):

  PrivateSqlsessionOpensessionfromdatasource(Executortype Exectype, transactionisolationlevel level,Booleanautocommit) {Transaction tx =NULL;Try{FinalEnvironment environment = configuration.getenvironment ();FinalTransactionfactory transactionfactory = gettransactionfactoryfromenvironment (Environment); tx = Transactionfactory.newtransaction (Environment.getdatasource (), level, autocommit);FinalExecutor Executor = Configuration.newexecutor (TX, exectype);return NewDefaultsqlsession (configuration, executor, autocommit); }Catch(Exception e) {closetransaction (TX);//May has fetched a connection so lets call Close ()      ThrowExceptionfactory.wrapexception ("Error opening session. Cause: "+ E, E); }finally{errorcontext.instance (). reset (); }  }
    • The excutor of executing SQL in the main assembly defaultsqlsession, followed by a full execution of SQL, will have a detailed analysis of it

It is clear that the operation to actually get the database connection is in sqlSession.selectOne("org.alien.mybatis.samples.mapper.AuthorMapper.getAllAuthorsCount"); progress.

Get database connection

Before you actually get the database connection code, there are many code for SQL execution, a temporary omission here or some necessary instructions, and the main focus on how to get a database connection.
The book is answered, starting with the SQL code in front:

intcount = (Integer)sqlSession.selectOne("org.alien.mybatis.samples.mapper.AuthorMapper.getAllAuthorsCount");

Is the above code a series of method call procedures:

After a series of calls to simpleexecutor--, Doquery ():

   Public<E> list<e>Doquery(mappedstatement MS, Object parameter, rowbounds rowbounds, Resulthandler Resulthandler, Boundsql boundsql)throwsSQLException {Statement stmt =NULL;Try{Configuration configuration = Ms.getconfiguration ();//routingstatementhandlerStatementhandler handler = Configuration.newstatementhandler (wrapper, MS, parameter, Rowbounds, Resulthandler, BOUNDSQL);//mappedstatement, this sentence is the keystmt = Preparestatement (Handler, Ms.getstatementlog ());/* * Parameter: * Stmt:preparedstatementlogger * resulthandler:null * *      returnHandler.<e>query (stmt, Resulthandler); }finally{closestatement (stmt); }  }
    • After a series of jumps above the various instances of the reference I added comments, interested can follow up, and sometimes may have to follow a few more times
    • The key code stmt=prepareStatement(handler,ms.getStatementLog()); , this sentence can guess according to the method name, is based on connection to obtain the execution of SQL Preparestatement
    • But so far we have not seen the parameters of the method in the database connection, in this method

simpleexecutor--"Preparestatement ();

  privateprepareStatementthrows SQLException {    Statement stmt;    //获取数据库连接。statementLog:org.apache.ibatis.loggin.slf4j.Slf4Impl    Connection connection = getConnection(statementLog);    //获取执行Sql的Statement——PrepareStatementLogger    //PrepareStatementLogger是PrepareStatement的代理、多了对使用Mybatis执行sql语句时记录sql语句的功能    stmt = handler.prepare(connection);    //将执行Sql需要的参数设置到PrepareStatement中。    handler.parameterize(stmt);    return stmt;  }

Others don't care, just look at the database connection code: Connection connection = getConnection(statementLog); baseexecutor--"getconnection ():

  protectedgetConnectionthrows SQLException {    //如果关于数据库连接的日志记录级别是DEBUG级别、则为获取的Connection进行代理、新增日志记录功能、这里不是重点。    if (statementLog.isDebugEnabled()) {      return ConnectionLogger.newInstance(connection, statementLog, queryStack);    else {      return connection;    }  }
    • The value of the transaction configuration item in MyBatis is "JDBC", so the MyBatis in-depth transaction management know the transaction here is actually: jdbctransaction
    • Finally to jdbctransaction get the connection in the method

jdbctransaction--"OpenConnection ()

  protectedvoidopenConnectionthrows SQLException {    if (log.isDebugEnabled()) {      log.debug("Opening JDBC Connection");    }    connection = dataSource.getConnection();    ifnull) {      connection.setTransactionIsolation(level.getLevel());    }    setDesiredAutoCommit(autoCommmit);  }
    • The above datasource from MyBatis in-depth datasource instantiation process know that when using the database connection pool is instantiated Pooleddatasource

pooleddatasource--"getconnection ():

  publicgetConnectionthrows SQLException {/* * 为理解方便、将原来代码拆分如下: */    PooledConnection pooledConnection = popConnection(dataSource.getUsername(), dataSource.getPassword());    Connection connection = pooledConnection.getProxyConnection();    return connection ;//return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();  }
    • Split the code to see two steps
      • Get Database Real Connection
      • Gets the proxy class for the true database connection as the final return result, as to what the agent is doing, and then continuing

pooleddatasource--"Popconnection ():

Private pooledconnection popconnection (string Username, string password) throws SQLException {Boolean countedwait = FA Lse;Pooledconnection conn = null;Long T = System. Currenttimemillis();int localbadconnectioncount =0;while (conn = = null) {synchronized (state) {if (state. Idleconnections. Size() >0) {//Pool have available connection conn = State. Idleconnections. Remove(0);if (log. isdebugenabled()) {log. Debug("Checked out Connection"+ Conn. Getrealhashcode() +"from pool.");}} else {//Pool does not has available connection if (state. Activeconnections. Size() < Poolmaximumactiveconnections) {//Can Create new Connection conn = new pooledconnection (dat Asource. getconnection(), this);@SuppressWarnings ("Unused")//usedinchLogging, if enabled Connection REALCONN = conn. Getrealconnection();if (log. isdebugenabled()) {log. Debug("Created Connection"+ Conn. Getrealhashcode() +".");}} else {//Cannot create new connection pooledconnection oldestactiveconnection = State. Activeconnections. Get(0);Long Longestcheckouttime = Oldestactiveconnection. Getcheckouttime();if (Longestcheckouttime > Poolmaximumcheckouttime) {//Can claim overdue connection state. Claimedoverdueconnectioncount++;State. Accumulatedcheckouttimeofoverdueconnections+ = Longestcheckouttime;State. Accumulatedcheckouttime+ = Longestcheckouttime;State. Activeconnections. Remove(oldestactiveconnection);if (!oldestactiveconnection. Getrealconnection(). Getautocommit()) {oldestactiveconnection. Getrealconnection(). Rollback();} conn = new Pooledconnection (oldestactiveconnection. Getrealconnection(), this);Oldestactiveconnection. Invalidate();if (log. isdebugenabled()) {log. Debug("claimed overdue connection"+ Conn. Getrealhashcode() +".");}} else {//must wait-try {if (!countedwait) {STA Te. Hadtowaitcount++;Countedwait = True;} if (log. isdebugenabled()) {log. Debug("Waiting as Long"+ pooltimetowait +"milliseconds for connection.");} Long WT = System. Currenttimemillis();State. Wait(pooltimetowait);State. Accumulatedwaittime+ = System. Currenttimemillis()-WT;} catch (Interruptedexception e) { Break;}}}} if (conn! = null) {if (conn. IsValid()) {if (!conn. Getrealconnection(). Getautocommit()) {conn. Getrealconnection(). Rollback();} conn. Setconnectiontypecode(Assembleconnectiontypecode (DataSource. GetUrl(), username, password));Conn. Setcheckouttimestamp(System. Currenttimemillis());Conn. Setlastusedtimestamp(System. Currenttimemillis());State. Activeconnections. Add(conn);State. RequestCount++;State. Accumulatedrequesttime+ = System. Currenttimemillis()-T;} else {if (log. isdebugenabled()) {log. Debug("A Bad Connection ("+ Conn. Getrealhashcode() +"is returned from the pool, getting another connection.");} state. Badconnectioncount++;localbadconnectioncount++;conn = null;if (Localbadconnectioncount > (poolmaximumidleconnections +3) {if (log. isdebugenabled()) {log. Debug("Pooleddatasource:could not get a good connection to the database.");} Throw new SQLException ("Pooleddatasource:could not get a good connection to the database.");}}}}} if (conn = = null) {if (log. isdebugenabled()) {log. Debug("Pooleddatasource:unknown Severe error condition. The connection pool returned a null connection. ");} Throw new SQLException ("Pooleddatasource:unknown Severe error condition. The connection pool returned a null connection. ");} return Conn;}
    • First explain the logic, and then focus on the specific database connection method
1.  先看是否有空闲(idle)状态下的PooledConnection对象,如果有,就直接返回一个可用的PooledConnection对象;否则进行第2步。2.  查看活动状态的PooledConnection池activeConnections是否已满;如果没有满,则创建一个新的PooledConnection对象,然后放到activeConnections池中,然后返回此PooledConnection对象;否则进行第三步;3.  看最先进入activeConnections池中的PooledConnection对象是否已经过期:如果已经过期,从activeConnections池中移除此对象,然后创建一个新的PooledConnection对象,添加到activeConnections中,然后将此对象返回;否则进行第4步。4.  线程等待,循环2步

To create the database connection code specificallyconn = new PooledConnection(dataSource.getConnection(), this);

    • The DataSource in the above code is Unpooleddatasource, and you can understand the reason from the MyBatis in-depth datasource instantiation process.

So first to see Unpooleddatasource--getconnection () after a series of jumps to the same method as follows:

  privatedoGetConnectionthrows SQLException {    initializeDriver();    Connection connection = DriverManager.getConnection(url, properties);    configureConnection(connection);    return connection;  }
    • Above we can see the familiar load driver, get database connection
Add

In fact, there are many things to write about the database, such as how the database connection pool works, when the database connection is closed. It's not ready to put all the east together. It's easier to say how to separate points than to understand them.
There will be a MyBatis database connection pooling principle to analyze it later.

More Content MyBatis Catalogue

MyBatis in-depth access to the database connection

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.