Java DB loadBalance 設計

 

 

Java DB loadBalance 設計

1 JDBC

簡單介紹下JDBC的定義,以下(摘自百度百科):java

JDBC(Java Data Base Connectivity,java數據庫鏈接)是一種用於執行SQL語句的Java API,能夠爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此能夠構建更高級的工具和接口,使數據庫開發人員可以編寫數據庫應用程序,同時,JDBC也是個商標名。1 平時咱們在實際開發中通常都是直接使用鏈接池來作DB相關操做的,不多會直接使用JDBC進行編程。可是鏈接池底層鏈接DB的時候也是使用的JDBC,好比c3p0。2mysql

下面經過代碼介紹下經過JDBC操做DB的過程。以下所示:sql

//1. 註冊DriverManager,DriverManager中的靜態List registeredDrivers 保存了全部的Driver引用

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

//2.拼接鏈接信息,協議/子協議/數據源標識,鏈接信息
String url = "jdbc:mysql://localhost:3306/csc?user=root&password=xxxx";

//3. DriverManager 負責從註冊的驅動中挑選合適的鏈接
Connection connection = DriverManager.getConnection(url);

//4. 創建陳述式語句 (Statement,PrepareStatement(安全性[防止sql注入]和性能),CallableStatement(存儲過程))

//4.1 Statement
Statement statement = connection.createStatement();
//execute query
ResultSet resultSet = statement.executeQuery("SELECT  * FROM test ORDER by ID limit 10");
//4.2 PrepareStatement,在一個提交中設置了多個陳述式語句。
connection.setAutoCommit(false);
PreparedStatement preparedStatementInsert = connection.prepareStatement("INSERT  into test(name,sex) VALUES (?,?)");
preparedStatementInsert.setString(1, "csophys");
preparedStatementInsert.setInt(2, 0);
preparedStatementInsert.execute();
Statement getLastIdStatement = connection.createStatement();
ResultSet set = getLastIdStatement.executeQuery("SELECT LAST_INSERT_ID()");
connection.commit();

//4.3 statement 的batch的功能以及CallableStatement平時用的很少

//5. 處理返回結果ResultSet
while (resultSet.next()) {
    System.out.println(resultSet.getString(2));
    System.out.println(resultSet.getString("id"));
}
while(set.next()){
    System.out.println(set.getString(1));
    System.out.println(set.getString("LAST_INSERT_ID()"));
}

經過上面的代碼,比較清楚的可以看到經過JDBC進行DB操做的幾個步驟。以下圖所示:數據庫

jdbc.jpg

其中 創建陳述式語句 Statement時能夠有三類,,Statement,PrepareStatement,CallableStatement。CallableStatement通常用於存儲過程, 而Statement和PrepareStatement通常用PrepareStatement比較多,PrepareStatement 能夠預編譯SQL預計,而後經過sql參數傳遞執行sql語句, 而Statement執行的時候是完整的執行一個sql,不會預編譯,因此須要屢次執行一個sql的時候。PrepareStatement比Statement的效果要好,並且PrepareStatement還能夠預防SQL注入。3編程

2 DATASOURCE

Datasource 的功能和DriverManager 比較相似,都是向外輸出Connection,只是DataSource通常不直接和DB交互,而是會從鏈接池中獲取DB鏈接
安全

不要混淆DataSource,DriverManager還有鏈接池的概念。個人理解是,DriverManager封裝了各個DB廠商數據庫驅動的差別,能直接和DB操做而且向
外提供數據庫鏈接。而鏈接池保存了多個DB鏈接,減小新建DB鏈接所須要的時間開銷。Datasource是更高層次的封裝,向外提供Connection,底層通常會
使用鏈接池技術。 bash

好比採用Spring和Mybatis進行集成開發的時候,會須要配置一個DataSource。通常從採用比較有名的c3p0等。以下: 架構

<!--c3p0數據源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/csc" />
    <property name="user" value="root" />
    <property name="password" value="xxxx" />
</bean>

爲了強化記憶,咱們能夠本身來實現一個簡單的DataSource,來給Mybatis使用。以下:ide

<!--MyDatasource-->
<bean id="myDataSource" class="base.jdbc.MyDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/csc" />
    <property name="user" value="root" />
    <property name="password" value="xxxx" />
</bean>

MyDataSource中來接收DB的鏈接信息,而且直接經過DriverManager來獲取DB鏈接。MyDataSource只要集成javax.sql.DataSource,
而且實現裏面的getConnection方法就能夠了。以下所示: 工具

public class MyDataSource implements DataSource {
    private String driverClass;
    private String jdbcUrl;
    private String user;
    private String password;


    public Connection getConnection() throws SQLException {
        try {
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return DriverManager.getConnection(jdbcUrl+"?user="+user+"&password="+password);
    }
....

而後用本身的DataSource替換c3p0後用單元測試能夠正常工做。

3 讀寫分離及分庫分表設計

首先讀寫分離確定會有多個數據源,因此須要先獲取到主從庫的配置信息好比,w,r1,r2.w爲主庫,r1,r2爲從庫,而且創建了3個數據源wds,rds1,rds2。 爲了方便DBA修改,主從庫的配置信息能夠配置在遠程,而後程序動態獲取。

接下來能夠對於多個數據源作一個封裝,根據SQL類型、事務是否自動提交來決定具體走哪個數據源。封裝的類圖以下所示(取名參考大衆點評的架構組件zebra):

loadBalance.jpg

GroupPrepareStatement執行的時候,會根據SQL的類型以及配置類型會選擇GroupConnection中的Datasource引用,而後獲取真實的connection後進行數據庫操做。

而後分庫分表設計的原理也和上面相似,只是主庫通常會有多個,會根據某個維度進行水平切分。執行的時候須要根據sql中的維度的值來肯定具體須要選擇的DataSource。

Footnotes:

2
com.mchange.v2.c3p0.DriverManagerDataSource

    private synchronized Driver driver() throws SQLException
    {
        //System.err.println( "driver() <-- " + this );
        if (driver == null)
            driver = DriverManager.getDriver( jdbcUrl );
        return driver;
    }

Author: 陳勝 csophys

Created: 2017-01-15 Sun 21:45

Validate

相關文章
相關標籤/搜索