zoukankan      html  css  js  c++  java
  • 数据源管理 | 基于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模式读写分离
  • 相关阅读:
    使用 Facebook开源动画库 POP 实现真实衰减动画
    在命名空间下定义类型
    作为程序猿我给csdn博客加入打赏功能
    linux高可用集群heartbeat实现http的高可用
    杭电 HDU 1247 ACMHat’s Words(trie树 或着STL)
    取石子(一)-博弈数论
    区块链技术开发怎么结合已有产业链落地?
    KafkaConsumer assign VS subscribe
    KafkaConsumer assign VS subscribe
    KafkaConsumer assign VS subscribe
  • 原文地址:https://www.cnblogs.com/cicada-smile/p/12656529.html
Copyright © 2011-2022 走看看