0
点赞
收藏
分享

微信扫一扫

【电厂用 交流三相电流继电器HJL-F93/AY 导轨安装 JOSEF约瑟供应 】

一、技术选型

springboot2.4+、mybatisplus3.4+、mysql5.7+、redis3.0+

二、编写目的

如果产品开发默认数据库采用mysql,但是当客户提出数据库需要采用Sqlserver或者Oracle以及其他国产数据库时,程序中就不能出现方言性的sql语句,否则程序在个性化的sql上做不到数据库兼容,因此要想产品能兼容多种数据类型,则在编码时就要考虑将个性化的方言sql抽离出来。

三、数据库兼容方案

实现思路:
(1)应用启动时要根据数据源知道当前链接的数据库类型,并存到全局变量
(2)根据数据库类型自动设置mybatis-plus分页方言
(3)个性化方言实现不要在主业务中耦合(如:if mysql … else if sqlserver…)
(4)个性化方言实现可以多种数据库类型复用(如mysql、mariadb可以用一种实现)
(5)个性化方言实现类能根据数据库类型自动注入
代码实现:
根据url获取数据库类型

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
/**
 * 数据库类型
 */
public class Dialect {

    private static DbType dbType = null;
    private static final String DB_URL = "spring.datasource.url";
    /**
     * 获取数据库类型
     * @return
     */
    public synchronized static DbType getDbType(){
        if(dbType == null){
            String url = PropUtil.getValue(DB_URL);
            dbType = JdbcUtils.getDbType(url);
        }
        return dbType;
    }
}

自定义注解(实现方言实现的选择注入)

import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

/**
 * Configuration annotation for a conditional element that depends on the dbType.
 *
 * @author luoxiaolin5
 * @date 14:34 2023/4/12
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(DbTypeCondition.class)
public @interface ConditionalOnDbType {
    /**
     * condition dbType or {@code false} if it fails.
     * @return the DbType
     */
    DbType[] types() default DbType.OTHER;
}

注解条件实现

import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;


/**
 * A Condition that match current dbType.
 * @author luoxiaolin5
 * @date 12:56 2023/4/12
 */
public class DbTypeCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        DbType[] dbTypes = (DbType[]) metadata.getAnnotationAttributes(ConditionalOnDbType.class.getName()).get("types");
        for(DbType dbType : dbTypes){
            if(Dialect.getDbType().equals(dbType)){
                return true;
            }
        }
        return false;
    }
}

1、mybatisplus配置

分页方言配置

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(Dialect.getDbType()));
        return interceptor;
    }
}

2、数据库YAML配置

数据源配置上注意驱动和URL的替换。

mysql配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip:3306/db?serverTimezone=Asia/Shanghai&useUnicode=true
    username: username
    password: password
    hikari:
      ## 最小空闲连接数
      minimum-idle: 5
      ## 最大连接数
      maximum-pool-size: 20
      ## 自动提交
      auto-commit: true
      ## 连接池名称
      pool-name: TmcHikariCP
      ## 超时时间(ms)
      connection-timeout: 30000

sqlserver配置

spring:
  datasource:
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://ip:1433;databasename=db_schema;trustServerCertificate=true;integratedSecurity=false;
    username: username
    password: password
    hikari:
      ## 最小空闲连接数
      minimum-idle: 5
      ## 最大连接数
      maximum-pool-size: 20
      ## 自动提交
      auto-commit: true
      ## 连接池名称
      pool-name: TmcHikariCP
      ## 超时时间(ms)
      connection-timeout: 30000
 

3、应用举例

方言抽离接口

/**
 * 数据库兼容处理
 * @author luoxiaolin5
 * @date 12:39 2023/4/12
 */
public interface DialectService<T> {
    /**
     * json条件拼接查询
     * @param queryWrapper
     */
    void conditon(QueryWrapper<T> queryWrapper, Map<String, Clazz> attrMap,Object k,Object v);

}

Mysql方言实现

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * mysql 条件拼接实现
 * @author luoxiaolin5
 * @date 12:43 2023/4/12
 */
@Slf4j
@Service
@ConditionalOnDbType(types = {DbType.MYSQL,DbType.MARIADB})
public class MysqlFormDataDialectServiceImpl implements FormDataDialectService<FormDataEntity> {

    @Override
    public void conditon(QueryWrapper<FormDataEntity> queryWrapper, Map<String, Clazz> attrMap, Object k, Object v) {
        try {
            //替换时间类型判断(时间查询为时间段)
            Clazz.Format format = attrMap.get(k).getFormat();
            if(Clazz.Format.DateTime.equals(format) || Clazz.Format.Date.equals(format)){
                String[] dateArray = ObjectMapperHelper.mapper().readValue(v.toString(), String[].class);
                queryWrapper.ge("attr_json->'$." + k + "'", dateArray[0]);
                queryWrapper.lt("attr_json->'$." + k + "'", dateArray[1]);
            }else {
                queryWrapper.eq("attr_json->'$." + k + "'", v);
            }
        }catch (Exception e){
            log.error("form data query k:{},v:{} error:{}",k,v,e.getMessage());
        }
    }
}

Sqlserver方言实现

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * sql server 条件拼接实现
 * @author luoxiaolin5
 * @date 12:43 2023/4/12
 */
@Slf4j
@Service
@ConditionalOnDbType(types = {DbType.SQL_SERVER2005,DbType.SQL_SERVER})
public class SqlServerFormDataDialectServiceImpl implements FormDataDialectService<FormDataEntity> {

    @Override
    public void conditon(QueryWrapper<FormDataEntity> queryWrapper, Map<String, Clazz> attrMap, Object k, Object v) {
        try {
            //替换时间类型判断(时间查询为时间段)
            Clazz.Format format = attrMap.get(k).getFormat();
            if(Clazz.Format.DateTime.equals(format) || Clazz.Format.Date.equals(format)){
                String[] dateArray = ObjectMapperHelper.mapper().readValue(v.toString(), String[].class);
                queryWrapper.ge("JSON_VALUE(attr_json, '$." + k + "')", dateArray[0]);
                queryWrapper.lt("JSON_VALUE(attr_json, '$." + k + "')", dateArray[1]);
            }else {
                queryWrapper.eq("JSON_VALUE(attr_json, '$." + k + "')", v);
            }
        }catch (Exception e){
            log.error("form data query k:{},v:{} error:{}",k,v,e.getMessage());
        }
    }
}

4、数据库脚本转换

最后注意数据库脚本从mysql到sqlserver的转换,可以用微软的工具Microsoft SQL Server Migration Assistant for MySQL,
可参照官网实现。
下载链接:https://www.microsoft.com/en-us/download/details.aspx?id=54257&6B49FDFB-8E5B-4B07-BC31-15695C5A2143=1

举报

相关推荐

0 条评论