本文源碼:GitHub·點這裡 || GitEE·點這裡
一、關系型資料源
1、動态資料源
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5YDO0YDO0AjNx0yMwkTMyYDMyIzNwQDMwIDMy0yNxcTM5YTMvwFNwAjMwIzLcdTM3ETO2EzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
動态管理資料源的基本功能:資料源加載,容器維護,持久化管理。
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模式讀寫分離 |