java通過代理創建Conncection對象與自定義JDBC連接池


最近學習了一下代理發現,代理其實一個蠻有用的,主要是用在動態的實現接口中的某一個方法而不去繼承這個接口所用的一種技巧,首先是自定義的一個連接池

代碼如下

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; /** * 自定義連接池, 管理連接 * 代碼實現: 1. MyPool.java 連接池類, 2. 指定全局參數: 初始化數目、最大連接數、當前連接、 連接池集合 3. 構造函數:循環創建3個連接 4. 寫一個創建連接的方法 5. 獲取連接 ------> 判斷: 池中有連接, 直接拿 ------> 池中沒有連接, ------> 判斷,是否達到最大連接數; 達到,拋出異常;沒有達到最大連接數, 創建新的連接 6. 釋放連接 -------> 連接放回集合中(..) * */ public class TestMyPool { private int init_count = 3; // 初始化連接數目 private int max_count = 6; // 最大連接數 private int current_count = 0; // 記錄當前使用連接數 // 連接池 (存放所有的初始化連接) private LinkedList<Connection> pool = new LinkedList<Connection>(); //1. 構造函數中,初始化連接放入連接池 public TestMyPool() { // 初始化連接 for (int i=0; i<init_count; i++){ // 記錄當前連接數目 current_count++; // 創建原始的連接對象 Connection con = createConnection(); // 把連接加入連接池 pool.addLast(con); } } //2. 創建一個新的連接的方法 private Connection createConnection(){ try { Class.forName("com.mysql.jdbc.Driver"); // 原始的目標對象 final Connection con = DriverManager.getConnection("jdbc:mysql:///jdbc_demo", "root", "root"); /**********對con對象代理**************/ // 對con創建其代理對象 Connection proxy = (Connection) Proxy.newProxyInstance( con.getClass().getClassLoader(), // 類加載器 //con.getClass().getInterfaces(), // 當目標對象是一個具體的類的時候 new Class[]{Connection.class}, // 目標對象實現的接口 new InvocationHandler() { // 當調用con對象方法的時候, 自動觸發事務處理器 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法返回值 Object result = null; // 當前執行的方法的方法名 String methodName = method.getName(); // 判斷當執行了close方法的時候,把連接放入連接池 if ("close".equals(methodName)) { System.out.println("begin:當前執行close方法開始!"); // 連接放入連接池 (判斷..) pool.addLast(con); System.out.println("end: 當前連接已經放入連接池了!"); } else { // 調用目標對象方法 result = method.invoke(con, args); } return result; } } ); return proxy; } catch (Exception e) { throw new RuntimeException(e); } } //3. 獲取連接 public Connection getConnection(){ // 3.1 判斷連接池中是否有連接, 如果有連接,就直接從連接池取出 if (pool.size() > 0){ return pool.removeFirst(); } // 3.2 連接池中沒有連接: 判斷,如果沒有達到最大連接數,創建; if (current_count < max_count) { // 記錄當前使用的連接數 current_count++; // 創建連接 return createConnection(); } // 3.3 如果當前已經達到最大連接數,拋出異常 throw new RuntimeException("當前連接已經達到最大連接數目 !"); } //4. 釋放連接 public void realeaseConnection(Connection con) { // 4.1 判斷: 池的數目如果小於初始化連接,就放入池中 if (pool.size() < init_count){ pool.addLast(con); } else { try { // 4.2 關閉 current_count--; con.close(); } catch (SQLException e) { throw new RuntimeException(e); } } } public static void main(String[] args) throws SQLException { TestMyPool pool = new TestMyPool(); System.out.println("當前連接: " + pool.current_count); // 3 // 使用連接 pool.getConnection(); pool.getConnection(); Connection con4 = pool.getConnection(); Connection con3 = pool.getConnection(); Connection con2 = pool.getConnection(); Connection con1 = pool.getConnection(); // 釋放連接, 連接放回連接池 // pool.realeaseConnection(con1); /* * 希望:當關閉連接的時候,要把連接放入連接池!【當調用Connection接口的close方法時候,希望觸發pool.addLast(con);操作】 * 把連接放入連接池 * 解決1:實現Connection接口,重寫close方法 * 解決2:動態代理 */ con1.close(); // 再獲取 pool.getConnection(); System.out.println("連接池:" + pool.pool.size()); // 0 System.out.println("當前連接: " + pool.current_count); // 3 } }

在這里使用代理主要是為了監測Connection 中的close()方法,當然也可以檢測Connection中的其他方法,順便值得一提的是還有Jdbc的兩個開源連接數據庫的框架可以為連接數據庫省去一些代碼:例如dbcp和c3p0這兩個框架實現代碼分別如下,但前提必須將對應的jar包導入

 

import java.io.InputStream;
import java.sql.Connection; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.junit.Test; public class App_Dbcp { public App_Dbcp() { // TODO Auto-generated constructor stub  } /** * 硬編碼方式 */ @Test public void testDbcp() { //DBCP中的核心類 BasicDataSource dataSource = new BasicDataSource(); //連接池配置參數,初始化連接參數,最大連接參數,連接的驅動名  dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); dataSource.setUrl("jdbc:sqlserver://localhost:1433;DatabaseName=教學庫"); dataSource.setUsername("sa"); dataSource.setPassword("****"); dataSource.setInitialSize(3);//設置初始化連接參數 dataSource.setMaxActive(6);//設置最大連接數 dataSource.setMaxIdle(3000);//設置最大空閑時間 //獲取連接 try { Connection con = dataSource.getConnection(); con.prepareStatement("delete from tb_user where id=3").executeUpdate(); //關閉  con.close(); } catch (Exception e) { // TODO Auto-generated catch block  e.printStackTrace(); throw new RuntimeException(e); } } @Test public void testDBCP() { /** * 使用配置方式來獲取參數 */ try { Properties props = new Properties(); InputStream in = App_Dbcp.class.getResourceAsStream("/db.properties"); //讀取流文件  props.load(in); //根據Props配置文件直接產生數據對象  DataSource dataSource = BasicDataSourceFactory.createDataSource(props); //創建連接對象 Connection con = dataSource.getConnection(); con.prepareStatement("delete from tb_user where id=4").executeUpdate(); con.close(); }catch(Exception e) { throw new RuntimeException(e); } } }

 

c3p0連接池的測試代碼

package gz.itcast.b_c3p0;

import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.SQLException; import org.junit.Test; import com.mchange.v2.c3p0.ComboPooledDataSource; public class App { public App() { // TODO Auto-generated constructor stub  } //硬編碼方式,使用c3p0連接池來管理連接數目  @Test public void testCode() throws Exception { //創建c3p0核心類 ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver"); dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=教學庫"); dataSource.setUser("sa"); dataSource.setPassword("***"); dataSource.setInitialPoolSize(3); dataSource.setMaxPoolSize(6); dataSource.setMaxIdleTime(3000); Connection con = dataSource.getConnection(); con.prepareStatement("delete from tb_user where id=3").executeUpdate(); con.close(); } //c3p0使用xml配置文件來管理連接方式  @Test public void testXml() throws Exception { //c3p0核心類,在new 一個對象時就會自動的加載c3p0-config.xml文件 ComboPooledDataSource dataSource = new ComboPooledDataSource(); Connection con = dataSource.getConnection(); con.prepareStatement("delete from tb_user where id=2").executeUpdate(); //關閉連接  con.close(); } }

對應的xml配置文件

<c3p0-config>
  <default-config>
      <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
    <property name="url">jdbc:sqlserver://localhost:1433;DatabaseName=教學庫</property>
    <property name="username">sa</property>
    <property name="password">****</property>
    <property name="initialPoolSize">3</property>
    <property name="maxPoolSize">6</property>
    <property name="maxIdleTime">3000</property>
    <!--
    <user-overrides user="swaldman">
      <property name="debugUnreturnedConnectionStackTraces">true</property>
    </user-overrides>
    -->

  </default-config>

<!--
  <named-config name="dumbTestConfig">
    <property name="maxStatements">200</property>
    <property name="jdbcUrl">jdbc:test</property>
    <user-overrides user="poop">
      <property name="maxStatements">300</property>
    </user-overrides>
   </named-config>
-->

</c3p0-config>

最后就到為止了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM