插件自定义数据源

概述

Halo 本身数据库设计是基于单表进行设计,在对接其他系统通常情况下采用的是API进行交互,会导致其他系统负载过大。有些时候通常直接对接数据源会比较便捷也可以降低对接系统的负载。

背景

Halo 系统本身是通过 R2DBC 数据库驱动进行链接。目前也支持了 H2、MySQL、PostgreSQL、MariaDB、SQLServer 等关系型数据库驱动链接。那我们可以直接在插件中通过 R2DBC 进行自定义数据源链接。

定义连接池

数据库配置

@Data
public class DataBaseSetting {
    private String url;//数据库URL
    private String username;//用户名
    private String password;//密码
}
  • url: 数据库 URL,通过情况下格式为r2dbc:pool:mysql://localhost:3306/test?ssl=false

  • username: 数据库用户名

  • password: 数据库密码

数据库连接

@Slf4j
public class DataSourceFactory {

    private static ConnectionPool connectionPool;


    public static ConnectionPool getDataSource(DataBaseSetting setting) {
        if (connectionPool != null) {
            return connectionPool;
        }
        //如果没有查到就初始化
        init(setting);
        //返回datasource
        return connectionPool;
    }

    /**
     * 初始化
     *
     * @param setting
     */
    public static void init(DataBaseSetting setting) {
        log.info("*********************Initializing DataSource*********************");
        //先销毁..
        closeDataSource();
        //创建池
        var url = setting.getUrl();
        ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions
            .builder()
            .from(ConnectionFactoryOptions.parse(url))
            .option(ConnectionFactoryOptions.USER, setting.getUsername())
            .option(ConnectionFactoryOptions.PASSWORD, setting.getPassword())
            .build());
        var isConnect = verifyConnect(connectionFactory);
        //校验通过后才进来
        if (isConnect) {
            ConnectionPoolConfiguration configuration =
                ConnectionPoolConfiguration.builder(connectionFactory)
                    .maxIdleTime(Duration.ofMillis(1000))
                    .maxSize(20)
                    .build();
            connectionPool = new ConnectionPool(configuration);
        }
    }

    //验证连接是否有效
    static boolean verifyConnect(ConnectionFactory connectionFactory) {
        return Mono.from(connectionFactory.create())
            .flatMap(connection -> Mono.from(connection.close()).then(Mono.just(true)))
            .onErrorResume(e -> Mono.just(false))
            .block(Duration.ofMillis(1000));
    }

    // 销毁数据源
    private static void closeDataSource() {
        if (connectionPool != null) {
            connectionPool.dispose();
        }
    }
}

具体业务

// 以MySQL 5.7版本为例 根据用户 ID 查询用户信息
//根据ID查询用户信息
    public static void getUserInfo(String id) {
        DataBaseSetting setting = new DataBaseSetting();
        setting.setUrl("r2dbc:pool:mysql://localhost:3306/test?ssl=false");
        setting.setUsername("root");
        setting.setPassword("*****");
        String sql = "select * from user where id=?";
        ConnectionPool pool = DataSourceFactory.getDataSource(setting);
        if (pool != null) {
            var user = pool.create().flatMap(connection -> {
                return Mono.from(connection.createStatement(sql)
                        .bind(0, id)
                        .execute())
                    .flatMap(
                        result -> Mono.from(result.map((row, rowMedata) -> {
                            var uid = row.get(0, String.class);
                            var name = row.get(1, String.class);
                            return User.builder().id(uid).name(name).build();
                        })))
                    .doFinally(signalType -> Mono.from(connection.close()).subscribe());
            }).block(Duration.ofSeconds(1));
            log.info("用户信息:{}", user);
        }
    }

    //用户实体
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        String id;
        String name;
    }