application.properties
mybatis-plus.config-location=classpath:mybatis-config.xml
mybatis-plus.mapper-locations=classpath:mapper/**/*.xml
spring.datasource.ubip.expected-type=javax.sql.DataSource
spring.datasource.ubip.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.ubip.jdbc-url=jdbc:mysql://10.60.86.154:3311/ioms?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=UTC
spring.datasource.ubip.username=deployop
spring.datasource.ubip.password=9pSKVWV+=2
spring.datasource.myeast.expected-type=javax.sql.DataSource
spring.datasource.myeast.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.myeast.jdbc-url=jdbc:oracle:thin:@10.50.81.17:1521:trade
spring.datasource.myeast.username=trade
spring.datasource.myeast.password=QHtest123
#spring.datasource.ubip.jndi-name=java:/iomsLife
#spring.datasource.ubip.expected-type=javax.sql.DataSource
#spring.datasource.ubip.driver-class-name=com.mysql.jdbc.Driver
#
#spring.datasource.myeast.jndi-name=java:/tradeLife
#spring.datasource.myeast.expected-type=javax.sql.DataSource
#spring.datasource.myeast.driver-class-name=oracle.jdbc.OracleDriver
数据源配置(默认数据源)
package com.xxx.xx.config;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jndi.JndiObjectFactoryBean;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
@MapperScan(basePackages = {"com.xxx.xx.**.dao", "com.xxx.xx.**.mapper", "com.xxx.xx.modules.xx.xx.dao.ioms"}, sqlSessionTemplateRef = "ubipSqlSessionTemplate")
public class UbipConfig {
// @Value("${spring.datasource.ubip.jndi-name}")
// private String jndiName;
//
// @Primary
// @Bean("ubipDataSource")
// @ConfigurationProperties(prefix = "spring.datasource.ubip")
// public DataSource getUbipDataSource() throws NamingException {
// JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
// bean.setJndiName(jndiName);
// bean.setProxyInterface(DataSource.class);
// bean.setLookupOnStartup(false);
// bean.afterPropertiesSet();
// return (DataSource) bean.getObject();
// }
@Primary
@Bean(name = "ubipDataSource")
@ConfigurationProperties(prefix = "spring.datasource.ubip")
public DataSource getUbipDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public GlobalConfig globalConfig() {
GlobalConfig conf = new GlobalConfig();
conf.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerator(new OracleKeyGenerator()));
return conf;
}
@Primary
@Bean("ubipSqlSessionFactory")
public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("ubipDataSource") DataSource dataSource) throws IOException {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
//配置拦截器插件 开始
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.addInterceptor(new SqlInterceptor());
bean.setConfiguration(configuration);
// 结束
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
bean.setGlobalConfig(globalConfig());
return bean;
}
@Primary
@Bean("ubipSqlSessionTemplate")
public SqlSessionTemplate ubipSqlSessionTemplate(@Qualifier("ubipSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
数据源配置2
package com.xxx.xx.config;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.io.IOException;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import javax.naming.NamingException;
@Configuration
@MapperScan(basePackages = {"com.xxx.xx.modules.xxx.xx.dao.trade"}, sqlSessionTemplateRef = "myeastSqlSessionTemplate") // com.xxx.xx.modules.xxx.xx.dao.trade 为Dao层
public class MyeastConfig {
// @Value("${spring.datasource.myeast.jndi-name}")
// private String jndiName;
//
// @Bean("myeastDataSource")
// @ConfigurationProperties(prefix = "spring.datasource.myeast")
// public DataSource getMyeastDataSource() throws NamingException {
// JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
// bean.setJndiName(jndiName);
// bean.setProxyInterface(DataSource.class);
// bean.setLookupOnStartup(false);
// bean.afterPropertiesSet();
// return (DataSource) bean.getObject();
// }
@Bean(name = "myeastDataSource")
@ConfigurationProperties(prefix = "spring.datasource.myeast")
public DataSource getMyeastDataSource() {
return DataSourceBuilder.create().build();
}
@Bean("myeastSqlSessionFactory")
public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("myeastDataSource") DataSource dataSource) throws IOException{
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
//配置拦截器插件 开始
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.addInterceptor(new SqlInterceptor());
bean.setConfiguration(configuration);
// 结束
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
return bean;
}
@Bean("myeastSqlSessionTemplate")
public SqlSessionTemplate myeastSqlSessionTemplate(@Qualifier("myeastSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
由于配置多数据源导致日志不打印:
com.google.common.base.Joiner的依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
SqlInterceptor 类:
import com.google.common.base.Joiner;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
@Intercepts(value = {
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class})})
@Component
public class SqlInterceptor implements Interceptor {
private static final Logger log = LoggerFactory.getLogger(SqlInterceptor.class);
/**
* 重写intercept,拦截sql,拼接完整sql语句
* @param invocation 调用
* @return Object
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object returnValue;
long start = System.currentTimeMillis();
returnValue = invocation.proceed();
long end = System.currentTimeMillis();
long time = end - start;
try {
final Object[] args = invocation.getArgs();
//获取原始的ms
MappedStatement ms = (MappedStatement) args[0];
Object parameter = null;
//获取参数,if语句成立,表示sql语句有参数,参数格式是map形式
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
Method method = invocation.getMethod();
String name = method.getName();
String commandName = ms.getSqlCommandType().name();
if (commandName.startsWith("INSERT")) {
name = name + "=新增";
} else if (commandName.startsWith("UPDATE")) {
name = name + "=修改";
} else if (commandName.startsWith("DELETE")) {
name = name + "=删除";
} else if (commandName.startsWith("SELECT")) {
name = name + "=查询";
}
// 获取到节点的id,即sql语句的id
String sqlId = ms.getId();
// BoundSql就是封装myBatis最终产生的sql类
BoundSql boundSql = ms.getBoundSql(parameter);
// 获取节点的配置
Configuration configuration = ms.getConfiguration();
// 获取到最终的sql语句
String sql = getSql(configuration, boundSql, sqlId, time, returnValue, name);
log.info(sql);
} catch (Exception e) {
log.error("拦截sql处理出错,出错原因:" + e.getMessage());
e.printStackTrace();
}
return returnValue;
}
/**
* 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句
* @param configuration 配置
* @param boundSql boundSql
* @param sqlId sqlId
* @param time 执行时间
* @param result 结果
* @param name sql操作类型
* @return String
*/
public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId, long time, Object result, String name) {
Map<String, Object> map = showSql(configuration, boundSql);
String message = "[SqlInterceptor] 执行 [" + name + "] 时间 [" + new Timestamp(System.currentTimeMillis()) + "] sql耗时 [" + (double) time / 1000 + "] s";
StringBuilder str = new StringBuilder(100);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
str.append("\n").append("----------------------------begin【SQL Execute Message】--------------------------------\n");
str.append("【方法】").append(sqlId).append("\n");
str.append("【sql】").append(map.get("sql"));
str.append("\n");
str.append("【参数映射】").append(parameterMappings);
str.append("\n");
str.append("【参数对象】").append(Joiner.on(", ").join((Iterable<?>) map.get("parameters")));
str.append("\n");
str.append("【结果】 ");
if (result != null) {
if (result instanceof List) {
str.append("共 ").append(((List) result).size()).append(" 条记录\n");
} else if (result instanceof Collection) {
str.append("共 ").append(((Collection) result).size()).append(" 条记录\n");
} else {
str.append("共 1 条记录").append("\n");
}
/*str.append("【结果详情】").append(JSON.toJSONString(result));*/
} else {
str.append("【结果】 NULL").append("\n");
}
/*str.append("\n");*/
str.append("【执行信息】").append(message);
str.append("\n");
str.append("----------------------------end【SQL Execute Message】--------------------------------\n");
return str.toString();
}
/**
* 如果参数是String,则添加单引号,
* 如果是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理
* @param obj 参数
* @return String
*/
private static String getParameterValue(Object obj) {
String value;
if (obj instanceof String) {
value = "'" + obj + "'";
} else if (obj instanceof Date) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
value = "'" + formatter.format(obj) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
}
}
return value;
}
/**
* 进行?的替换
* @param configuration 配置
* @param boundSql boundSql
* @return Map<String, Object>
*/
public static Map<String, Object> showSql(Configuration configuration, BoundSql boundSql) {
Map<String, Object> map = new HashMap<>(0);
// 获取参数
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql
.getParameterMappings();
// sql语句中多个空格都用一个空格代替
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
List<String> list = new ArrayList<>();
if (!CollectionUtils.isEmpty(parameterMappings) && parameterObject != null) {
// 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换
// 如果根据parameterObject.getClass()可以找到对应的类型,则替换
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(parameterObject)));
list.add(parameterObject + "(" + parameterObject.getClass().getSimpleName() +")");
} else {
// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
list.add(parameterMapping.getProperty() + "=" + obj.toString() + "(" + obj.getClass().getSimpleName() +")");
} else if (boundSql.hasAdditionalParameter(propertyName)) {
// 该分支是动态sql
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(getParameterValue(obj)));
list.add(parameterMapping.getProperty() + "=" + obj.toString() + "(" + obj.getClass().getSimpleName() +")");
} else {
sql = sql.replaceFirst("\\?", "缺失");
list.add("缺失");
}//打印出缺失,提醒该参数缺失并防止错位
}
}
}
map.put("sql", sql);
map.put("parameters", list);
return map;
}
@Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, this);
}
@Override
public void setProperties(Properties properties) {
}
}