MyBatis 提供了数据库厂商标识(DatabaseIdProvider)功能,允许你根据不同的数据库厂商编写特定的 SQL 语句。这在需要支持多数据库的项目中非常有用。
首先需要在 MyBatis 配置文件中配置 DatabaseIdProvider:
<configuration>
<databaseIdProvider type="VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="PostgreSQL" value="postgresql"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
</configuration>
在 SQL 映射文件中,可以为不同数据库编写特定的 SQL 语句:
<select id="selectUser" resultType="User" databaseId="mysql">
SELECT * FROM user LIMIT #{offset}, #{limit}
</select>
<select id="selectUser" resultType="User" databaseId="oracle">
SELECT * FROM (
SELECT a.*, ROWNUM rn FROM (
SELECT * FROM user
) a WHERE ROWNUM <= #{end}
) WHERE rn >= #{start}
</select>
<select id="selectUser" resultType="User" databaseId="postgresql">
SELECT * FROM user OFFSET #{offset} LIMIT #{limit}
</select>
在动态 SQL 中,可以使用内置的 _databaseId
变量来编写条件分支:
<select id="selectUser" resultType="User">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="_databaseId == 'mysql'">
LIMIT #{offset}, #{limit}
</if>
<if test="_databaseId == 'oracle'">
AND ROWNUM <= #{end}
</if>
</where>
<if test="_databaseId == 'oracle'">
OFFSET #{start} ROWS
</if>
</select>
如果需要更复杂的逻辑,可以实现自己的 DatabaseIdProvider:
public class CustomDatabaseIdProvider implements DatabaseIdProvider {
@Override
public void setProperties(Properties properties) {
// 初始化配置
}
@Override
public String getDatabaseId(DataSource dataSource) {
// 根据数据源返回数据库标识
try (Connection conn = dataSource.getConnection()) {
String dbName = conn.getMetaData().getDatabaseProductName();
if ("MySQL".equals(dbName)) {
return "mysql";
} else if ("Oracle".equals(dbName)) {
return "oracle";
}
// 其他数据库...
} catch (SQLException e) {
throw new RuntimeException("无法获取数据库标识", e);
}
return null;
}
}
在注解方式的 Mapper 中也可以使用数据库厂商标识:
public interface UserMapper {
@SelectProvider(type = UserSqlProvider.class, method = "selectUser")
List<User> selectUsers(User user);
}
public class UserSqlProvider {
public String selectUser(User user) {
return new SQL() {{
SELECT("*");
FROM("user");
if (user.getName() != null) {
WHERE("name = #{name}");
}
if ("mysql".equals(getDatabaseId())) {
LIMIT("#{offset}, #{limit}");
}
}}.toString();
}
// 获取当前数据库标识
private String getDatabaseId() {
return Configuration.getDatabaseId();
}
}
通过合理使用数据库厂商标识,可以大大简化多数据库支持的开发工作。