數據源管理 | 基於JDBC模式,適配和管理動態數據源

本文源碼:GitHub·點這裏 || GitEE·點這裏java

1、關係型數據源

一、動態數據源

動態管理數據源的基本功能:數據源加載,容器維護,持久化管理。mysql

二、關係型數據庫

不一樣廠商的關係型數據庫,提供的連接方式,驅動包,驅動類名都是不同的,Java數據庫鏈接API,JDBC是Java語言中用來規範客戶端程序如何來訪問數據庫的應用程序接口,提供了諸如查詢和更新數據庫中數據的方法,且適配大部分關係型數據庫。git

三、適配要素

核心要素:驅動包、驅動類名、URL格式、默認端口。github

關係型數據庫不少,這裏必定是不全的,根據須要自行完善便可。sql

public enum DataSourceType {

    MySql("MySql", "com.mysql.jdbc.Driver"),
    Oracle("Oracle", "oracle.jdbc.OracleDriver"),
    DB2("DB2", "com.ibm.db2.jcc.DB2Driver");

    private String dataSourceName;
    private String driverClassName;

    public static String getDriver (String dataSourceName) {
        DataSourceType[] types = DataSourceType.values();
        for (DataSourceType type : types) {
            if (type.getDataSourceName().equals(dataSourceName)) {
                return type.getDriverClassName();
            }
        }
        return null;
    }
    DataSourceType (String dataSourceName,String driverClassName){
        this.dataSourceName = dataSourceName ;
        this.driverClassName = driverClassName ;
    }
}

四、JDBC基礎API

DriverManager數據庫

管理JDBC驅動程序的基本服務API。調用方法Class.forName,顯式地加載驅動程序類,正好適用於動態數據源的業務場景,數據源類型未知狀況。加載Driver類並在DriverManager類註冊後,便可用來與數據庫創建鏈接。設計模式

DataSourceapi

DataSource接口,由驅動程序供應商實現,負責創建與數據庫的鏈接,當在應用程序中訪問數據庫時,經常使用於獲取操做數據的Connection對象。oracle

Connectionapp

Connection接口表明與特定的數據庫的鏈接,要對數據庫數據進行操做,首先要獲取數據庫鏈接,Connection實現就像在應用程序中與數據庫之間開通了一條通道,經過DriverManager類或DataSource類均可獲取Connection實例。

2、連接和管理

這裏幾個核心類的封裝思路:模塊化功能,API分開封裝,若是須要適配處理各種數據源類型,則分別能夠向上抽象提取,向下自定義適配策略,設計模式影響下的基本意識。

一、連接工具

基於DriverManager管理數據源的驅動加載,連接獲取等。

public class ConnectionUtil {

    public static synchronized Connection getConnect(String driverClassName,String userName,
                                                  String passWord,String jdbcUrl) {
        Properties prop = new Properties();
        prop.put("user", userName);
        prop.put("password", passWord);
        return connect(driverClassName,prop,jdbcUrl) ;
    }

    private static synchronized Connection connect(String driverClassName,
                                                   Properties prop,String jdbcUrl) {
        try {
            Class.forName(driverClassName);
            DriverManager.setLoginTimeout(JdbcConstant.LOGIN_TIMEOUT);
            return DriverManager.getConnection(jdbcUrl, prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null ;
    }

}

二、API工具類

提供API配置獲取類,加載須要的數據源API,關閉資源等基本操做。

@Component
public class JdbcConfig {

    /**
     * 獲取數據源鏈接
     */
    public Connection getConnection (ConnectionEntity connectionEntity){
        String dataTypeName = connectionEntity.getDataTypeName();
        String driverClassName = DataSourceType.getDriver(dataTypeName) ;
        if (driverClassName == null){
            throw new RuntimeException("不支持該數據源類型") ;
        }
        connectionEntity.setDriverClassName(driverClassName);
        return ConnectionUtil.getConnect(connectionEntity.getDriverClassName(),
                connectionEntity.getUserName(),
                connectionEntity.getPassWord(),
                connectionEntity.getJdbcUrl()) ;
    }

}

三、數據源容器

維護一個Map容器,管理數據源的添加,刪除,動態獲取等基本需求。

@Component
public class DataSourceFactory {

    private volatile Map<Integer, DataSource> dataSourceMap = new HashMap<>();

    @Resource
    private JdbcConfig jdbcConfig ;
    @Resource
    private ConnectionMapper connectionMapper ;

    /**
     * 數據源API包裝
     */
    private static DataSource getDataSource (ConnectionEntity connectionEntity){
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(connectionEntity.getJdbcUrl());
        datasource.setUsername(connectionEntity.getUserName());
        datasource.setPassword(connectionEntity.getPassWord());
        datasource.setDriverClassName(connectionEntity.getDriverClassName());
        return datasource ;
    }

    /**
     * 獲取 JDBC 連接
     */
    public JdbcTemplate getById (Integer id){
        return new JdbcTemplate(dataSourceMap.get(id)) ;
    }

    /**
     * 移除 數據源
     */
    public void removeById (Integer id) {
        dataSourceMap.remove(id) ;
    }

    /**
     * 添加數據源管理
     * 注意這裏的方法,鏈接驗證以後直接調用
     */
    public void addDataSource (ConnectionEntity connectionEntity){
        DataSource dataSource = getDataSource(connectionEntity);
        dataSourceMap.put(connectionEntity.getId(),dataSource) ;
    }
}

四、流程測試

基於動態的數據源,查詢表數據,這裏操做的表示已知的表結構,實際上動態數據源的表結構都是須要再次動態獲取表字段,才能操做。(下節數據動態讀取和寫入會詳說)

@Api(value = "JdbcQueryController")
@RestController
public class JdbcQueryController {

    @Resource
    private DataSourceFactory dataSourceFactory ;

    @GetMapping("getList")
    public List<ConnectionEntity> getList (@RequestParam("id") Integer id){
        String sql = "SELECT * FROM jm_connection WHERE state='1'" ;
        JdbcTemplate jdbcTemplate = dataSourceFactory.getById(id);
        List<ConnectionEntity> connectionEntities = jdbcTemplate.query(sql,
                new BeanPropertyRowMapper<>(ConnectionEntity.class));
        return connectionEntities ;
    }
}

3、批量管理

持久化數據源的配置信息,多了一步配置信息入庫,和入庫信息加載到容器,使用時動態獲取。

一、庫表Mapper結構

存儲配置信息的表結構,轉換Mapper文件。

<mapper namespace="com.dynamic.add.mapper.ConnectionMapper">
    <!-- 通用查詢映射結果 -->
    <resultMap id="BaseResultMap" type="com.dynamic.add.entity.ConnectionEntity">
        <id column="id" property="id" />
        <result column="data_type_name" property="dataTypeName" />
        <result column="driver_class_name" property="driverClassName" />
        <result column="jdbc_url" property="jdbcUrl" />
        <result column="user_name" property="userName" />
        <result column="pass_word" property="passWord" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="state" property="state" />
    </resultMap>
    <select id="getAllList" resultMap="BaseResultMap" >
        SELECT * FROM jm_connection WHERE state='1'
    </select>
</mapper>

二、持久化管理

測試數據源連接是否成功,可用的數據源連接,配置信息入庫保存。

@Service
public class ConnectionServiceImpl implements ConnectionService {

    @Resource
    private ConnectionMapper connectionMapper ;
    @Resource
    private JdbcConfig jdbcConfig ;
    @Resource
    private DataSourceFactory dataSourceFactory ;

    @Override
    public boolean testConnection(ConnectionEntity connectionEntity) {
        return jdbcConfig.getConnection(connectionEntity) !=null ;
    }

    @Override
    public boolean addConnection(ConnectionEntity connectionEntity) {
        Connection connection = jdbcConfig.getConnection(connectionEntity) ;
        if (connection !=null){
            int addFlag = connectionMapper.insert(connectionEntity);
            if (addFlag > 0){
                dataSourceFactory.addDataSource(connectionEntity) ;
                return true ;
            }
        }
        return false ;
    }
}

三、動態加載

容器工廠類中,添加一個初始化的方法,加載入庫的數據源配置信息。

@Component
public class DataSourceFactory {
    /**
     * 初始化 JDBC 連接API
     */
    @PostConstruct
    public void init (){
        List<ConnectionEntity> connectionList = connectionMapper.getAllList();
        if (connectionList != null && connectionList.size()>0){
            for (ConnectionEntity connectionEntity:connectionList) {
                Connection connection = jdbcConfig.getConnection(connectionEntity) ;
                if (connection != null){
                    DataSource dataSource = getDataSource(connectionEntity);
                    dataSourceMap.put(connectionEntity.getId(),dataSource) ;
                }
            }
        }
    }
}

4、源代碼地址

GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent

推薦閱讀:數據管理

序號 標題
01 數據源管理:主從庫動態路由,AOP模式讀寫分離
相關文章
相關標籤/搜索