How does the connection pool do liveness detection (BeeCP)

Some time ago, a netizen sent a message asking: Why is there no liveness detection in your connection pool? In fact, the little bee connection pool not only has it, but also has a superior skill. Our detection method is to perform liveness detection as soon as the connection is obtained. If the detection is invalid, it will actively remove the connection from the pool, and Try to obtain the next connection, and then check until a valid connection or timeout exits; the first check ensures the performance advantage of the pool to a certain extent [such as the practice of a certain international famous pool: obtain a connection from the queue After exiting the borrow method, the detection result finds that the connection is invalid, and it will enter the borrow method again. I believe that some friends with certain skills can compare and see which is better (I hope my code not only reflects excellent performance, but also more important It is necessary to show rigor and elegance)] The idea of ​​the little bee pool is very refined, and the code method is not tortuous: unless I time out, I must get a valid connection. The topic is a bit far off, let's go back to our central topic.

1: Connection survivability detection method

Friends who are familiar with connection pools know that connection pools generally have connection survivability detection methods. The common methods are:

A: Connection.IsValid method (after JDK1.6)

B:  Use Statement to execute a SQL statement (before Java 1.5)

The general connection pool supports the above two methods. If the driver does not support the first method, the connection pool will execute a certain SQL statement according to the second method: at intervals of a certain period of time. If there is no abnormality, it will be determined as a valid connection. Therefore, it is very necessary to provide a test script for the connection pool (a bottom-guarantee method). The test code is roughly as follows:

public boolean isAlive(Connection con,String sql){
   Statement st=null;
   try{
       st =con.createStatement();
       st.execute(sql);
       return true;
    }catch(Exception e){
      return false;
    }finally{
      if(st!=null)try{st.close();}catch(Exception e){}
    }
}

Two: SQL and transaction rollback

Friends who have seen the above code may have the following questions

A: What kind of statement should I use for this SQL?

Answer: Usually a simple query statement, some pool default statement: SELECT 1 or SELECT 1 FROM DUAL

B: Can this statement be an insert statement or an update statement?

 Answer: Of course, some pools do not limit how this statement should be written.

C: If it is an insert statement, after the connection pool runs for a long time, this SQL will definitely be executed repeatedly, so a certain table will not expand greatly?

 Answer: Yes, if you don't add some controls, running a table for a long time may cause bloat, which is a good question.

For problem C, my personal opinion is to add transaction control to avoid 'real' (actual changes), then the above code needs to be adjusted to:

public boolean isAlive(Connection con,String sql){
   Statement st=null;
   boolean changed=false;

   try{
       if(con.getAutoCommit()){
          con.setAutoCommit(false);
          changed=true;
       }

       st =con.createStatement();
       st.execute(sql);
       return true;
    }catch(Exception e){
      return false;
    }finally{
      con.rollback();//回滚操作,必须放在finally中
      if(st!=null)try{st.close();}catch(Exception e){}
      if(changed) con.setAutoCommit(true);
    }
}

Friends who have read the above code may ask: Why should rollback be written in finally, is it not good to follow the execute method directly?

My answer : failure does not necessarily mean that data is not written, finally is the best place, let's imagine if the user configures the following SQL:

select xxx() from dual

Friends who are familiar with Oracle are no strangers to this way of writing. Use a SQL statement to execute a stored procedure. On this basis, we move the problem forward: if 100 insert statements are executed in this process, when the execution is completed After 99 entries, the last insert fails or all of them succeed. Dear friends, please tell me, do I need to roll back in this case? The answer is yes, unless you want to spice up Curry.

Three: Transaction switching problem ( additional points )

All friends of setAutoCommit know that this is a method used for transactions, but you know: Can't this method be switched arbitrarily? What are the consequences of switching at will? 83 lines of my code ( https://github.com/Chris2018998/BeeCP/blob/master/src/main/java/cn/beecp/pool/ProxyConnectionBase.java ): There is a dirty flag check in setAutoCommit method Unusual, you may be wondering why this is done? My answer is: the rigor of data protection, in this case either rollback or commit or no change is allowed. Let's do a test, please see the following step diagram (Oracle11g)

Step 1: View the records of a certain table of data (empty table)

Step 2: Write test code (AutoComit switches from false to true, without rolling back in the middle)

Step 3: View the table results (the results after the switch are saved into the library)

(This test mainly reminds everyone that the stolen operation on the connection, if you are not careful, will be saved in the library when the subsequent commit or close)

 

Finally, I wish friends in the community a happy May Day! And recommend two open source works 

1 (connection pool): https://github.com/Chris2018998/BeeCP

2 (object pool): https://github.com/Chris2018998/BeeOP

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324124985&siteId=291194637