我们在做一些兼容非MySQL数据库时,经常遇到一些关键字,或者语法差异问题。 这里举个极端例子,有个字段为desc,因为与数据库关键字冲突,在mysql中需要使用`desc`,而guassdb中需要使用"desc"
针对有语法差异的,利用mybatis的@Intercepts
注解插件拦截,在拦截器中,处理与mysql的兼容性问题,通过类型判断,写不同逻辑
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
public class SqlDialectInterceptor implements Interceptor {
private String databaseType;
public SqlDialectInterceptor(String databaseType) {
this.databaseType = databaseType;
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
String adjustedSql = adjustedSql(sql);
Field sqlField = boundSql.getClass().getDeclaredField("sql");
sqlField.setAccessible(true);
sqlField.set(boundSql, adjustedSql);
return invocation.proceed();
}
private String adjustedSql(String sql) {
if (databaseType.toLowerCase().contains("mysql")) {
sql = sql.replace("\"desc\"", "`desc`");
} else {
sql = sql.replace("`desc`", "\"desc\"");
}
return sql;
}
@Override
public void setProperties(Properties properties) {
Interceptor.super.setProperties(properties);
}
}
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
@Configuration
@MapperScan(basePackages = "com.db.mapper")
public class SqlSessionFactoryConfig {
private static final Logger loggder = LoggerFactory.getLogger(SqlSessionFactoryConfig.class);
private final DataSource dataSource;
public SqlSessionFactoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public SqlSessionFactoryBean createSqlSessionFactory() {
try {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String packageXmlConfigPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "mybatis/mapper/**/*.xml";
// 设置 mapper 配置文件路径
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(packageXmlConfigPath));
// 设置数据源
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置 mybatis 配置文件路径
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
sqlSessionFactoryBean.setPlugins(new SqlDialectInterceptor(getDatabaseType(dataSource)));
return sqlSessionFactoryBean;
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
}
private String getDatabaseType(DataSource dataSource) {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
String databaseProductName = metaData.getDatabaseProductName();
loggder.info("init getDatabaseType: {}", databaseProductName);
return databaseProductName;
} catch (Exception ex) {
loggder.info("init getDatabaseType error {}", ex.getMessage(), ex);
return "mysql";
}
}
}