­

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

本文源碼:GitHub·點這裡 || GitEE·點這裡

一、關係型數據源

1、動態數據源

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

2、關係型資料庫

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

3、適配要素

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

關係型資料庫很多,這裡一定是不全的,根據需要自行完善即可。

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 ;      }  }  

4、JDBC基礎API

DriverManager

管理JDBC驅動程式的基本服務API。調用方法Class.forName,顯式地載入驅動程式類,正好適用於動態數據源的業務場景,數據源類型未知情況。載入Driver類並在DriverManager類註冊後,即可用來與資料庫建立連接。

DataSource

DataSource介面,由驅動程式供應商實現,負責建立與資料庫的連接,當在應用程式中訪問資料庫時,常用於獲取操作數據的Connection對象。

Connection

Connection介面代表與特定的資料庫的連接,要對資料庫數據進行操作,首先要獲取資料庫連接,Connection實現就像在應用程式中與資料庫之間開通了一條通道,通過DriverManager類或DataSource類都可獲取Connection實例。

二、鏈接和管理

這裡幾個核心類的封裝思路:模組化功能,API分開封裝,如果需要適配處理各類數據源類型,則分別可以向上抽象提取,向下自定義適配策略,設計模式影響下的基本意識。

1、鏈接工具

基於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 ;      }    }  

2、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()) ;      }    }  

3、數據源容器

維護一個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) ;      }  }  

4、流程測試

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

@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 ;      }  }  

三、批量管理

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

1、庫表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>  

2、持久化管理

測試數據源鏈接是否成功,可用的數據源鏈接,配置資訊入庫保存。

@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 ;      }  }  

3、動態載入

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

@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) ;                  }              }          }      }  }  

四、源程式碼地址

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

推薦閱讀:數據管理

序號 標題
01 數據源管理:主從庫動態路由,AOP模式讀寫分離