天天看點

DBCP和JDBC學習總結(應用篇) DBCP和JDBC學習總結(應用篇)

DBCP和JDBC學習總結(應用篇)

DBCP是一個常用的資料庫連接配接池,JDBC是資料庫連接配接的一套API。從應用層面學習一下兩個的使用。

JDBC 連接配接示例

public class DataBaseTest {

    public static Connection getConnection() throws SQLException,ClassNotFoundException {
        /**
         * 在加載這個類的時候,會執行靜态代碼塊中的代碼,将自己注冊到DriverManager類中
         */
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://server/yourdatabase";
        String username="xxxx";
        String password = "xxxx";

        Connection conn = DriverManager.getConnection(url,username,password);
        return conn;
    }

    public static void main(String[] args) {

        try {
            Connection conn = getConnection();
            Statement sqlStatement = conn.createStatement();
            String query = "select * from sequence";
            ResultSet result = sqlStatement.executeQuery(query);

            while(result.next()) {

                Date gmtModified = result.getDate("gmt_modified");
                String name = result.getString("name");
                Integer value = result.getInt("value");

                System.out.println("gmt_modified="+gmtModified+" name="+name+" value="+value);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
           

以上是一個jdbc連接配接資料庫的一個demo。要是用jdbc連接配接mysql,首先要将mysql的驅動程式注冊到 DriverManager中,注冊這個操作通過

Class.forName("com.mysql.jdbc.Driver");

來完成的, 這行代碼是怎麼完成mysql驅動程式的注冊的呢?其實這個注冊的功能主要是驅動程式自己完成的,在通過Class.forName()顯示加載com.mysql.jdbc.Driver的時候,會執行Driver的靜态代碼塊,這個靜态代碼塊就調用了DriverManager添加驅動的方法,将自己注冊到了驅動管理器中。 com.mysql.jdbc.Driver将自己注冊到驅動管理器的源代碼如下:

static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
 }
           

以上這段代碼位于驅動程式的靜态代碼塊中,在類被Class.forName顯示加載的時候會被執行,從代碼中看以看到把自己注冊到了DriverManager中。注冊了mysql驅動之後,就可以通過DB連接配接資訊擷取到資料庫的一個Connection了。擷取Connection的這個邏輯主要是這個樣子的:

DBCP和JDBC學習總結(應用篇) DBCP和JDBC學習總結(應用篇)

應用通過DriverManager擷取Connection,DriverManager找到合适的驅動程式後,調用驅動程式來擷取一個Connection,這個Connection一般情況下都是重新new一個,主要和連接配接池技術是相對的。 DriverManager部分源碼:

for (int i = 0; i < drivers.size(); i++) {
    DriverInfo di = (DriverInfo)drivers.elementAt(i);

    // If the caller does not have permission to load the driver then 
    // skip it.
    if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
    println("    skipping: " + di);
    continue;
    }
    try {
    println("    trying " + di);
    Connection result = di.driver.connect(url, info);
    if (result != null) {
        // Success!
        println("getConnection returning " + di);
        return (result);
    }
    } catch (SQLException ex) {
    if (reason == null) {
        reason = ex;
    }
    }
}
           

以上這個邏輯就是循環的周遊資料總管清單,找到合适的驅動程式擷取連接配接。 driver.connect()這個主要的源碼如下:

public java.sql.Connection connect(String url, Properties info)
        throws SQLException {
    if (url != null) {
        if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {
            return connectLoadBalanced(url, info);
        } else if (StringUtils.startsWithIgnoreCase(url,
                REPLICATION_URL_PREFIX)) {
            return connectReplicationConnection(url, info);
        }
    }
    Properties props = null;
    if ((props = parseURL(url, info)) == null) {
        return null;
    }

    try {
        Connection newConn = new com.mysql.jdbc.Connection(host(props),
                port(props), props, database(props), url);

        return newConn;
    } catch (SQLException sqlEx) {
        // Don't wrap SQLExceptions, throw
        // them un-changed.
        throw sqlEx;
    } catch (Exception ex) {
        throw SQLError.createSQLException(Messages
                .getString("NonRegisteringDriver.17") //$NON-NLS-1$
                + ex.toString()
                + Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$
                SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
    }
}   
           

DBCP使用DEMO:

public class DbcpConnection {
private static DataSource dataSource;
private static Connection con;

public DbcpConnection() {
}

public static Connection getConnection() {
    if (dataSource == null) {
        initDataSource();
    }
    try {
        con = dataSource.getConnection();
        print();

    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return con;

}

public static void initDataSource() {
    FileInputStream is = null;
    Properties p = new Properties();
    String driverClassName = null;
    String url = null;
    String username = null;
    String password = null;
    int initialSize = 0;
    int minIdle = 0;
    int maxIdle = 0;
    int maxWait = 0;
    int maxActive = 0;
    try {
        String path = DbcpConnection.class.getClass().getResource("/")
                .getPath();
        is = new FileInputStream(path + "dbcp.properties");
        p.load(is);
        driverClassName = p.getProperty("dbcp.driverClassName");
        url = p.getProperty("dbcp.url");
        username = p.getProperty("dbcp.username");
        password = p.getProperty("dbcp.password");

        initialSize = Integer.parseInt(p.getProperty("dbcp.initialSize"));
        minIdle = Integer.parseInt(p.getProperty("dbcp.minIdle"));
        maxIdle = Integer.parseInt(p.getProperty("dbcp.maxIdle"));
        maxWait = Integer.parseInt(p.getProperty("dbcp.maxWait"));
        maxActive = Integer.parseInt(p.getProperty("dbcp.maxActive"));
    } catch (NumberFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    BasicDataSource ds = new BasicDataSource();
    ds.setUrl(url);
    ds.setDriverClassName(driverClassName);
    ds.setUsername(username);
    ds.setPassword(password);

    ds.setInitialSize(initialSize); // 初始的連接配接數;
    ds.setMaxActive(maxActive);
    ds.setMinIdle(minIdle);
    ds.setMaxIdle(maxIdle);
    ds.setMaxWait(maxWait);
    ds.setRemoveAbandoned(true);
    ds.setRemoveAbandonedTimeout(2000);
    dataSource = ds;

}

/* 用于測試連接配接狀态的方法 */
public static void print() {
    BasicDataSource ds = (BasicDataSource) dataSource;
    System.out.println(ds.getInitialSize());
    System.out.println(ds.getNumActive());
    System.out.println(ds.getNumIdle());
    System.out.println(ds.getDefaultAutoCommit());
}

public static void main(String[] args) {

    Connection con;
    try {
        con = DbcpConnection.getConnection();
        print();
        Statement stmt = con.createStatement();
        ResultSet result = stmt.executeQuery("select * from sequence");
        while (result.next()) {
            Date gmtModified = result.getDate("gmt_modified");
            String name = result.getString("name");
            Integer value = result.getInt("value");

            System.out.println("gmt_modified="+gmtModified+" name="+name+" value="+value);
        }
    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}   }
           

這段代碼主要使用了DBCP連接配接池連接配接資料庫的一個DEMO,前面一堆就是設定了資料庫連接配接池的一些參數,這些參數是從一個props檔案中讀取的。通過javax.sql.DataSource可以擷取資料的連接配接。 javax.sql.DataSource定義了DataSource的一套接口。javax中DataSource的概念可以這麼解釋: DataSource作為DriverManager的替代項,從其定義的接口中可以擷取實體資料源的連接配接,是擷取資料源連接配接的一個首選方法。DataSource接口的對象通常在基于JNDI API的命名服務中注冊。 DataSource接口的驅動實作由各供應商提供,共有三種類型的實作: (1)基本實作:生成标準的Connection對象(就是每次new個Connection出來) (2)連接配接池實作:生成自動參與連接配接池的Connection對象。此實作與中間層連接配接池管理器一起使用 (3)分布式事務實作:生成一個Connection對象,該對象可用于分布式事務,大多數情況下總是參與連接配接池。此實作與中間層事務管理器一起使用,大多數情況下總是與連接配接池管理器一起使用。 common-dbcp是common-pool在資料庫通路方面的一個具體應用,即dbcp是依賴common-tool的。

tomcat資料源配置DEMO

在tomcat中配置資料源也是非常友善的,tomcat中内置了dbcp連接配接池。可以在context.xml中配置datasource的基礎資訊,然後再代碼中通過jndi方式擷取連接配接。具體的執行個體如下: 在 %CATALINA_HOME%/conf/context.xml中 添加如下這段代碼:

<Resource 
        name="jdbc/testdbcp"
        auth="Container"
        type="javax.sql.DataSource"
        maxActive="20"
        maxIdel="10"
        maxWait="1000"
        username="xxxx"
        password="xxxx"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://dbserver/yourdatabase">
    </Resource>
           

主要填寫一下資料庫連接配接的基礎資訊。然後在java代碼中調用示例如下:

public void exeSql(String sql) {
    try {
        Context context = new InitialContext();
        /**
         * java:/comp/env/ 是固定寫法,後面接的是context.xml中的Resource中name屬性的值
         */
        DataSource ds = (DataSource)context.lookup("java:/comp/env/jdbc/testdbcp");
        Connection conn = ds.getConnection();
        Statement stmt = conn.createStatement();
        ResultSet result = stmt.executeQuery(sql);

        while(result.next()) {

            Date gmtModified = result.getDate("gmt_modified");
            String name = result.getString("name");
            Integer value = result.getInt("value");

            System.out.println("gmt_modified="+gmtModified+" name="+name+" value="+value);
        }
    } catch (NamingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
           

通過JNDI的方式擷取到DataSource,然後就可以輕松的擷取DB連接配接執行sql了,整個過程沒有看到涉及到DBCP的東西,因為DBCP的東西完全内置在tomcat中了,在初始化JNDI上下文的時候,會根據Context.xml檔案中配置的datasource資訊來裝配具體的Datasource資訊來完成對外服務。

對于tomcat對context.xml中資料源的解析可以參考這篇部落格: http://blog.csdn.net/lantian0802/article/details/9099977 這裡就不在多說了! 這篇文章主要從應用層面簡單的總結下DataSource,下篇将從源碼角度分析下DBCP連接配接池,以及tomcat的加載流程。 我的部落格:http://blog.csdn.net/lantian0802

繼續閱讀