[Mybatis] 使用mybatis适配多数据库

本文介绍了Mybatis中如何使用DatabaseIdProvider和DatabaseIdEnum来识别数据库类型,以便根据厂商名称和自定义值动态调整SQL语句,解决不同数据库的兼容性问题。

1. 什么是databaseIdProvider

根据jdk规定,各个数据库厂商必须实现方法java.sql.DatabaseMetaData#getDatabaseProductName,这个方法会返回数据库产品的名称。mybatis就是根据这一原理,通过DatabaseIdProviderdatabaseId通过识别产品的productName,切换到对应数据库的处理,从而解决xml中SQL对于不同数据库的适配问题

2. 在Mybatis中使用DatabaseProvider来实现代码对多数据库的匹配

定义DatabaseId

/**
mybatis使用databaseid时需要适配的厂商名称和自定义的对应值。 厂商名称可以通过dataSource.getConnection().getMetaData().getDatabaseProductName()获取
**/
@AllArgsConstructor
public enum DBIdEnum
{
    Oracle("Oracle","oracle"),
    MySQL("MySQL","mysql"),
    MSSql("Microsoft SQL Server","mssql"), // mssql2019名称
    ;
     // 数据库厂商提供的productName
    private String name;
    // 根据productName自定义应用中使用的值
    private String value;

    public static DBIdEnum getEnumer(String _databaseId){
        DBIdEnum[] values = DBIdEnum.values();
        for(DBIdEnum v:values){
            if(_databaseId.equals(v.getValue())){
                return v;
            }
        }
        throw new RuntimeException("DBIdEnum中找不到给定的_databaseId:"+_databaseId);
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }
}

注册DatabaseIdProvider

  @Bean
    public DatabaseIdProvider databaseIdProvider() throws Exception  {
        log.info("当前数据的productName:{}",dataSource.getConnection().getMetaData().getDatabaseProductName());
        VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties props = new Properties();
        DBIdEnum[] values = DBIdEnum.values();
        for (DBIdEnum v : values) {
            props.put(v.getName(), v.getValue());
        }
        databaseIdProvider.setProperties(props);
        return databaseIdProvider;
    }

使用

方法一:使用java静态方法注入

注意:必须是静态方法


/**
 * mybatis中使用的SQL转义工具,根据不同数据库适配不同的SQL
 * 注意:
 * ①方法必须是静态方法
 * ②方法中的数据格式和语法必输是对应的数据库的SQL语法
 */
@Component
public class SqlConvert {
    @Resource
    private DatabaseIdProvider databaseIdProvider;
    @Resource
    private DataSource dataSource;
    public static DBIdEnum DBType;

    @PostConstruct
    public void init() throws SQLException {
        // 初始化
        String databaseId = databaseIdProvider.getDatabaseId(dataSource);
        DBType = DBIdEnum.getEnumer(databaseId);
    }
       /**
     * 不同原生数据库适配的uuid生成方式
     *
     * @return
     */
    public static String idGen() {
        return switch (DBType) {
            case Oracle -> "sys_guid() from dual";
            case MSSql -> "REPLACE(NEWID(),'-','')";
            default -> defaultOperation();
        };
    }
}

在XML文件中使用

<select id="listChargeDetailList" resultMap="BaseResultMap">
  ${@com.yn.config.mybatis.SqlConvert@idGen()} 
</select>

当然,在这种情况下,也可以使用参数的,比如java方法定义为:public static String ifNull(String expression, String defaultValue),那么就需要在xml文件中使用填入相应的参数: ${@com.yn.config.mybatis.SqlConvert@ifNull("avg(cast (total_costs as decimal) )","0.0")}

方法二:直接在Mybatis的xml文件中使用
 <sql id="wm_group_ori_price">
        <if test="_databaseId == 'oracle'">
            listagg
            (distinct charge_price, '||')
            within group (order by charge_price)
        </if>
        <if test="_databaseId == 'mssql'">
            stuff
            ((select '||' + x1.charge_price
            from (select distinct charge_detail_code,charge_price  from fin_hos_charge_detail  ) x1
            where x1.charge_detail_code = k1.charge_detail_code
            order by x1.charge_price for xml path('')) , 1, 2, '')
        </if>

    </sql>

在使用时,直接使用<include refid="wm_group_ori_price"></include>对当前进行SQL引用即可。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值