From 9e37f693c38a30e60ea843439b645439cd3cff16 Mon Sep 17 00:00:00 2001 From: Redkale Date: Sun, 25 Dec 2022 17:36:35 +0800 Subject: [PATCH] =?UTF-8?q?DistributeTableStrategy=E5=A2=9E=E5=8A=A0getTab?= =?UTF-8?q?les=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redkale/boot/LoggingSearchHandler.java | 6 +- .../org/redkale/source/DataJdbcSource.java | 179 ++++++++-- .../org/redkale/source/DataMemorySource.java | 8 +- .../org/redkale/source/DataSqlSource.java | 316 +++++++++++++----- .../source/DistributeTableStrategy.java | 22 +- .../java/org/redkale/source/EntityInfo.java | 8 +- .../org/redkale/source/FilterJoinNode.java | 4 +- 7 files changed, 411 insertions(+), 132 deletions(-) diff --git a/src/main/java/org/redkale/boot/LoggingSearchHandler.java b/src/main/java/org/redkale/boot/LoggingSearchHandler.java index 00e318c96..22fcebc53 100644 --- a/src/main/java/org/redkale/boot/LoggingSearchHandler.java +++ b/src/main/java/org/redkale/boot/LoggingSearchHandler.java @@ -6,10 +6,9 @@ import java.io.*; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.*; import java.util.logging.Formatter; +import java.util.logging.*; import java.util.regex.Pattern; - import static org.redkale.boot.Application.RESNAME_APP_NAME; import org.redkale.convert.*; import org.redkale.convert.json.JsonConvert; @@ -18,7 +17,6 @@ import org.redkale.persistence.*; import org.redkale.source.*; import org.redkale.util.*; - /** * 基于SearchSource的日志输出类 *

@@ -305,7 +303,7 @@ public class LoggingSearchHandler extends LoggingBaseHandler { } @Override - public String getTable(String table, FilterNode node) { + public String[] getTables(String table, FilterNode node) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/org/redkale/source/DataJdbcSource.java b/src/main/java/org/redkale/source/DataJdbcSource.java index cd50f9c26..557f0ca5a 100644 --- a/src/main/java/org/redkale/source/DataJdbcSource.java +++ b/src/main/java/org/redkale/source/DataJdbcSource.java @@ -315,19 +315,53 @@ public class DataJdbcSource extends DataSqlSource { } @Override - protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) { + protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String... sqls) { Connection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setReadOnly(false); conn.setAutoCommit(true); - sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); - final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); - stmt.close(); - slowLog(s, sql); + int c = 0; + if (sqls.length == 1) { + String sql = sqls[0]; + sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())); + if (info.isLoggable(logger, Level.FINEST, sql)) { + logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); + } + final Statement stmt = conn.createStatement(); + c = stmt.executeUpdate(sql); + stmt.close(); + } else { + if (flipper == null || flipper.getLimit() < 1) { + if (info.isLoggable(logger, Level.FINEST, sqls[0])) { + logger.finest(info.getType().getSimpleName() + " delete sqls=" + Arrays.toString(sqls)); + } + final Statement stmt = conn.createStatement(); + for (String sql : sqls) { + stmt.addBatch(sql); + } + int[] cs = stmt.executeBatch(); + stmt.close(); + for (int cc : cs) { + c += cc; + } + } else { + if (info.isLoggable(logger, Level.FINEST, sqls[0])) { + logger.finest(info.getType().getSimpleName() + " limit " + flipper.getLimit() + " delete sqls=" + Arrays.toString(sqls)); + } + final Statement stmt = conn.createStatement(); + for (String sql : sqls) { + stmt.addBatch(sql + " LIMIT " + flipper.getLimit()); + } + int[] cs = stmt.executeBatch(); + stmt.close(); + for (int cc : cs) { + c += cc; + } + } + } + slowLog(s, sqls); return CompletableFuture.completedFuture(c); } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { @@ -345,7 +379,6 @@ public class DataJdbcSource extends DataSqlSource { st.executeBatch(); } st.close(); - slowLog(s, sql); return CompletableFuture.completedFuture(0); } catch (SQLException e2) { return CompletableFuture.failedFuture(e2); @@ -360,17 +393,29 @@ public class DataJdbcSource extends DataSqlSource { } @Override - protected CompletableFuture clearTableDB(EntityInfo info, final String table, String sql) { + protected CompletableFuture clearTableDB(EntityInfo info, final String[] tables, String... sqls) { Connection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setReadOnly(false); conn.setAutoCommit(true); + int c = 0; final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); + if (sqls.length == 1) { + String sql = sqls[0]; + c = stmt.executeUpdate(sql); + } else { + for (String sql : sqls) { + stmt.addBatch(sql); + } + int[] cs = stmt.executeBatch(); + for (int cc : cs) { + c += cc; + } + } stmt.close(); - slowLog(s, sql); + slowLog(s, sqls); return CompletableFuture.completedFuture(c); } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); @@ -381,21 +426,35 @@ public class DataJdbcSource extends DataSqlSource { } @Override - protected CompletableFuture dropTableDB(EntityInfo info, final String table, String sql) { + protected CompletableFuture dropTableDB(EntityInfo info, String[] tables, String... sqls) { Connection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setReadOnly(false); conn.setAutoCommit(true); + int c = 0; final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); + if (sqls.length == 1) { + String sql = sqls[0]; + c = stmt.executeUpdate(sql); + } else { + for (String sql : sqls) { + stmt.addBatch(sql); + } + int[] cs = stmt.executeBatch(); + for (int cc : cs) { + c += cc; + } + } stmt.close(); if (info.getTableStrategy() != null) { - String tablekey = table.indexOf('.') > 0 ? table : (conn.getCatalog() + '.' + table); - info.removeDisTable(tablekey); + for (String table : tables) { + String tablekey = table.indexOf('.') > 0 ? table : (conn.getCatalog() + '.' + table); + info.removeDisTable(tablekey); + } } - slowLog(s, sql); + slowLog(s, sqls); return CompletableFuture.completedFuture(c); } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); @@ -480,31 +539,51 @@ public class DataJdbcSource extends DataSqlSource { } @Override - protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, String sql, boolean prepared, Object... params) { + protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, SqlInfo sql) { //String sql, boolean prepared, Object... blobs) { Connection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setReadOnly(false); conn.setAutoCommit(true); - if (prepared) { - final PreparedStatement prestmt = conn.prepareStatement(sql); - int index = 0; - for (Object param : params) { - Blob blob = conn.createBlob(); - blob.setBytes(1, (byte[]) param); - prestmt.setBlob(++index, blob); + if (sql.blobs != null || sql.tables != null) { + final PreparedStatement prestmt = conn.prepareStatement(sql.sql); + int c = 0; + if (sql.tables == null) { + int index = 0; + for (byte[] param : sql.blobs) { + Blob blob = conn.createBlob(); + blob.setBytes(1, param); + prestmt.setBlob(++index, blob); + } + c = prestmt.executeUpdate(); + } else { + for (String table : sql.tables) { + int index = 0; + if (sql.blobs != null) { + for (byte[] param : sql.blobs) { + Blob blob = conn.createBlob(); + blob.setBytes(1, param); + prestmt.setBlob(++index, blob); + } + } + prestmt.setString(++index, table); + prestmt.addBatch(); + } + int[] cs = prestmt.executeBatch(); + for (int cc : cs) { + c += cc; + } } - int c = prestmt.executeUpdate(); prestmt.close(); - slowLog(s, sql); + slowLog(s, sql.sql); return CompletableFuture.completedFuture(c); } else { - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); + if (info.isLoggable(logger, Level.FINEST, sql.sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); + int c = stmt.executeUpdate(sql.sql); stmt.close(); - slowLog(s, sql); + slowLog(s, sql.sql); return CompletableFuture.completedFuture(c); } } catch (SQLException e) { @@ -888,9 +967,23 @@ public class DataJdbcSource extends DataSqlSource { final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); if ("mysql".equals(dbtype()) || "postgresql".equals(dbtype())) { //sql可以带limit、offset - final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) - + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) + String listsubsql; + StringBuilder union = new StringBuilder(); + if (tables.length == 1) { + listsubsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(info.getFullQueryColumns(tabalis, selects)).append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + listsubsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM (" + (union) + ") a"; + } + final String listsql = listsubsql + createSQLOrderby(info, flipper) + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())); if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { logger.finest(info.getType().getSimpleName() + " query sql=" + listsql); @@ -905,7 +998,13 @@ public class DataJdbcSource extends DataSqlSource { ps.close(); long total = list.size(); if (needtotal) { - final String countsql = "SELECT " + (distinct ? "DISTINCT COUNT(" + info.getQueryColumns("a", selects) + ")" : "COUNT(*)") + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String countsubsql; + if (tables.length == 1) { + countsubsql = "SELECT " + (distinct ? "DISTINCT COUNT(" + info.getQueryColumns("a", selects) + ")" : "COUNT(*)") + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + countsubsql = "SELECT " + (distinct ? "DISTINCT COUNT(" + info.getQueryColumns("a", selects) + ")" : "COUNT(*)") + " FROM (" + (union) + ") a"; + } + final String countsql = countsubsql; if (readcache && info.isLoggable(logger, Level.FINEST, countsql)) { logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql); } @@ -918,8 +1017,20 @@ public class DataJdbcSource extends DataSqlSource { slowLog(s, listsql); return CompletableFuture.completedFuture(new Sheet<>(total, list)); } - final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) - + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper); + String listsubsql; + StringBuilder union = new StringBuilder(); + if (tables.length == 1) { + listsubsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(distinct ? "DISTINCT " : "").append(info.getFullQueryColumns(tabalis, selects)).append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + listsubsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM (" + (union) + ") a"; + } + final String listsql = listsubsql + info.createSQLOrderby(flipper); if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { logger.finest(info.getType().getSimpleName() + " query sql=" + listsql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()))); } diff --git a/src/main/java/org/redkale/source/DataMemorySource.java b/src/main/java/org/redkale/source/DataMemorySource.java index 4bf49ff86..3f0bb314e 100644 --- a/src/main/java/org/redkale/source/DataMemorySource.java +++ b/src/main/java/org/redkale/source/DataMemorySource.java @@ -120,17 +120,17 @@ public class DataMemorySource extends DataSqlSource implements SearchSource { } @Override - protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) { + protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String... sqls) { return CompletableFuture.completedFuture(0); } @Override - protected CompletableFuture clearTableDB(EntityInfo info, final String table, String sql) { + protected CompletableFuture clearTableDB(EntityInfo info, String[] tables, String... sqls) { return CompletableFuture.completedFuture(0); } @Override - protected CompletableFuture dropTableDB(EntityInfo info, final String table, String sql) { + protected CompletableFuture dropTableDB(EntityInfo info, String[] tables, String... sqls) { return CompletableFuture.completedFuture(0); } @@ -140,7 +140,7 @@ public class DataMemorySource extends DataSqlSource implements SearchSource { } @Override - protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, String sql, boolean prepared, Object... params) { + protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, SqlInfo sql) { return CompletableFuture.completedFuture(0); } diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index 214e0ef88..af7d044c3 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -560,19 +560,19 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected abstract CompletableFuture insertDB(final EntityInfo info, T... entitys); //删除记录 - protected abstract CompletableFuture deleteDB(final EntityInfo info, Flipper flipper, final String sql); + protected abstract CompletableFuture deleteDB(final EntityInfo info, Flipper flipper, final String... sqls); //清空表 - protected abstract CompletableFuture clearTableDB(final EntityInfo info, final String table, final String sql); + protected abstract CompletableFuture clearTableDB(final EntityInfo info, String[] tables, final String... sqls); //删除表 - protected abstract CompletableFuture dropTableDB(final EntityInfo info, final String table, final String sql); + protected abstract CompletableFuture dropTableDB(final EntityInfo info, String[] tables, final String... sqls); //更新纪录 protected abstract CompletableFuture updateEntityDB(final EntityInfo info, T... entitys); //更新纪录 - protected abstract CompletableFuture updateColumnDB(final EntityInfo info, Flipper flipper, final String sql, final boolean prepared, Object... params); + protected abstract CompletableFuture updateColumnDB(final EntityInfo info, Flipper flipper, final SqlInfo sql); //查询Number Map数据 protected abstract CompletableFuture> getNumberMapDB(final EntityInfo info, final String sql, final FilterFuncColumn... columns); @@ -872,7 +872,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi return sql; } - protected String deleteSql(final EntityInfo info, final Flipper flipper, final FilterNode node) { + protected String[] deleteSql(final EntityInfo info, final Flipper flipper, final FilterNode node) { boolean pgsql = "postgresql".equals(dbtype()); Map joinTabalis = null; CharSequence join = null; @@ -889,20 +889,31 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); } - String sql; + if (pgsql && flipper != null && flipper.getLimit() > 0) { String wherestr = ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - sql = "DELETE FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1)) - + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + info.getTable(node) - + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + String[] tables = info.getTables(node); + List sqls = new ArrayList<>(); + for (String table : tables) { + String sql = "DELETE FROM " + table + " a" + (join1 == null ? "" : (", " + join1)) + + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + table + + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + sqls.add(sql); + } + return sqls.toArray(new String[sqls.size()]); } else { - sql = "DELETE " + ("mysql".equals(dbtype()) ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1)) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper) - + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + String[] tables = info.getTables(node); + List sqls = new ArrayList<>(); + for (String table : tables) { + String sql = "DELETE " + ("mysql".equals(dbtype()) ? "a" : "") + " FROM " + table + " a" + (join1 == null ? "" : (", " + join1)) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper) + + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + sqls.add(sql); + } + return sqls.toArray(new String[sqls.size()]); } - return sql; } //----------------------------- clearTableCompose ----------------------------- @@ -947,10 +958,23 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } protected CompletableFuture clearTableCompose(final EntityInfo info, final FilterNode node) { - final String table = info.getTable(node); - String sql = "TRUNCATE TABLE " + table; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " clearTable sql=" + sql); - return clearTableDB(info, table, sql); + final String[] tables = info.getTables(node); + if (tables.length == 1) { + String sql = "TRUNCATE TABLE " + tables[0]; + if (info.isLoggable(logger, Level.FINEST, sql)) { + logger.finest(info.getType().getSimpleName() + " clearTable sql=" + sql); + } + return clearTableDB(info, tables, sql); + } else { + List sqls = new ArrayList<>(); + for (String table : tables) { + sqls.add("TRUNCATE TABLE " + table); + } + if (info.isLoggable(logger, Level.FINEST, sqls.get(0))) { + logger.finest(info.getType().getSimpleName() + " clearTable sqls=" + sqls); + } + return clearTableDB(info, tables, sqls.toArray(new String[sqls.size()])); + } } //----------------------------- dropTableCompose ----------------------------- @@ -990,10 +1014,24 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } protected CompletableFuture dropTableCompose(final EntityInfo info, final FilterNode node) { - final String table = node == null ? info.getOriginTable() : info.getTable(node); - String sql = "DROP TABLE IF EXISTS " + table; - //if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " dropTable sql=" + sql); - return dropTableDB(info, table, sql); + if (node == null) { + final String table = info.getOriginTable(); + String sql = "DROP TABLE IF EXISTS " + table; + //if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " dropTable sql=" + sql); + return dropTableDB(info, new String[]{table}, sql); + } else { + final String[] tables = info.getTables(node); + if (tables.length == 1) { + String sql = "DROP TABLE IF EXISTS " + tables[0]; + return dropTableDB(info, tables, sql); + } else { + List sqls = new ArrayList<>(); + for (String table : tables) { + sqls.add("DROP TABLE IF EXISTS " + table); + } + return dropTableDB(info, tables, sqls.toArray(new String[sqls.size()])); + } + } } protected int clearTableCache(final EntityInfo info, FilterNode node) { @@ -1135,13 +1173,8 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected CompletableFuture updateColumnCompose(final EntityInfo info, Serializable pk, String column, final Serializable colval) { Attribute attr = info.getAttribute(column); - Serializable val = getSQLAttrValue(info, attr, colval); SqlInfo sql = updateSql(info, pk, column, colval); - if (val instanceof byte[]) { - return updateColumnDB(info, null, sql.sql, true, val); - } else { - return updateColumnDB(info, null, sql.sql, false); - } + return updateColumnDB(info, null, sql); } protected SqlInfo updateSql(final EntityInfo info, Serializable pk, String column, final Serializable colval) { @@ -1203,13 +1236,8 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected CompletableFuture updateColumnCompose(final EntityInfo info, final String column, final Serializable colval, final FilterNode node) { Attribute attr = info.getAttribute(column); - Serializable val = getSQLAttrValue(info, attr, colval); SqlInfo sql = updateSql(info, column, colval, node); - if (val instanceof byte[]) { - return updateColumnDB(info, null, sql.sql, true, val); - } else { - return updateColumnDB(info, null, sql.sql, false); - } + return updateColumnDB(info, null, sql); } protected SqlInfo updateSql(final EntityInfo info, final String column, final Serializable colval, final FilterNode node) { @@ -1227,18 +1255,34 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi Attribute attr = info.getAttribute(column); Serializable val = getSQLAttrValue(info, attr, colval); String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql的BUG, UPDATE的SET中不能含别名 + String[] tables = info.getTables(node); + String sql; if (val instanceof byte[]) { - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) - + " SET " + info.getSQLColumn(alias, column) + "=" + prepareParamSign(1) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - return new SqlInfo(sql, (byte[]) val); + if (tables.length == 1) { + sql = "UPDATE " + tables[0] + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + prepareParamSign(1) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + } else { + sql = "UPDATE " + prepareParamSign(2) + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + prepareParamSign(1) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + } + return new SqlInfo(sql, tables.length == 1 ? null : tables, (byte[]) val); } else { - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) - + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(val, sqlFormatter) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - return new SqlInfo(sql); + if (tables.length == 1) { + sql = "UPDATE " + tables[0] + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(val, sqlFormatter) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + } else { + sql = "UPDATE " + prepareParamSign(1) + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(val, sqlFormatter) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + } + return new SqlInfo(sql, tables.length == 1 ? null : tables); } } @@ -1291,11 +1335,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected CompletableFuture updateColumnCompose(final EntityInfo info, final Serializable pk, final ColumnValue... values) { SqlInfo sql = updateSql(info, pk, values); - if (sql.blobs == null || sql.blobs.isEmpty()) { - return updateColumnDB(info, null, sql.sql, false); - } else { - return updateColumnDB(info, null, sql.sql, true, sql.blobs.toArray()); - } + return updateColumnDB(info, null, sql); } protected SqlInfo updateSql(final EntityInfo info, final Serializable pk, final ColumnValue... values) { @@ -1360,11 +1400,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected CompletableFuture updateColumnCompose(final EntityInfo info, final FilterNode node, final Flipper flipper, final ColumnValue... values) { SqlInfo sql = updateSql(info, node, flipper, values); - if (sql.blobs == null || sql.blobs.isEmpty()) { - return updateColumnDB(info, flipper, sql.sql, false); - } else { - return updateColumnDB(info, flipper, sql.sql, true, sql.blobs.toArray()); - } + return updateColumnDB(info, flipper, sql); } protected SqlInfo updateSql(final EntityInfo info, final FilterNode node, final Flipper flipper, final ColumnValue... values) { @@ -1399,20 +1435,37 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); } String sql; + String[] tables = info.getTables(node); if (pgsql && flipper != null && flipper.getLimit() > 0) { String wherestr = ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql - + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + info.getTable(node) - + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + if (tables.length == 1) { + sql = "UPDATE " + tables[0] + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + tables[0] + + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + } else { + String sign = prepareParamSign(++index); + sql = "UPDATE " + sign + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + sign + + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + } } else { - sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) - + info.createSQLOrderby(flipper) - + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + if (tables.length == 1) { + sql = "UPDATE " + tables[0] + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + + info.createSQLOrderby(flipper) + + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + } else { + String sign = prepareParamSign(++index); + sql = "UPDATE " + sign + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + + info.createSQLOrderby(flipper) + + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + } } - return new SqlInfo(sql, blobs); + return new SqlInfo(sql, tables.length == 1 ? null : tables, blobs); } //返回不存在的字段名,null表示字段都合法; @@ -1522,11 +1575,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected CompletableFuture updateColumnCompose(final EntityInfo info, final boolean needNode, final T entity, final FilterNode node, final SelectColumn selects) { SqlInfo sql = updateSql(info, needNode, entity, node, selects); - if (sql.blobs == null || sql.blobs.isEmpty()) { - return updateColumnDB(info, null, sql.sql, false); - } else { - return updateColumnDB(info, null, sql.sql, true, sql.blobs.toArray()); - } + return updateColumnDB(info, null, sql); } protected SqlInfo updateSql(final EntityInfo info, final boolean needNode, final T entity, final FilterNode node, final SelectColumn selects) { @@ -1560,10 +1609,20 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); } - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - return new SqlInfo(sql, blobs); + String sql; + String[] tables = info.getTables(node); + if (tables.length == 1) { + sql = "UPDATE " + tables[0] + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + return new SqlInfo(sql, blobs); + } else { + String sign = prepareParamSign(++index); + sql = "UPDATE " + sign + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + return new SqlInfo(sql, tables, blobs); + } } else { final Serializable id = (Serializable) info.getSQLValue(info.getPrimary(), entity); String sql = "UPDATE " + info.getTable(id) + " a SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(id, sqlFormatter); @@ -1817,8 +1876,23 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); final String funcSqlColumn = func == null ? info.getSQLColumn("a", funcColumn) : func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : info.getSQLColumn("a", funcColumn))); - final String sql = "SELECT a." + keySqlColumn + ", " + funcSqlColumn - + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + keySqlColumn; + + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String sql; + if (tables.length == 1) { + sql = "SELECT a." + keySqlColumn + ", " + funcSqlColumn + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + StringBuilder union = new StringBuilder(); + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(tabalis).append(".").append(keySqlColumn).append(", ").append(funcSqlColumn.replace("a.", tabalis + ".")) + .append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + sql = "SELECT a." + keySqlColumn + ", " + funcSqlColumn + " FROM (" + (union) + ") a"; + } if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); return queryColumnMapDB(info, sql, keyColumn); } @@ -1899,9 +1973,29 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi final Set haset = new HashSet<>(); final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - String sql = "SELECT "; - if (groupBySqlColumns.length() > 0) sql += groupBySqlColumns + ", "; - sql += funcSqlColumns + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String sql; + if (tables.length == 1) { + sql = "SELECT "; + if (groupBySqlColumns.length() > 0) sql += groupBySqlColumns + ", "; + sql += funcSqlColumns + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + StringBuilder union = new StringBuilder(); + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + String subsql = "SELECT "; + if (groupBySqlColumns.length() > 0) subsql += groupBySqlColumns.toString().replace("a.", tabalis + ".") + ", "; + subsql += funcSqlColumns.toString().replace("a.", tabalis + ".") + " FROM " + table + " " + tabalis + joinAndWhere; + union.append(subsql); + } + sql = "SELECT "; + if (groupBySqlColumns.length() > 0) sql += groupBySqlColumns + ", "; + sql += funcSqlColumns + " FROM (" + (union) + ") a"; + } if (groupBySqlColumns.length() > 0) sql += " GROUP BY " + groupBySqlColumns; if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); return queryColumnMapDB(info, sql, funcNodes, groupByColumns); @@ -2030,7 +2124,21 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String sql; + if (tables.length == 1) { + sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + StringBuilder union = new StringBuilder(); + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(info.getQueryColumns(tabalis, selects)).append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM (" + (union) + ") a"; + } if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); return findDB(info, sql, false, selects); } @@ -2100,7 +2208,21 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String sql; + if (tables.length == 1) { + sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + StringBuilder union = new StringBuilder(); + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(info.getSQLColumn(tabalis, column)).append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + sql = "SELECT " + info.getSQLColumn("a", column) + " FROM (" + (union) + ") a"; + } if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); return findColumnDB(info, sql, false, column, defValue); } @@ -2175,7 +2297,21 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi final Map joinTabalis = node == null ? null : node.getJoinTabalis(); final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String[] tables = info.getTables(node); + String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + String sql; + if (tables.length == 1) { + sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + tables[0] + " a" + joinAndWhere; + } else { + int b = 0; + StringBuilder union = new StringBuilder(); + for (String table : tables) { + if (!union.isEmpty()) union.append(" UNION ALL "); + String tabalis = "t" + (++b); + union.append("SELECT ").append(info.getPrimarySQLColumn(tabalis)).append(" FROM ").append(table).append(" ").append(tabalis).append(joinAndWhere); + } + sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM (" + (union) + ") a"; + } if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); return existsDB(info, sql, false); } @@ -2406,12 +2542,23 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected static class SqlInfo { - public String sql; + public String sql; //prepare-sql时表名参数只能是最后一个 - public List blobs; + public String[] tables; + + public List blobs; //要么null,要么有内容,不能是empty-list public SqlInfo(String sql, byte[]... blobs) { + this(sql, null, blobs); + } + + public SqlInfo(String sql, List blobs) { + this(sql, null, blobs); + } + + public SqlInfo(String sql, String[] tables, byte[]... blobs) { this.sql = sql; + this.tables = tables; if (blobs.length > 0) { this.blobs = new ArrayList<>(); for (byte[] bs : blobs) { @@ -2420,9 +2567,10 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } } - public SqlInfo(String sql, List blobs) { + public SqlInfo(String sql, String[] tables, List blobs) { this.sql = sql; - this.blobs = blobs; + this.tables = tables; + this.blobs = blobs.isEmpty() ? null : blobs; } } diff --git a/src/main/java/org/redkale/source/DistributeTableStrategy.java b/src/main/java/org/redkale/source/DistributeTableStrategy.java index 5bce05353..5f5b5953f 100644 --- a/src/main/java/org/redkale/source/DistributeTableStrategy.java +++ b/src/main/java/org/redkale/source/DistributeTableStrategy.java @@ -47,11 +47,31 @@ public interface DistributeTableStrategy { * 查询、修改、删除对象(DataSource.find、DataSource.query、DataSource.delete、DataSource.update)时调用本方法获取表名
* 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中
* + * @deprecated 2.8.0 replaced by getTables(String table, FilterNode node) + * * @param table 模板表的表名 * @param node 过滤条件 * * @return 带库名的全表名 */ - public String getTable(String table, FilterNode node); + @Deprecated + default String getTable(String table, FilterNode node) { + return getTables(table, node)[0]; + } + + /** + * 获取对象的表名
+ * 查询、修改、删除对象(DataSource.find、DataSource.query、DataSource.delete、DataSource.update)时调用本方法获取表名
+ * + * @param table 模板表的表名 + * @param node 过滤条件 + * + * @return 带库名的全表名 + * + * @since 2.8.0 + */ + default String[] getTables(String table, FilterNode node) { + return new String[]{getTable(table, node)}; + } } diff --git a/src/main/java/org/redkale/source/EntityInfo.java b/src/main/java/org/redkale/source/EntityInfo.java index 9d1eca87e..8d1479387 100644 --- a/src/main/java/org/redkale/source/EntityInfo.java +++ b/src/main/java/org/redkale/source/EntityInfo.java @@ -959,10 +959,10 @@ public final class EntityInfo { * * @return String */ - public String getTable(FilterNode node) { - if (tableStrategy == null) return table; - String t = tableStrategy.getTable(table, node); - return t == null || t.isEmpty() ? table : t; + public String[] getTables(FilterNode node) { + if (tableStrategy == null) return new String[]{table}; + String[] t = tableStrategy.getTables(table, node); + return t == null || t.length == 0 ? new String[]{table} : t; } /** diff --git a/src/main/java/org/redkale/source/FilterJoinNode.java b/src/main/java/org/redkale/source/FilterJoinNode.java index 37a60b39d..61a577280 100644 --- a/src/main/java/org/redkale/source/FilterJoinNode.java +++ b/src/main/java/org/redkale/source/FilterJoinNode.java @@ -331,7 +331,9 @@ public class FilterJoinNode extends FilterNode { @Override protected void putJoinTabalis(Map map) { - if (this.joinClass != null && !map.containsKey(this.joinClass)) map.put(joinClass, String.valueOf((char) ('b' + map.size()))); + if (this.joinClass != null && !map.containsKey(this.joinClass)) { + map.put(joinClass, "jt" + map.size()); //join_table_1 + } if (this.nodes == null) return; for (FilterNode node : this.nodes) { node.putJoinTabalis(map);