Data source management: adapt and manage dynamic data sources based on JDBC mode

Keywords: Programming Database JDBC github MySQL

Source code: GitHub point here || GitEE point here

1, Relational data source

1. Dynamic data source

The basic functions of dynamic management data source: data source loading, container maintenance, persistent management.

2. Relational database

Different manufacturers of relational databases provide different connection methods, driver packages and driver class names. Java database connection API and JDBC are application program interfaces used in Java language to regulate how client programs access the database. They provide methods such as querying and updating data in the database, and adapt to most relational databases.

3. Adaptive elements

Core elements: driver package, driver class name, URL format, default port.

There are a lot of relational databases, which must be incomplete here. You can improve them by yourself according to your needs.

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 basic API

DriverManager

Basic service API for managing JDBC drivers. Call the method Class.forName to explicitly load the Driver class, which is just suitable for the business scenario of dynamic data source. The data source type is unknown. Once the Driver class is loaded and registered with the DriverManager class, it can be used to establish a connection with the database.

DataSource

The DataSource interface, implemented by the driver supplier, is responsible for establishing the Connection with the database. When accessing the database in the application, it is often used to obtain the Connection object of the operation data.

Connection

The Connection interface represents the Connection with a specific database. To operate on the database data, the first step is to obtain the database Connection. The Connection implementation is like opening a channel between the application and the database. The Connection instance can be obtained through the DriverManager class or DataSource class.

2, Linking and management

Here are the encapsulation ideas of several core classes: modular function, API separately encapsulation. If you need to adapt to handle various data source types, you can abstract them up, customize the adaptation strategy down, and realize the basic awareness under the influence of design mode.

1. Linking tools

Based on DriverManager to manage data source's drive loading, link obtaining, etc.

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 tool class

Provide API configuration to obtain classes, load required data source APIs, close resources and other basic operations.

@Component
public class JdbcConfig {

    /**
     * Get data source connection
     */
    public Connection getConnection (ConnectionEntity connectionEntity){
        String dataTypeName = connectionEntity.getDataTypeName();
        String driverClassName = DataSourceType.getDriver(dataTypeName) ;
        if (driverClassName == null){
            throw new RuntimeException("The data source type is not supported") ;
        }
        connectionEntity.setDriverClassName(driverClassName);
        return ConnectionUtil.getConnect(connectionEntity.getDriverClassName(),
                connectionEntity.getUserName(),
                connectionEntity.getPassWord(),
                connectionEntity.getJdbcUrl()) ;
    }

}

3. Data source container

Maintain a Map container, manage the basic requirements of data source addition, deletion, dynamic acquisition, etc.

@Component
public class DataSourceFactory {

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

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

    /**
     * Data source API wrapper
     */
    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 ;
    }

    /**
     * Get JDBC link
     */
    public JdbcTemplate getById (Integer id){
        return new JdbcTemplate(dataSourceMap.get(id)) ;
    }

    /**
     * Remove data source
     */
    public void removeById (Integer id) {
        dataSourceMap.remove(id) ;
    }

    /**
     * Add data source management
     * Note the method here, which is called directly after connection verification
     */
    public void addDataSource (ConnectionEntity connectionEntity){
        DataSource dataSource = getDataSource(connectionEntity);
        dataSourceMap.put(connectionEntity.getId(),dataSource) ;
    }
}

4. Process testing

Based on the dynamic data source, query the table data. The operation here represents the known table structure. In fact, the table structure of the dynamic data source needs to obtain the table fields dynamically again to operate. (data dynamic reading and writing in the next section will be explained in detail)

@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, Batch management

The configuration information of the persistent data source has one more step of configuration information warehousing, and the warehousing information is loaded into the container and acquired dynamically when used.

1. Mapper structure of library table

Table structure to store configuration information, and transform Mapper file.

<mapper namespace="com.dynamic.add.mapper.ConnectionMapper">
    <!-- General query mapping results -->
    <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. Persistent management

Test whether the data source link is successful, the available data source link, and the configuration information are stored in the warehouse.

@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. Dynamic loading

In the container factory class, add an initialization method to load the configuration information of the data source.

@Component
public class DataSourceFactory {
    /**
     * Initialize JDBC link 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, Source code address

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

Posted by blackhawk08 on Tue, 07 Apr 2020 08:51:15 -0700