MyBatis的DatabaseIdProvider解析

MyBatis 的 DatabaseIdProvider 解析

数据库厂商标识

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃

配置方法

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
    <environment id="developmentOracle">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${oracle.driver}"/>
            <property name="url" value="${oracle.url}"/>
            <property name="username" value="${oracle.username}"/>
            <property name="password" value="${oracle.password}"/>
        </dataSource>
    </environment>
</environments>

<databaseIdProvider type="com.yczuoxin.databaseidorovider.MyDatabaseIdProvider">
    <property name="Oracle" value="oracle"/>
    <property name="MySQL" value="mysql"/>
</databaseIdProvider>

DatabaseIdProvider 接口

public interface DatabaseIdProvider {

    default void setProperties(Properties p) {
        // NOP
    }
	// 返回数据源的产品名称
    String getDatabaseId(DataSource dataSource) throws SQLException;
}

其继承关系如下

  • org.apache.ibatis.mapping.DatabaseIdProvider
    • org.apache.ibatis.mapping.VendorDatabaseIdProvider

VendorDatabaseIdProvider 实现类

public class VendorDatabaseIdProvider implements DatabaseIdProvider {

    private Properties properties;

    @Override
    public String getDatabaseId(DataSource dataSource) {
        // 空值判定
        if (dataSource == null) {
            throw new NullPointerException("dataSource cannot be null");
        }
        try {
            // 获取数据源的产品名称
            return getDatabaseName(dataSource);
        } catch (Exception e) {
            LogHolder.log.error("Could not get a databaseId from dataSource", e);
        }
        return null;
    }

    @Override
    public void setProperties(Properties p) {
        this.properties = p;
    }

    private String getDatabaseName(DataSource dataSource) throws SQLException {
        String productName = getDatabaseProductName(dataSource);
        if (this.properties != null) {
            for (Map.Entry<Object, Object> property : properties.entrySet()) {
                if (productName.contains((String) property.getKey())) {
                    return (String) property.getValue();
                }
            }
            // no match, return null
            return null;
        }
        return productName;
    }

    private String getDatabaseProductName(DataSource dataSource) throws SQLException {
        Connection con = null;
        try {
            con = dataSource.getConnection();
            DatabaseMetaData metaData = con.getMetaData();
            return metaData.getDatabaseProductName();
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    // ignored
                }
            }
        }
    }

    private static class LogHolder {
        private static final Log log = LogFactory.getLog(VendorDatabaseIdProvider.class);
    }

}

查询数据源产品名称底层调用的是 java.sql.DatabaseMetaData#getDatabaseProductName 方法,在 mapper.xml 中选择对应的 databaseId 就会将信息保存在org.apache.ibatis.mapping.MappedStatement 对象中并保存在 Configuration 的 Map<String, MappedStatement> mappedStatements 中保存


配置读取

private void databaseIdProviderElement(XNode context) throws Exception {
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
        String type = context.getStringAttribute("type");
        if ("VENDOR".equals(type)) {
            type = "DB_VENDOR";
        }
        Properties properties = context.getChildrenAsProperties();
        // DB_VENDOR 类型创建 VendorDatabaseIdProvider 对象
        databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
        databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
        String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
        configuration.setDatabaseId(databaseId);
    }
}

自定义

public class MyDatabaseIdProvider implements DatabaseIdProvider {
    private static final Log log = LogFactory.getLog(MyDatabaseIdProvider.class);
    private Properties properties;

    @Override
    public void setProperties(Properties p) {
        this.properties = p;
    }

    @Override
    public String getDatabaseId(DataSource dataSource) throws SQLException {
        Connection connection = dataSource.getConnection();
        DatabaseMetaData metaData = connection.getMetaData();
        String databaseProductName = metaData.getDatabaseProductName();
        log.debug("Current DataBase Product Name is: " + databaseProductName);
        for (Object key : properties.keySet()) {
            if (key.equals(databaseProductName)) {
                log.debug("Find a matched property value: " + properties.get(key));
                return (String) properties.get(key);
            }
        }
        return null;
    }
}

在配置中引入

<databaseIdProvider type="com.yczuoxin.databaseprovider.MyDatabaseIdProvider">
    <property name="DB2" value="db2"/>
    <property name="Oracle" value="oracle" />
</databaseIdProvider>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis是一个轻量级的Java持久层开源框架,它封装了JDBC操作数据库的底层细节,提供了一个简单易用的数据库访问方式。 Mybatis的源码分为核心模块和附加模块两部分,核心模块主要包括配置解析、SQL解析、SQL执行等功能,附加模块包括连接池、缓存、事务管理等功能。 在Mybatis的源码中,配置解析是其中的关键部分。通过解析mybatis-config.xml配置文件,可以获取到数据库连接信息、映射器配置、插件配置等。在配置解析过程中,Mybatis会对配置文件进行校验,确保配置的正确性。 SQL解析Mybatis的另一个重要功能。Mybatis通过解析Mapper接口中的注解或XML配置文件中的SQL语句,将SQL语句解析为ParameterMapping、BoundSql等对象,并将其封装成一个MappedStatement对象,供后续的SQL执行使用。 SQL执行是Mybatis的核心功能之一。在SQL执行阶段,Mybatis会根据MappedStatement中的信息,获取数据库连接,并执行对应的SQL语句。在执行过程中,Mybatis会通过TypeHandler对参数进行类型转换,并使用ResultSetHandler将查询结果封装成Java对象。 除了核心模块,Mybatis的源码还包括了连接池、缓存、事务管理等附加模块的实现。连接池模块负责管理数据库连接的获取和释放,缓存模块负责缓存查询结果以提高性能,而事务管理模块则负责管理数据库的事务处理。 总之,Mybatis的源码解析涉及多个关键模块的实现,包括配置解析、SQL解析、SQL执行、连接池、缓存、事务管理等。通过了解这些模块的实现原理,我们可以更好地理解和使用Mybatis框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值