目录
mybatis plus的springboot配置方式和mvc配置方式
1、MybatisPlus的springboot的配置方式
1.1、配置application.properties
#mybatis-plus
mybatis-plus.type-aliases-package=com.xx.archive.*
mybatis-plus.mapper-locations=classpath:dao/*.xml
mybatis-plus.global-config.db-config.table-underline=true
#mybatis-plus.global-config.db-config.column-underline=true
mybatis-plus.global-config.db-config.id-type=auto
#下面这句打开的时候是可以进行 打印sql到控制台
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
1.2、MybatisPlusConfig配置
@Configuration
public class MybatisPlusConfig {
/*
* 分页插件,自动识别数据库类型
* 多租户,请参考官网【插件扩展】
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql");
return page;
}
/**
* SQL执行效率插件(打印sql)
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
return performanceInterceptor;
}
}
2、mvc配置
2.1、配置properties
#mybatis-plus config
mybatis-plus.entities=com.xx.archive
mybatis-plus.mapper=classpath*:dao/*.xml,classpath*:dao/system/*.xml
mybatis-plus.transaction.definition=true
2.2、MybatisPlusConfig配置
@Configuration
@PropertySource(value = "classpath:mybatis/mybatis.properties")
public class MybatisPlusConfig {
/**
* 慢查询
*/
public static final int TIME = 300;
@Value("${mybatis-plus.entities}")
private String entities;
@Value("${mybatis-plus.mapper}")
private String[] mapperLocations;
@Autowired
private DataSource dataSource;
@MapperScan({"com.xx.archive.business.*.dao", "com.xx.archive.business.*.mapper"})
@Configuration
public class MybatisPlusMapperScan {
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
//单个路径配置
//Resource[] resources = resolver.getResources("classpath*:dao/*.xml");
sqlSessionFactoryBean.setMapperLocations(getMapperLocations(mapperLocations));
//配置包的别名,会导致reader entry乱码
sqlSessionFactoryBean.setTypeAliasesPackage(entities);
} catch (Exception e) {
e.printStackTrace();
}
//数据库策略
GlobalConfig globalConfig = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setIdType(IdType.AUTO);
globalConfig.setDbConfig(dbConfig);
sqlSessionFactoryBean.setGlobalConfig(globalConfig);
//操作日志
MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
mybatisConfiguration.setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);
sqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
//分页拦截器
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setDialectType("mysql");
//sql日志 拦截器
SqlLogInterceptor sqlLogInterceptor = new SqlLogInterceptor();
sqlLogInterceptor.setWriteInLog(true);
sqlLogInterceptor.setMaxTime(TIME);
//加入到sqlSessionFactory
sqlSessionFactoryBean.setPlugins(new Interceptor[]{
sqlLogInterceptor,
paginationInterceptor
});
SqlSessionFactory sessionFactory = sqlSessionFactoryBean.getObject();
return sessionFactory;
}
/**
* @param mapperLocations |多个xml配置的路径
* @return
*/
public Resource[] getMapperLocations(String[] mapperLocations) {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList();
if (mapperLocations != null) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
}
2.3、SqlLogInterceptor
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
@Slf4j(topic = "sql")
public class SqlLogInterceptor implements Interceptor {
private static final String DruidPooledPreparedStatement = "com.alibaba.druid.pool.DruidPooledPreparedStatement";
private static final String T4CPreparedStatement = "oracle.jdbc.driver.T4CPreparedStatement";
private static final String OraclePreparedStatementWrapper = "oracle.jdbc.driver.OraclePreparedStatementWrapper";
/**
* SQL 执行最大时长,超过自动停止运行,有助于发现问题。
*/
@Setter
@Getter
@Accessors(chain = true)
private long maxTime = 0;
/**
* SQL 是否格式化
*/
@Setter
@Getter
@Accessors(chain = true)
private boolean format = false;
/**
* 是否写入日志文件<br>
* true 写入日志文件,不阻断程序执行!<br>
* 超过设定的最大执行时长异常提示!
*/
@Setter
@Getter
@Accessors(chain = true)
private boolean writeInLog = false;
private Method oracleGetOriginalSqlMethod;
private Method druidGetSQLMethod;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Statement statement;
Object firstArg = invocation.getArgs()[0];
if (Proxy.isProxyClass(firstArg.getClass())) {
statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
} else {
statement = (Statement) firstArg;
}
MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);
try {
statement = (Statement) stmtMetaObj.getValue("stmt.statement");
} catch (Exception e) {
// do nothing
}
if (stmtMetaObj.hasGetter("delegate")) {
//Hikari
try {
statement = (Statement) stmtMetaObj.getValue("delegate");
} catch (Exception ignored) {
}
}
String originalSql = null;
String stmtClassName = statement.getClass().getName();
if (DruidPooledPreparedStatement.equals(stmtClassName)) {
try {
if (druidGetSQLMethod == null) {
Class<?> clazz = Class.forName(DruidPooledPreparedStatement);
druidGetSQLMethod = clazz.getMethod("getSql");
}
Object stmtSql = druidGetSQLMethod.invoke(statement);
if (stmtSql instanceof String) {
originalSql = (String) stmtSql;
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (T4CPreparedStatement.equals(stmtClassName)
|| OraclePreparedStatementWrapper.equals(stmtClassName)) {
try {
if (oracleGetOriginalSqlMethod != null) {
Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);
if (stmtSql instanceof String) {
originalSql = (String) stmtSql;
}
} else {
Class<?> clazz = Class.forName(stmtClassName);
oracleGetOriginalSqlMethod = getMethodRegular(clazz, "getOriginalSql");
if (oracleGetOriginalSqlMethod != null) {
//OraclePreparedStatementWrapper is not a public class, need set this.
oracleGetOriginalSqlMethod.setAccessible(true);
if (null != oracleGetOriginalSqlMethod) {
Object stmtSql = oracleGetOriginalSqlMethod.invoke(statement);
if (stmtSql instanceof String) {
originalSql = (String) stmtSql;
}
}
}
}
} catch (Exception e) {
//ignore
}
}
if (originalSql == null) {
originalSql = statement.toString();
}
originalSql = originalSql.replaceAll("[\\s]+", StringPool.SPACE);
int index = indexOfSqlStart(originalSql);
if (index > 0) {
originalSql = originalSql.substring(index);
}
// 计算执行 SQL 耗时
long start = SystemClock.now();
Object result = invocation.proceed();
long timing = SystemClock.now() - start;
// 格式化 SQL 打印执行结果
Object target = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(target);
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//格式化sql拼接
// String sqlFormatStr = SqlUtils.sqlFormat(originalSql, true);
StringBuilder formatSql = new StringBuilder()
.append(" Time:").append(timing)
.append(" ms - ID:")
.append(ms.getId())
.append(StringPool.NEWLINE).append("Execute SQL:")
.append(originalSql)
.append(StringPool.NEWLINE);
if (this.isWriteInLog()) {
if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) {
//慢sql
log.error(formatSql.toString());
} else {
log.info(formatSql.toString());
}
}
return result;
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties prop) {
String maxTime = prop.getProperty("maxTime");
String format = prop.getProperty("format");
if (StringUtils.isNotEmpty(maxTime)) {
this.maxTime = Long.parseLong(maxTime);
}
if (StringUtils.isNotEmpty(format)) {
this.format = Boolean.valueOf(format);
}
}
/**
* 获取此方法名的具体 Method
*
* @param clazz class 对象
* @param methodName 方法名
* @return 方法
*/
public Method getMethodRegular(Class<?> clazz, String methodName) {
if (Object.class.equals(clazz)) {
return null;
}
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
return method;
}
}
return getMethodRegular(clazz.getSuperclass(), methodName);
}
/**
* 获取sql语句开头部分
*
* @param sql
* @return
*/
private int indexOfSqlStart(String sql) {
String upperCaseSql = sql.toUpperCase();
Set<Integer> set = new HashSet<>();
set.add(upperCaseSql.indexOf("SELECT "));
set.add(upperCaseSql.indexOf("UPDATE "));
set.add(upperCaseSql.indexOf("INSERT "));
set.add(upperCaseSql.indexOf("DELETE "));
set.remove(-1);
if (CollectionUtils.isEmpty(set)) {
return -1;
}
List<Integer> list = new ArrayList<>(set);
list.sort(Comparator.naturalOrder());
return list.get(0);
}
}
2.4、TransactionalConfig
/**
* @author yuguang
* @date 2019/12/11 10:56
* @desc
*/
@Setter
@Getter
@Configuration
@ConditionalOnExpression("${mybatis-plus.transaction.definition:true}")
@EnableTransactionManagement
public class TransactionalConfig {
private static final String CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME = "customizeTransactionInterceptor";
/**
* 默认只对 "*Service" , "*ServiceImpl" Bean 进行事务处理,"*"表示模糊匹配, 比如 : userService,orderServiceImpl
*/
private static final String[] DEFAULT_TRANSACTION_BEAN_NAMES = {"*Service", "*ServiceImpl"};
/**
* 可传播事务配置
*/
private static final String[] DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES = {
"add*",
"save*",
"insert*",
"delete*",
"update*",
"edit*",
"batch*",
"create*",
"remove*",
};
/**
* 默认的只读事务
*/
private static final String[] DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES = {
"get*",
"count*",
"find*",
"query*",
"select*",
"list*",
"*",
};
/**
* 自定义事务 BeanName 拦截
*/
private String[] customizeTransactionBeanNames = {};
/**
* 自定义方法名的事务属性相关联,可以使用通配符(*)字符关联相同的事务属性的设置方法; 只读事务
*/
private String[] customizeReadOnlyMethodRuleTransactionAttributes = {};
/**
* 自定义方法名的事务属性相关联,可以使用通配符(*)字符关联相同的事务属性的设置方法;
* 传播事务(默认的){@link org.springframework.transaction.annotation.Propagation#REQUIRED}
*/
private String[] customizeRequiredMethodRuleTransactionAttributes = {};
/**
* 配置事务拦截器
*
* @param transactionManager : 事务管理器
*/
@Bean(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME)
public TransactionInterceptor customizeTransactionInterceptor(PlatformTransactionManager transactionManager) {
NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule();
RuleBasedTransactionAttribute required = this.requiredTransactionRule();
// 默认的只读事务配置
for (String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
}
// 默认的传播事务配置
for (String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
transactionAttributeSource.addTransactionalMethod(methodName, required);
}
// 定制的只读事务配置
for (String methodName : customizeReadOnlyMethodRuleTransactionAttributes) {
transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
}
// 定制的传播事务配置
for (String methodName : customizeRequiredMethodRuleTransactionAttributes) {
transactionAttributeSource.addTransactionalMethod(methodName, required);
}
return new TransactionInterceptor(transactionManager, transactionAttributeSource);
}
/**
* 配置事务拦截
* <p>
* {@link #customizeTransactionInterceptor(PlatformTransactionManager)}
*/
@Bean
public BeanNameAutoProxyCreator customizeTransactionBeanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 设置定制的事务拦截器
beanNameAutoProxyCreator.setInterceptorNames(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME);
List<String> transactionBeanNames = new ArrayList<>(DEFAULT_TRANSACTION_BEAN_NAMES.length + customizeTransactionBeanNames.length);
// 默认
transactionBeanNames.addAll(Arrays.asList(DEFAULT_TRANSACTION_BEAN_NAMES));
// 定制
transactionBeanNames.addAll(Arrays.asList(customizeTransactionBeanNames));
// 归集
for (String transactionBeanName : transactionBeanNames) {
beanNameAutoProxyCreator.setBeanNames(transactionBeanName);
}
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
/**
* 支持当前事务;如果不存在创建一个新的
* {@link org.springframework.transaction.annotation.Propagation#REQUIRED}
*/
private RuleBasedTransactionAttribute requiredTransactionRule() {
RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
required.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);
return required;
}
/**
* 只读事务
* {@link org.springframework.transaction.annotation.Propagation#NOT_SUPPORTED}
*/
private RuleBasedTransactionAttribute readOnlyTransactionRule() {
RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
readOnly.setReadOnly(true);
readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
return readOnly;
}
}