Search code examples
springoracle-databasepostgresqlmybatisspring-mybatis

MyBatis DB_VENDOR doesn't work


can you please help me figure out what is wrong with the DB_VENDOR in MyBatis? I'm using mybatis 3.4.2, mybatis-spring 1.3.1, spring 4.3.6.RELEASE.

Everything, but the vendor dependent queries, works fine. The example query is not vendor dependent, this is only for the sake of this example. If I remove the databaseId attribute from it and remove the duplicated one, this query works.

I need to support Oracle and PostgreSQL and have already checked the metadata getDatabaseProductName() directly within my test scope, getting "Oracle" and "PostgreSQL". So if I got the documentation right, it should work, shouldn't it?

All I get with the databaseId in place is:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): mappers.ConfigurationMapper.containsKey

test-mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "Http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <databaseIdProvider type="DB_VENDOR">
        <property name="PostgreSQL" value="postgres"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>

    <mappers>
        <mapper resource="mybatis/ConfigurationMapper.xml"/>
    </mappers>
</configuration>

test-context.xml (having another one with PostgreSQL datasource)

    <mybatis:scan base-package="mappers" annotation="org.apache.ibatis.annotations.Mapper" factory-ref="sqlSessionFactory"/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
    <property name="username" value="test"/>
    <property name="password" value="test"/>
</bean>

<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:test-mybatis-config.xml"/>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

ConfigurationMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mappers.ConfigurationMapper">

    <select id="containsKey" resultType="string" parameterType="string" databaseId="oracle">
        SELECT '1' AS test FROM config_keys WHERE key = #{configKey}
    </select>

    <select id="containsKey" resultType="string" parameterType="string" databaseId="postgres">
        SELECT '1' AS test FROM config_keys WHERE key = #{configKey}
    </select>
</mapper>

mapper interface:

@Mapper
public interface ConfigurationMapper {

    String containsKey(@Param("configKey") String configKey);
}

Solution

  • Found it. The answer is in the XMLConfigBuilder:

        Environment environment = configuration.getEnvironment();
        if (environment != null && databaseIdProvider != null) {
          String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
          configuration.setDatabaseId(databaseId);
        }
    

    The environment must be configured in order to make the databaseId work.

    Here is how to use multi-db support in spring environment: http://www.mybatis.org/spring/factorybean.html

    <bean id="vendorProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="properties">
            <props>
                <prop key="SQL Server">sqlserver</prop>
                <prop key="DB2">db2</prop>
                <prop key="Oracle">oracle</prop>
                <prop key="MySQL">mysql</prop>
            </props>
        </property>
    </bean>
    
    <bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
        <property name="properties" ref="vendorProperties"/>
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
        <property name="databaseIdProvider" ref="databaseIdProvider"/>
    </bean>