com.github.mybatisintercept.util.MysqlMissColumnDataSourceConsumer Maven / Gradle / Ivy
package com.github.mybatisintercept.util;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* 查询没有字段的表
*/
public class MysqlMissColumnDataSourceConsumer implements Consumer> {
private static final Map> SKIP_TABLE_NAMES_CACHE = new ConcurrentHashMap<>(2);
private static final Map CATALOG_CACHE = new ConcurrentHashMap<>(2);
private final Collection> columnList = new LinkedHashSet<>();
public MysqlMissColumnDataSourceConsumer(Collection extends Collection> groupColumnList) {
for (Collection columnList : groupColumnList) {
this.columnList.add(new TreeSet<>(columnList));
}
}
public Collection> getColumnList() {
return columnList;
}
@Override
public void accept(Collection dataSources) {
if (dataSources == null || dataSources.isEmpty()) {
return;
}
try {
Set missColumnTableList = selectMissColumnTableList(dataSources, columnList);
onSelectEnd(missColumnTableList);
} catch (Exception e) {
Exception exception = onSelectException(e);
if (exception != null) {
PlatformDependentUtil.sneakyThrows(exception);
}
}
}
public void onSelectEnd(Set missColumnTableList) {
}
public Exception onSelectException(Exception exception) {
return exception;
}
private Set selectMissColumnTableList(Collection dataSources, Collection extends Collection> columnNameListList) {
Set tableList = new LinkedHashSet<>();
if (columnNameListList == null || columnNameListList.isEmpty()) {
return tableList;
}
for (DataSource dataSource : dataSources) {
String selectCatalog = getCatalog(dataSource);
List itemTableList = selectMissColumnTableList(dataSource, selectCatalog, columnNameListList);
tableList.addAll(itemTableList);
}
return tableList;
}
private String getCatalog(DataSource dataSource) {
return CATALOG_CACHE.computeIfAbsent(System.identityHashCode(dataSource), e -> {
try (Connection connection = dataSource.getConnection()) {
return connection.getCatalog();
} catch (Exception err) {
return null;
}
});
}
private List selectMissColumnTableList(DataSource dataSource, String catalog, Collection extends Collection> columnNameListList) {
// columnNameListList两种情况都没有,才算miss
Map missCounterMap = new LinkedHashMap<>();
for (Collection columnNameList : columnNameListList) {
String cacheKey = String.format("%d-%s", System.identityHashCode(dataSource), Objects.hash(columnNameList));
Set tableList = SKIP_TABLE_NAMES_CACHE.computeIfAbsent(cacheKey, e -> {
Set list = new LinkedHashSet<>();
int columnNameSize = columnNameList.size();
StringJoiner args = new StringJoiner(",");
for (int i = 0; i < columnNameSize; i++) {
args.add("?");
}
boolean isCatalog = catalog != null && !catalog.isEmpty();
String sql = isCatalog ? "SELECT GROUP_CONCAT(DISTINCT TABLE_NAME) TABLE_NAME,COUNT(IF(COLUMN_NAME in (" + args + "),1,null)) CNT FROM INFORMATION_SCHEMA.`COLUMNS` WHERE TABLE_SCHEMA = ? GROUP BY TABLE_NAME HAVING CNT != ?"
: "SELECT GROUP_CONCAT(DISTINCT TABLE_NAME) TABLE_NAME,COUNT(IF(COLUMN_NAME in (" + args + "),1,null)) CNT FROM INFORMATION_SCHEMA.`COLUMNS` GROUP BY TABLE_NAME HAVING CNT != ?";
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
int parameterIndex = 0;
for (String columnName : columnNameList) {
statement.setString(++parameterIndex, columnName);
}
if (isCatalog) {
statement.setString(++parameterIndex, catalog);
}
statement.setInt(++parameterIndex, columnNameSize);
try (ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
String tableName = rs.getString(1);
list.add(tableName);
}
}
} catch (Exception err) {
PlatformDependentUtil.sneakyThrows(err);
}
return Collections.unmodifiableSet(list);
});
for (String tableName : tableList) {
missCounterMap.compute(tableName, (k, v) -> v == null ? 1 : v + 1);
}
}
return missCounterMap.entrySet().stream().filter(e -> e.getValue() == columnNameListList.size()).map(Map.Entry::getKey).collect(Collectors.toList());
}
}