/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.redkale.source; import java.io.Serializable; import java.sql.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Stream; import org.redkale.annotation.AutoLoad; import org.redkale.annotation.ResourceListener; import org.redkale.annotation.ResourceType; import org.redkale.service.Local; import org.redkale.util.*; /** * DataSource的JDBC实现类 * *

* 详情见: https://redkale.org * * @author zhangjx */ @Local @AutoLoad(false) @SuppressWarnings("unchecked") @ResourceType(DataSource.class) public class DataJdbcSource extends AbstractDataSqlSource { protected ConnectionPool readPool; protected ConnectionPool writePool; public DataJdbcSource() { super(); } @Override public void init(AnyValue conf) { super.init(conf); this.readPool = new ConnectionPool(readConfProps); if (readConfProps == writeConfProps) { this.writePool = readPool; } else { this.writePool = new ConnectionPool(writeConfProps); } } @Override protected void updateOneResourceChange(Properties newProps, ResourceEvent[] events) { this.readPool.onResourceChange(events); } @Override protected void updateReadResourceChange(Properties newReadProps, ResourceEvent[] events) { this.readPool.onResourceChange(events); } @Override protected void updateWriteResourceChange(Properties newWriteProps, ResourceEvent[] events) { this.writePool.onResourceChange(events); } @Override protected int readMaxConns() { return this.readPool.maxConns; } @Override protected int writeMaxConns() { return this.writePool.maxConns; } @Override public void destroy(AnyValue config) { if (readPool != null) { readPool.close(); } if (writePool != null && writePool != readPool) { writePool.close(); } } @Override public void close() throws Exception { super.close(); if (readPool != null) { readPool.close(); } if (writePool != null && writePool != readPool) { writePool.close(); } } public static boolean acceptsConf(AnyValue conf) { try { AnyValue read = conf.getAnyValue("read"); AnyValue node = read == null ? conf : read; final Class driverClass = DriverManager.getDriver(node.getValue(DATA_SOURCE_URL)).getClass(); RedkaleClassLoader.putReflectionDeclaredConstructors(driverClass, driverClass.getName()); RedkaleClassLoader.putServiceLoader(java.sql.Driver.class); } catch (Exception e) { return false; } return true; } protected ConnectionPool readPool() { return readPool; } protected ConnectionPool writePool() { return writePool; } @Override protected final String prepareParamSign(int index) { return "?"; } @Override protected final boolean isAsync() { return false; } protected List prepareInsertEntityStatements(SourceConnection conn, EntityInfo info, Map> prepareInfos, T... entitys) throws SQLException { Attribute[] attrs = info.insertAttributes; final List prestmts = new ArrayList<>(); for (Map.Entry> en : prepareInfos.entrySet()) { PrepareInfo prepareInfo = en.getValue(); PreparedStatement prestmt = conn.prepareUpdateStatement(prepareInfo.prepareSql); for (final T value : prepareInfo.entitys) { bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.addBatch(); } prestmts.add(prestmt); } return prestmts; } protected PreparedStatement prepareInsertEntityStatement(SourceConnection conn, String sql, EntityInfo info, T... entitys) throws SQLException { Attribute[] attrs = info.insertAttributes; final PreparedStatement prestmt = conn.prepareUpdateStatement(sql); for (final T value : entitys) { bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.addBatch(); } return prestmt; } protected List prepareUpdateEntityStatements(SourceConnection conn, EntityInfo info, Map> prepareInfos, T... entitys) throws SQLException { Attribute primary = info.primary; Attribute[] attrs = info.updateAttributes; final List prestmts = new ArrayList<>(); for (Map.Entry> en : prepareInfos.entrySet()) { PrepareInfo prepareInfo = en.getValue(); PreparedStatement prestmt = conn.prepareUpdateStatement(prepareInfo.prepareSql); for (final T value : prepareInfo.entitys) { int k = bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.setObject(++k, primary.get(value)); prestmt.addBatch(); } prestmts.add(prestmt); } return prestmts; } protected PreparedStatement prepareUpdateEntityStatement(SourceConnection conn, String prepareSQL, EntityInfo info, T... entitys) throws SQLException { Attribute primary = info.primary; Attribute[] attrs = info.updateAttributes; final PreparedStatement prestmt = conn.prepareUpdateStatement(prepareSQL); for (final T value : entitys) { int k = bindStatementParameters(conn, prestmt, info, attrs, value); prestmt.setObject(++k, primary.get(value)); prestmt.addBatch(); } return prestmt; } protected int bindStatementParameters(SourceConnection conn, PreparedStatement prestmt, EntityInfo info, Attribute[] attrs, T entity) throws SQLException { int i = 0; for (Attribute attr : attrs) { Object val = getEntityAttrValue(info, attr, entity); if (val instanceof byte[]) { Blob blob = conn.createBlob(); blob.setBytes(1, (byte[]) val); prestmt.setObject(++i, blob); } else if (val instanceof Boolean) { prestmt.setObject(++i, ((Boolean) val) ? (byte) 1 : (byte) 0); } else if (val instanceof AtomicInteger) { prestmt.setObject(++i, ((AtomicInteger) val).get()); } else if (val instanceof AtomicLong) { prestmt.setObject(++i, ((AtomicLong) val).get()); } else { prestmt.setObject(++i, val); } } return i; } @Override public int batch(final DataBatch batch) { Objects.requireNonNull(batch); final DefaultDataBatch dataBatch = (DefaultDataBatch) batch; if (dataBatch.actions.isEmpty()) { return 0; } int c = 0; SourceConnection conn = null; try { conn = writePool.pollTransConnection(); conn.setAutoCommit(false); for (BatchAction action : dataBatch.actions) { if (action instanceof RunnableBatchAction) { RunnableBatchAction act = (RunnableBatchAction) action; act.task.run(); } else if (action instanceof InsertBatchAction1) { InsertBatchAction1 act = (InsertBatchAction1) action; EntityInfo info = apply(act.entity.getClass()); c += insertDBStatement(true, conn, info, act.entity); } else if (action instanceof DeleteBatchAction1) { DeleteBatchAction1 act = (DeleteBatchAction1) action; EntityInfo info = apply(act.entity.getClass()); Serializable pk = info.getPrimaryValue(act.entity); Map> pkmap = info.getTableMap(pk); String[] tables = pkmap.keySet().toArray(new String[pkmap.size()]); String[] sqls = deleteSql(info, pkmap); c += deleteDBStatement(true, conn, info, tables, null, null, pkmap, sqls); } else if (action instanceof DeleteBatchAction2) { DeleteBatchAction2 act = (DeleteBatchAction2) action; EntityInfo info = apply(act.clazz); Map> pkmap = info.getTableMap(act.pk); String[] tables = pkmap.keySet().toArray(new String[pkmap.size()]); String[] sqls = deleteSql(info, pkmap); c += deleteDBStatement(true, conn, info, tables, null, null, pkmap, sqls); } else if (action instanceof DeleteBatchAction3) { DeleteBatchAction3 act = (DeleteBatchAction3) action; EntityInfo info = apply(act.clazz); String[] tables = info.getTables(act.node); String[] sqls = deleteSql(info, tables, act.flipper, act.node); c += deleteDBStatement(true, conn, info, tables, act.flipper, act.node, null, sqls); } else if (action instanceof UpdateBatchAction1) { UpdateBatchAction1 act = (UpdateBatchAction1) action; EntityInfo info = apply(act.entity.getClass()); c += updateEntityDBStatement(true, conn, info, act.entity); } else if (action instanceof UpdateBatchAction2) { UpdateBatchAction2 act = (UpdateBatchAction2) action; EntityInfo info = apply(act.clazz); UpdateSqlInfo sql = updateColumnSql(info, act.pk, act.values); c += updateColumnDBStatement(true, conn, info, null, sql); } else if (action instanceof UpdateBatchAction3) { UpdateBatchAction3 act = (UpdateBatchAction3) action; EntityInfo info = apply(act.clazz); UpdateSqlInfo sql = updateColumnSql(info, act.node, act.flipper, act.values); c += updateColumnDBStatement(true, conn, info, act.flipper, sql); } else if (action instanceof UpdateBatchAction4) { UpdateBatchAction4 act = (UpdateBatchAction4) action; EntityInfo info = apply(act.entity.getClass()); UpdateSqlInfo sql = updateColumnSql(info, false, act.entity, act.node, act.selects); c += updateColumnDBStatement(true, conn, info, null, sql); } } conn.commit(); return c; } catch (SourceException se) { if (conn != null) { try { conn.rollback(); } catch (SQLException sqe) { } } throw se; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerTransConnection(conn); } } } @Override public CompletableFuture batchAsync(final DataBatch batch) { return supplyAsync(() -> batch(batch)); } @Override protected CompletableFuture insertDBAsync(EntityInfo info, T... entitys) { return supplyAsync(() -> insertDB(info, entitys)); } @Override protected int insertDB(EntityInfo info, T... entitys) { SourceConnection conn = null; try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c = insertDBStatement(false, conn, info, entitys); conn.commit(); return c; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } private int insertDBStatement(final boolean batch, final SourceConnection conn, final EntityInfo info, T... entitys) throws SQLException { final long s = System.currentTimeMillis(); int c = 0; String presql = null; PreparedStatement prestmt = null; List prestmts = null; Map> prepareInfos = null; Attribute[] attrs = info.insertAttributes; if (info.getTableStrategy() == null) { //单库单表 presql = info.getInsertQuestionPrepareSQL(entitys[0]); prestmt = prepareInsertEntityStatement(conn, presql, info, entitys); } else { //分库分表 prepareInfos = getInsertQuestionPrepareInfo(info, entitys); prestmts = prepareInsertEntityStatements(conn, info, prepareInfos, entitys); } try { if (info.getTableStrategy() == null) { //单库单表 c = Utility.sum(prestmt.executeBatch()); conn.offerUpdateStatement(prestmt); } else { //分库分表 int c1 = 0; for (PreparedStatement stmt : prestmts) { c1 += Utility.sum(stmt.executeBatch()); } c = c1; for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } } if (!batch) { conn.commit(); } } catch (SQLException se) { if (!batch) { conn.rollback(); } if (!isTableNotExist(info, se.getSQLState())) { throw se; } if (info.getTableStrategy() == null) { //单库单表 String[] tableSqls = createTableSqls(info); if (tableSqls == null) { throw se; } //创建单表结构 Statement stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); } else { //分库分表 info.disTableLock().lock(); try { final Set newCatalogs = new LinkedHashSet<>(); final List tableCopys = new ArrayList<>(); prepareInfos.forEach((t, p) -> { int pos = t.indexOf('.'); if (pos > 0) { newCatalogs.add(t.substring(0, pos)); } tableCopys.add(getTableCopySQL(info, t)); }); try { //执行一遍创建分表操作 Statement stmt = conn.createUpdateStatement(); for (String copySql : tableCopys) { stmt.addBatch(copySql); } stmt.executeBatch(); conn.offerUpdateStatement(stmt); } catch (SQLException sqle) { //多进程并发时可能会出现重复建表 if (isTableNotExist(info, sqle.getSQLState())) { if (newCatalogs.isEmpty()) { //分表的原始表不存在 String[] tableSqls = createTableSqls(info); if (tableSqls != null) { //创建原始表 Statement stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); //再执行一遍创建分表操作 stmt = conn.createUpdateStatement(); for (String copySql : tableCopys) { stmt.addBatch(copySql); } stmt.executeBatch(); conn.offerUpdateStatement(stmt); } } else { //需要先建库 Statement stmt; try { stmt = conn.createUpdateStatement(); for (String newCatalog : newCatalogs) { stmt.addBatch(("postgresql".equals(dbtype()) ? "CREATE SCHEMA IF NOT EXISTS " : "CREATE DATABASE IF NOT EXISTS ") + newCatalog); } stmt.executeBatch(); conn.offerUpdateStatement(stmt); } catch (SQLException sqle1) { logger.log(Level.SEVERE, "create database " + tableCopys + " error", sqle1); } try { //再执行一遍创建分表操作 stmt = conn.createUpdateStatement(); for (String copySql : tableCopys) { stmt.addBatch(copySql); } stmt.executeBatch(); conn.offerUpdateStatement(stmt); } catch (SQLException sqle2) { if (isTableNotExist(info, sqle2.getSQLState())) { String[] tableSqls = createTableSqls(info); if (tableSqls != null) { //创建原始表 stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); //再执行一遍创建分表操作 stmt = conn.createUpdateStatement(); for (String copySql : tableCopys) { stmt.addBatch(copySql); } stmt.executeBatch(); conn.offerUpdateStatement(stmt); } } else { logger.log(Level.SEVERE, "create table2 " + tableCopys + " error", sqle2); } } } } } } finally { info.disTableLock().unlock(); } } if (info.getTableStrategy() == null) { //单库单表 conn.offerUpdateStatement(prestmt); prestmt = prepareInsertEntityStatement(conn, presql, info, entitys); c = Utility.sum(prestmt.executeBatch()); conn.offerUpdateStatement(prestmt); } else { //分库分表 for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } prestmts = prepareInsertEntityStatements(conn, info, prepareInfos, entitys); int c1 = 0; for (PreparedStatement stmt : prestmts) { c1 += Utility.sum(stmt.executeBatch()); } c = c1; for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } } } //------------------------------------------------------------ if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息 if (info.getTableStrategy() == null) { char[] sqlchars = presql.toCharArray(); for (final T value : entitys) { //----------------------------- StringBuilder sb = new StringBuilder(128); int i = 0; for (char ch : sqlchars) { if (ch == '?') { Object obj = info.getSQLValue(attrs[i++], value); if (obj != null && obj.getClass().isArray()) { sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); } else { sb.append(info.formatSQLValue(obj, sqlFormatter)); } } else { sb.append(ch); } } String debugsql = sb.toString(); if (info.isLoggable(logger, Level.FINEST, debugsql)) { logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); } } } else { prepareInfos.forEach((t, p) -> { char[] sqlchars = p.prepareSql.toCharArray(); for (final T value : p.entitys) { //----------------------------- StringBuilder sb = new StringBuilder(128); int i = 0; for (char ch : sqlchars) { if (ch == '?') { Object obj = info.getSQLValue(attrs[i++], value); if (obj != null && obj.getClass().isArray()) { sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); } else { sb.append(info.formatSQLValue(obj, sqlFormatter)); } } else { sb.append(ch); } } String debugsql = sb.toString(); if (info.isLoggable(logger, Level.FINEST, debugsql)) { logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); } } }); } } //打印结束 if (info.getTableStrategy() == null) { slowLog(s, presql); } else { List presqls = new ArrayList<>(); prepareInfos.forEach((t, p) -> { presqls.add(p.prepareSql); }); slowLog(s, presqls.toArray(new String[presqls.size()])); } return c; } @Override protected CompletableFuture deleteDBAsync(final EntityInfo info, String[] tables, Flipper flipper, FilterNode node, Map> pkmap, final String... sqls) { return supplyAsync(() -> deleteDB(info, tables, flipper, node, pkmap, sqls)); } @Override protected int deleteDB(EntityInfo info, String[] tables, Flipper flipper, FilterNode node, Map> pkmap, String... sqls) { SourceConnection conn = null; try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c = deleteDBStatement(false, conn, info, tables, flipper, node, pkmap, sqls); conn.commit(); return c; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } private int deleteDBStatement(final boolean batch, final SourceConnection conn, final EntityInfo info, String[] tables, Flipper flipper, FilterNode node, Map> pkmap, String... sqls) throws SQLException { final long s = System.currentTimeMillis(); try { int c; if (sqls.length == 1) { final Statement stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(sqls[0]); conn.offerUpdateStatement(stmt); } else { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } if (!batch) { conn.commit(); } slowLog(s, sqls); return c; } catch (SQLException e) { if (!batch) { try { conn.rollback(); } catch (SQLException se) { } } if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { String[] tableSqls = createTableSqls(info); if (tableSqls != null) { Statement stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); return 0; } //单表结构不存在 return 0; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return 0; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw e; // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw e; } for (String t : notExistTables) { if (pkmap != null) { pkmap.remove(t); } else { tables = Utility.remove(tables, t); } } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "delete, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + (pkmap != null ? pkmap.keySet() : Arrays.toString(tables))); } if ((pkmap != null ? pkmap.size() : tables.length) == 0) { //分表全部不存在 return 0; } sqls = pkmap != null ? deleteSql(info, pkmap) : deleteSql(info, tables, flipper, node); if (info.isLoggable(logger, Level.FINEST, sqls[0])) { logger.finest(info.getType().getSimpleName() + " delete sql=" + Arrays.toString(sqls)); } try { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } int c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); conn.commit(); slowLog(s, sqls); return c; } catch (SQLException se) { throw se; } } else { throw e; } } throw e; } } @Override protected CompletableFuture clearTableDBAsync(EntityInfo info, final String[] tables, FilterNode node, String... sqls) { return supplyAsync(() -> clearTableDB(info, tables, node, sqls)); } @Override protected int clearTableDB(EntityInfo info, String[] tables, FilterNode node, String... sqls) { SourceConnection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c; if (sqls.length == 1) { final Statement stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(sqls[0]); conn.offerUpdateStatement(stmt); } else { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } conn.commit(); slowLog(s, sqls); return c; } catch (SQLException e) { try { conn.rollback(); } catch (SQLException se) { } if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //单表结构不存在 return 0; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return 0; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "clearTable, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return 0; } sqls = clearTableSql(info, tables, node); if (info.isLoggable(logger, Level.FINEST, sqls[0])) { logger.finest(info.getType().getSimpleName() + " clearTable sql=" + Arrays.toString(sqls)); } try { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } int c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); conn.commit(); slowLog(s, sqls); return c; } catch (SQLException se) { throw new SourceException(se); } } else { throw new SourceException(e); } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } @Override protected CompletableFuture createTableDBAsync(EntityInfo info, String copyTableSql, final Serializable pk, String... sqls) { return supplyAsync(() -> createTableDB(info, copyTableSql, pk, sqls)); } @Override protected CompletableFuture dropTableDBAsync(EntityInfo info, final String[] tables, FilterNode node, String... sqls) { return supplyAsync(() -> dropTableDB(info, tables, node, sqls)); } @Override protected int createTableDB(EntityInfo info, String copyTableSql, Serializable pk, String... sqls) { SourceConnection conn = null; Statement stmt; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c; if (copyTableSql == null) { if (sqls.length == 1) { stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(sqls[0]); conn.offerUpdateStatement(stmt); } else { stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } } else { //建分表 try { stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(copyTableSql); } catch (SQLException se) { if (isTableNotExist(info, se.getSQLState())) { //分表的原始表不存在 final String newTable = info.getTable(pk); if (newTable.indexOf('.') <= 0) { //分表的原始表不存在 if (info.isLoggable(logger, Level.FINEST, sqls[0])) { logger.finest(info.getType().getSimpleName() + " createTable sql=" + Arrays.toString(sqls)); } //创建原始表 stmt = conn.createUpdateStatement(); if (sqls.length == 1) { stmt.execute(sqls[0]); } else { for (String tableSql : sqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); //再执行一遍创建分表操作 if (info.isLoggable(logger, Level.FINEST, copyTableSql)) { logger.finest(info.getType().getSimpleName() + " createTable sql=" + copyTableSql); } stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(copyTableSql); conn.offerUpdateStatement(stmt); } else { //需要先建库 String newCatalog = newTable.substring(0, newTable.indexOf('.')); String catalogSql = ("postgresql".equals(dbtype()) ? "CREATE SCHEMA IF NOT EXISTS " : "CREATE DATABASE IF NOT EXISTS ") + newCatalog; try { if (info.isLoggable(logger, Level.FINEST, catalogSql)) { logger.finest(info.getType().getSimpleName() + " createCatalog sql=" + catalogSql); } stmt = conn.createUpdateStatement(); stmt.executeUpdate(catalogSql); conn.offerUpdateStatement(stmt); } catch (SQLException sqle1) { logger.log(Level.SEVERE, "create database " + copyTableSql + " error", sqle1); } try { //再执行一遍创建分表操作 if (info.isLoggable(logger, Level.FINEST, copyTableSql)) { logger.finest(info.getType().getSimpleName() + " createTable sql=" + copyTableSql); } stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(copyTableSql); conn.offerUpdateStatement(stmt); } catch (SQLException sqle2) { if (isTableNotExist(info, sqle2.getSQLState())) { if (info.isLoggable(logger, Level.FINEST, sqls[0])) { logger.finest(info.getType().getSimpleName() + " createTable sql=" + Arrays.toString(sqls)); } //创建原始表 stmt = conn.createUpdateStatement(); if (sqls.length == 1) { stmt.execute(sqls[0]); } else { for (String tableSql : sqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); //再执行一遍创建分表操作 if (info.isLoggable(logger, Level.FINEST, copyTableSql)) { logger.finest(info.getType().getSimpleName() + " createTable sql=" + copyTableSql); } stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(copyTableSql); conn.offerUpdateStatement(stmt); } else { throw new SourceException(sqle2); } } } } throw new SourceException(se); } } conn.commit(); slowLog(s, sqls); return c; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } @Override protected int dropTableDB(EntityInfo info, String[] tables, FilterNode node, String... sqls) { SourceConnection conn = null; final long s = System.currentTimeMillis(); try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c; if (sqls.length == 1) { final Statement stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(sqls[0]); conn.offerUpdateStatement(stmt); } else { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } conn.commit(); slowLog(s, sqls); return c; } catch (SQLException e) { try { conn.rollback(); } catch (SQLException se) { } if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //单表结构不存在 return 0; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return 0; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "dropTable, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return 0; } sqls = dropTableSql(info, tables, node); if (info.isLoggable(logger, Level.FINEST, sqls[0])) { logger.finest(info.getType().getSimpleName() + " dropTable sql=" + Arrays.toString(sqls)); } try { final Statement stmt = conn.createUpdateStatement(); for (String sql : sqls) { stmt.addBatch(sql); } int c = Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); conn.commit(); slowLog(s, sqls); return c; } catch (SQLException se) { throw new SourceException(se); } } else { throw new SourceException(e); } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } @Override protected CompletableFuture updateEntityDBAsync(EntityInfo info, T... entitys) { return supplyAsync(() -> updateEntityDB(info, entitys)); } @Override protected int updateEntityDB(EntityInfo info, T... entitys) { SourceConnection conn = null; try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c = updateEntityDBStatement(false, conn, info, entitys); conn.commit(); return c; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } private int updateEntityDBStatement(final boolean batch, final SourceConnection conn, final EntityInfo info, T... entitys) throws SQLException { final long s = System.currentTimeMillis(); String presql = null; String caseSql = null; PreparedStatement prestmt = null; List prestmts = null; Map> prepareInfos = null; int c = -1; final Attribute[] attrs = info.updateAttributes; try { if (info.getTableStrategy() == null) { caseSql = info.getUpdateQuestionPrepareCaseSQL(entitys); if (caseSql == null) { presql = info.getUpdateQuestionPrepareSQL(entitys[0]); prestmt = prepareUpdateEntityStatement(conn, presql, info, entitys); } else { presql = caseSql; prestmt = conn.prepareUpdateStatement(presql); int len = entitys.length; final Attribute primary = info.getPrimary(); Attribute otherAttr = attrs[0]; //UPDATE twointrecord SET randomNumber = ( CASE WHEN id = ? THEN ? WHEN id = ? THEN ? WHEN id = ? THEN ? END ) WHERE id IN (?,?,?) for (int i = 0; i < entitys.length; i++) { Serializable pk = primary.get(entitys[i]); prestmt.setObject(i * 2 + 1, pk); //1 3 5 prestmt.setObject(i * 2 + 2, getEntityAttrValue(info, otherAttr, entitys[i])); //2 4 6 prestmt.setObject(len * 2 + i + 1, pk); //7 8 9 } prestmt.addBatch(); } int c1 = 0; int[] pc = prestmt.executeBatch(); for (int p : pc) { if (p >= 0) { c1 += p; } } c = c1; conn.offerUpdateStatement(prestmt); } else { prepareInfos = getUpdateQuestionPrepareInfo(info, entitys); prestmts = prepareUpdateEntityStatements(conn, info, prepareInfos, entitys); int c1 = 0; for (PreparedStatement stmt : prestmts) { int[] cs = stmt.executeBatch(); for (int cc : cs) { c1 += cc; } } c = c1; for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } } if (!batch) { conn.commit(); } } catch (SQLException se) { if (!batch) { conn.rollback(); } if (isTableNotExist(info, se.getSQLState())) { if (info.getTableStrategy() == null) { String[] tableSqls = createTableSqls(info); if (tableSqls != null) { try { Statement stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); } catch (SQLException e2) { } } //表不存在,更新条数为0 return 0; } else { //String tableName = parseNotExistTableName(se); if (prepareInfos == null) { throw se; } for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } String[] oldTables = prepareInfos.keySet().toArray(new String[prepareInfos.size()]); List notExistTables = checkNotExistTables(conn, oldTables); if (notExistTables.isEmpty()) { throw se; } for (String t : notExistTables) { prepareInfos.remove(t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "update entitys, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + prepareInfos.keySet()); } if (prepareInfos.isEmpty()) { //分表全部不存在 return 0; } prestmts = prepareUpdateEntityStatements(conn, info, prepareInfos, entitys); int c1 = 0; for (PreparedStatement stmt : prestmts) { c1 += Utility.sum(stmt.executeBatch()); } c = c1; for (PreparedStatement stmt : prestmts) { conn.offerUpdateStatement(stmt); } conn.commit(); } } else { throw se; } } if (info.isLoggable(logger, Level.FINEST) && caseSql == null) { //打印调试信息 Attribute primary = info.getPrimary(); if (info.getTableStrategy() == null) { char[] sqlchars = presql.toCharArray(); for (final T value : entitys) { //----------------------------- StringBuilder sb = new StringBuilder(128); int i = 0; for (char ch : sqlchars) { if (ch == '?') { Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value); if (obj != null && obj.getClass().isArray()) { sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); } else { sb.append(info.formatSQLValue(obj, sqlFormatter)); } } else { sb.append(ch); } } String debugsql = sb.toString(); if (info.isLoggable(logger, Level.FINEST, debugsql)) { logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); } } } else { prepareInfos.forEach((t, p) -> { char[] sqlchars = p.prepareSql.toCharArray(); for (final T value : p.entitys) { //----------------------------- StringBuilder sb = new StringBuilder(128); int i = 0; for (char ch : sqlchars) { if (ch == '?') { Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value); if (obj != null && obj.getClass().isArray()) { sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); } else { sb.append(info.formatSQLValue(obj, sqlFormatter)); } } else { sb.append(ch); } } String debugsql = sb.toString(); if (info.isLoggable(logger, Level.FINEST, debugsql)) { logger.finest(info.getType().getSimpleName() + " update sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); } } }); } } //打印结束 if (info.getTableStrategy() == null) { slowLog(s, presql); } else { List presqls = new ArrayList<>(); prepareInfos.forEach((t, p) -> { presqls.add(p.prepareSql); }); slowLog(s, presqls.toArray(new String[presqls.size()])); } return c; } @Override protected CompletableFuture updateColumnDBAsync(EntityInfo info, Flipper flipper, UpdateSqlInfo sql) { return supplyAsync(() -> updateColumnDB(info, flipper, sql)); } @Override protected int updateColumnDB(EntityInfo info, Flipper flipper, UpdateSqlInfo sql) { SourceConnection conn = null; try { conn = writePool.pollConnection(); conn.setAutoCommit(false); int c = updateColumnDBStatement(false, conn, info, flipper, sql); conn.commit(); return c; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException se) { } } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } private int updateColumnDBStatement(final boolean batch, final SourceConnection conn, final EntityInfo info, Flipper flipper, UpdateSqlInfo sql) throws SQLException { //String sql, boolean prepared, Object... blobs) { final long s = System.currentTimeMillis(); int c = -1; String firstTable = null; try { if (sql.blobs != null || sql.tables != null) { if (sql.tables == null) { final PreparedStatement prestmt = conn.prepareUpdateStatement(sql.sql); int index = 0; for (byte[] param : sql.blobs) { Blob blob = conn.createBlob(); blob.setBytes(1, param); prestmt.setBlob(++index, blob); } if (info.isLoggable(logger, Level.FINEST, sql.sql)) { logger.finest(info.getType().getSimpleName() + " updateColumn sql=" + sql.sql); } c = prestmt.executeUpdate(); conn.offerUpdateStatement(prestmt); if (!batch) { conn.commit(); } slowLog(s, sql.sql); return c; } else { firstTable = sql.tables[0]; List prestmts = new ArrayList<>(); String[] sqls = new String[sql.tables.length]; for (int i = 0; i < sql.tables.length; i++) { sqls[i] = i == 0 ? sql.sql : sql.sql.replaceFirst(firstTable, sql.tables[i]); PreparedStatement prestmt = conn.prepareUpdateStatement(sqls[i]); 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.addBatch(); prestmts.add(prestmt); } if (info.isLoggable(logger, Level.FINEST, sql.sql)) { logger.finest(info.getType().getSimpleName() + " updateColumn sql=" + Arrays.toString(sqls)); } int c1 = 0; for (PreparedStatement stmt : prestmts) { c1 += Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } c = c1; if (!batch) { conn.commit(); } slowLog(s, sqls); } return c; } else { if (info.isLoggable(logger, Level.FINEST, sql.sql)) { logger.finest(info.getType().getSimpleName() + " updateColumn sql=" + sql.sql); } final Statement stmt = conn.createUpdateStatement(); c = stmt.executeUpdate(sql.sql); conn.offerUpdateStatement(stmt); if (!batch) { conn.commit(); } slowLog(s, sql.sql); return c; } } catch (SQLException se) { if (!batch) { conn.rollback(); } if (isTableNotExist(info, se.getSQLState())) { if (info.getTableStrategy() == null) { String[] tableSqls = createTableSqls(info); if (tableSqls != null) { try { Statement stmt = conn.createUpdateStatement(); if (tableSqls.length == 1) { stmt.execute(tableSqls[0]); } else { for (String tableSql : tableSqls) { stmt.addBatch(tableSql); } stmt.executeBatch(); } conn.offerUpdateStatement(stmt); } catch (SQLException e2) { } } //表不存在,更新条数为0 return 0; } else if (sql.tables == null) { //单一分表不存在 return 0; } else { // String tableName = parseNotExistTableName(se); // if (tableName == null) { // throw se; // } String[] oldTables = sql.tables; List notExistTables = checkNotExistTables(conn, oldTables); if (notExistTables.isEmpty()) { throw se; } for (String t : notExistTables) { sql.tables = Utility.remove(sql.tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "updateColumn, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(sql.tables)); } if (sql.tables.length == 0) { //分表全部不存在 return 0; } List prestmts = new ArrayList<>(); String[] sqls = new String[sql.tables.length]; for (int i = 0; i < sql.tables.length; i++) { sqls[i] = sql.sql.replaceFirst(firstTable, sql.tables[i]); PreparedStatement prestmt = conn.prepareUpdateStatement(sqls[i]); 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.addBatch(); prestmts.add(prestmt); } if (info.isLoggable(logger, Level.FINEST, sql.sql)) { logger.finest(info.getType().getSimpleName() + " updateColumn sql=" + Arrays.toString(sqls)); } int c1 = 0; for (PreparedStatement stmt : prestmts) { c1 += Utility.sum(stmt.executeBatch()); conn.offerUpdateStatement(stmt); } c = c1; if (!batch) { conn.commit(); } slowLog(s, sqls); return c; } } else { throw se; } } } @Override protected CompletableFuture> getNumberMapDBAsync(EntityInfo info, String[] tables, String sql, FilterNode node, FilterFuncColumn... columns) { return supplyAsync(() -> getNumberMapDB(info, tables, sql, node, columns)); } @Override protected Map getNumberMapDB(EntityInfo info, String[] tables, String sql, FilterNode node, FilterFuncColumn... columns) { SourceConnection conn = null; final Map map = new HashMap<>(); final long s = System.currentTimeMillis(); Statement stmt = null; try { conn = readPool.pollConnection(); stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); if (set.next()) { int index = 0; for (FilterFuncColumn ffc : columns) { for (String col : ffc.cols()) { Object o = set.getObject(++index); Number rs = ffc.getDefvalue(); if (o != null) { rs = (Number) o; } map.put(ffc.col(col), rs); } } } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return map; } catch (SQLException e) { map.clear(); if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return map; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return map; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "getNumberMap, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return map; } //重新查询一次 try { sql = getNumberMapSql(info, tables, node, columns); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " getNumberMap sql=" + sql); } if (stmt != null) { conn.offerQueryStatement(stmt); } stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); if (set.next()) { int index = 0; for (FilterFuncColumn ffc : columns) { for (String col : ffc.cols()) { Object o = set.getObject(++index); Number rs = ffc.getDefvalue(); if (o != null) { rs = (Number) o; } map.put(ffc.col(col), rs); } } } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return map; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture getNumberResultDBAsync(EntityInfo info, String[] tables, String sql, FilterFunc func, Number defVal, String column, FilterNode node) { return supplyAsync(() -> getNumberResultDB(info, tables, sql, func, defVal, column, node)); } @Override protected Number getNumberResultDB(EntityInfo info, String[] tables, String sql, FilterFunc func, Number defVal, String column, FilterNode node) { SourceConnection conn = null; final long s = System.currentTimeMillis(); Statement stmt = null; try { conn = readPool.pollConnection(); stmt = conn.createQueryStatement(); Number rs = defVal; ResultSet set = stmt.executeQuery(sql); if (set.next()) { Object o = set.getObject(1); if (o != null) { rs = (Number) o; } } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return defVal; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return defVal; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "getNumberResult, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return defVal; } //重新查询一次 try { sql = getNumberResultSql(info, info.getType(), tables, func, defVal, column, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " getNumberResult sql=" + sql); } if (stmt != null) { conn.offerQueryStatement(stmt); } stmt = conn.createQueryStatement(); Number rs = defVal; ResultSet set = stmt.executeQuery(sql); if (set.next()) { Object o = set.getObject(1); if (o != null) { rs = (Number) o; } } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture> queryColumnMapDBAsync(EntityInfo info, String[] tables, String sql, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { return supplyAsync(() -> queryColumnMapDB(info, tables, sql, keyColumn, func, funcColumn, node)); } @Override protected Map queryColumnMapDB(EntityInfo info, String[] tables, String sql, String keyColumn, FilterFunc func, String funcColumn, FilterNode node) { SourceConnection conn = null; final long s = System.currentTimeMillis(); Map rs = new LinkedHashMap<>(); Statement stmt = null; try { conn = readPool.pollConnection(); stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); ResultSetMetaData rsd = set.getMetaData(); boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT; while (set.next()) { rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2)); } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException e) { rs.clear(); if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return rs; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return rs; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "queryColumnMap, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return rs; } //重新查询一次 try { sql = queryColumnMapSql(info, tables, keyColumn, func, funcColumn, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " queryColumnMap sql=" + sql); } if (stmt != null) { conn.offerQueryStatement(stmt); } stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); ResultSetMetaData rsd = set.getMetaData(); boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT; while (set.next()) { rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2)); } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture> queryColumnMapDBAsync(EntityInfo info, String[] tables, String sql, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { return supplyAsync(() -> queryColumnMapDB(info, tables, sql, funcNodes, groupByColumns, node)); } @Override protected Map queryColumnMapDB(EntityInfo info, String[] tables, String sql, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { SourceConnection conn = null; Map rs = new LinkedHashMap<>(); final long s = System.currentTimeMillis(); Statement stmt = null; try { conn = readPool.pollConnection(); stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); ResultSetMetaData rsd = set.getMetaData(); boolean[] smallints = null; while (set.next()) { int index = 0; Serializable[] keys = new Serializable[groupByColumns.length]; if (smallints == null) { smallints = new boolean[keys.length]; for (int i = 0; i < keys.length; i++) { smallints[i] = rsd == null ? false : rsd.getColumnType(i + 1) == Types.SMALLINT; } } for (int i = 0; i < keys.length; i++) { keys[i] = (Serializable) ((smallints[i] && index == 0) ? set.getShort(++index) : set.getObject(++index)); } Number[] vals = new Number[funcNodes.length]; for (int i = 0; i < vals.length; i++) { vals[i] = (Number) set.getObject(++index); } rs.put(keys, vals); } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException e) { rs.clear(); if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return rs; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return rs; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "queryColumnMap, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return rs; } //重新查询一次 try { sql = queryColumnMapSql(info, tables, funcNodes, groupByColumns, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " queryColumnMap sql=" + sql); } if (stmt != null) { conn.offerQueryStatement(stmt); } stmt = conn.createQueryStatement(); ResultSet set = stmt.executeQuery(sql); ResultSetMetaData rsd = set.getMetaData(); boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT; while (set.next()) { rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2)); } set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected T findUnCache(final EntityInfo info, final SelectColumn selects, final Serializable pk) { if (selects == null && info.getTableStrategy() == null) { return findDB(info, pk); } else { return super.findUnCache(info, selects, pk); } } @Override protected CompletableFuture findUnCacheAsync(final EntityInfo info, final SelectColumn selects, final Serializable pk) { if (selects == null && info.getTableStrategy() == null) { return supplyAsync(() -> findDB(info, pk)); } else { return super.findUnCacheAsync(info, selects, pk); } } protected T findDB(EntityInfo info, Serializable pk) { SourceConnection conn = null; final long s = System.currentTimeMillis(); PreparedStatement prestmt = null; try { conn = readPool.pollConnection(); String prepareSQL = info.getFindQuestionPrepareSQL(pk); prestmt = conn.prepareQueryStatement(prepareSQL); prestmt.setObject(1, pk); final DataResultSet set = createDataResultSet(info, prestmt.executeQuery()); T rs = set.next() ? info.getBuilder().getFullEntityValue(set) : null; set.close(); conn.offerQueryStatement(prestmt); slowLog(s, prepareSQL); return rs; } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { return null; } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture findDBAsync(EntityInfo info, String[] tables, String sql, boolean onlypk, SelectColumn selects, Serializable pk, FilterNode node) { return supplyAsync(() -> findDB(info, tables, sql, onlypk, selects, pk, node)); } @Override protected T findDB(EntityInfo info, String[] tables, String sql, boolean onlypk, SelectColumn selects, Serializable pk, FilterNode node) { SourceConnection conn = null; final long s = System.currentTimeMillis(); PreparedStatement prestmt = null; try { conn = readPool.pollConnection(); prestmt = conn.prepareQueryStatement(sql); prestmt.setFetchSize(1); final DataResultSet set = createDataResultSet(info, prestmt.executeQuery()); T rs = set.next() ? selects == null ? info.getBuilder().getFullEntityValue(set) : info.getBuilder().getEntityValue(selects, set) : null; set.close(); conn.offerQueryStatement(prestmt); slowLog(s, sql); return rs; } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return null; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return null; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "find, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return null; } //重新查询一次 try { sql = findSql(info, tables, selects, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " find sql=" + sql); } if (prestmt != null) { conn.offerQueryStatement(prestmt); } prestmt = conn.prepareQueryStatement(sql); prestmt.setFetchSize(1); final DataResultSet set = createDataResultSet(info, prestmt.executeQuery()); T rs = set.next() ? selects == null ? info.getBuilder().getFullEntityValue(set) : info.getBuilder().getEntityValue(selects, set) : null; set.close(); conn.offerQueryStatement(prestmt); slowLog(s, sql); return rs; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture findColumnDBAsync(EntityInfo info, final String[] tables, String sql, boolean onlypk, String column, Serializable defValue, Serializable pk, FilterNode node) { return supplyAsync(() -> findColumnDB(info, tables, sql, onlypk, column, defValue, pk, node)); } @Override protected Serializable findColumnDB(EntityInfo info, String[] tables, String sql, boolean onlypk, String column, Serializable defValue, Serializable pk, FilterNode node) { SourceConnection conn = null; final long s = System.currentTimeMillis(); PreparedStatement prestmt = null; final Attribute attr = info.getAttribute(column); try { conn = readPool.pollConnection(); prestmt = conn.prepareQueryStatement(sql); prestmt.setFetchSize(1); final DataResultSet set = createDataResultSet(info, prestmt.executeQuery()); Serializable val = defValue; if (set.next()) { val = info.getBuilder().getFieldValue(attr, set, 1); } set.close(); conn.offerQueryStatement(prestmt); slowLog(s, sql); return val == null ? defValue : val; } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return defValue; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return defValue; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "findColumn, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return defValue; } //重新查询一次 try { sql = findColumnSql(info, tables, column, defValue, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " findColumn sql=" + sql); } if (prestmt != null) { conn.offerQueryStatement(prestmt); } prestmt = conn.prepareQueryStatement(sql); prestmt.setFetchSize(1); final DataResultSet set = createDataResultSet(info, prestmt.executeQuery()); Serializable val = defValue; if (set.next()) { val = info.getBuilder().getFieldValue(attr, set, 1); } set.close(); conn.offerQueryStatement(prestmt); slowLog(s, sql); return val == null ? defValue : val; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected CompletableFuture existsDBAsync(EntityInfo info, final String[] tables, String sql, boolean onlypk, Serializable pk, FilterNode node) { return supplyAsync(() -> existsDB(info, tables, sql, onlypk, pk, node)); } @Override protected boolean existsDB(EntityInfo info, String[] tables, String sql, boolean onlypk, Serializable pk, FilterNode node) { SourceConnection conn = null; final long s = System.currentTimeMillis(); PreparedStatement prestmt = null; try { conn = readPool.pollConnection(); prestmt = conn.prepareQueryStatement(sql); final ResultSet set = prestmt.executeQuery(); boolean rs = set.next() ? (set.getInt(1) > 0) : false; set.close(); conn.offerQueryStatement(prestmt); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql); } slowLog(s, sql); return rs; } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return false; } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return false; } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(e); // if (tableName == null) { // throw new SourceException(e); // } String[] oldTables = tables; List notExistTables = checkNotExistTablesNoThrows(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(e); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "exists, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return false; } //重新查询一次 try { sql = existsSql(info, tables, node); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); } if (prestmt != null) { conn.offerQueryStatement(prestmt); } prestmt = conn.prepareQueryStatement(sql); final ResultSet set = prestmt.executeQuery(); boolean rs = set.next() ? (set.getInt(1) > 0) : false; set.close(); conn.offerQueryStatement(prestmt); if (info.isLoggable(logger, Level.FINEST, sql)) { logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql); } slowLog(s, sql); return rs; } catch (SQLException se) { throw new SourceException(se); } } } throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override public List findsList(Class clazz, Stream pks) { final EntityInfo info = loadEntityInfo(clazz); Serializable[] ids = pks.toArray(serialArrayFunc); if (info.getTableStrategy() == null) { SourceConnection conn = null; final long s = System.currentTimeMillis(); try { conn = readPool.pollConnection(); final List list = new ArrayList(); try { String prepareSQL = info.getFindQuestionPrepareSQL(ids[0]); PreparedStatement prestmt = conn.prepareQueryStatement(prepareSQL); DataJdbcResultSet rr = new DataJdbcResultSet(info); for (Serializable pk : ids) { prestmt.setObject(1, pk); ResultSet set = prestmt.executeQuery(); rr.resultSet(set); if (set.next()) { list.add(getEntityValue(info, null, rr)); } else { list.add(null); } set.close(); } conn.offerQueryStatement(prestmt); slowLog(s, prepareSQL); return list; } catch (SQLException se) { if (isTableNotExist(info, se.getSQLState())) { return list; } throw new SourceException(se); } } catch (SourceException se) { throw se; } catch (Exception e) { throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } else { return queryList(info.getType(), null, null, FilterNode.create(info.getPrimarySQLColumn(), FilterExpress.IN, ids)); } } @Override public CompletableFuture> findsListAsync(final Class clazz, final Stream pks) { return supplyAsync(() -> findsList(clazz, pks)); } @Override protected CompletableFuture> querySheetDBAsync(EntityInfo info, final boolean readCache, boolean needTotal, final boolean distinct, SelectColumn selects, Flipper flipper, FilterNode node) { return supplyAsync(() -> querySheetDB(info, readCache, needTotal, distinct, selects, flipper, node)); } protected Sheet querySheetFullListDB(EntityInfo info) { SourceConnection conn = null; final long s = System.currentTimeMillis(); try { conn = readPool.pollConnection(); final List list = new ArrayList(); try { String prepareSQL = info.getAllQueryPrepareSQL(); PreparedStatement prestmt = conn.prepareQueryStatement(prepareSQL); ResultSet set = prestmt.executeQuery(); final DataResultSet rr = createDataResultSet(info, set); while (set.next()) { list.add(getEntityValue(info, null, rr)); } set.close(); conn.offerQueryStatement(prestmt); slowLog(s, prepareSQL); return Sheet.asSheet(list); } catch (SQLException se) { if (isTableNotExist(info, se.getSQLState())) { return Sheet.asSheet(list); } throw new SourceException(se); } } catch (SourceException se) { throw se; } catch (Exception e) { throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Override protected Sheet querySheetDB(EntityInfo info, final boolean readCache, boolean needTotal, final boolean distinct, SelectColumn selects, Flipper flipper, FilterNode node) { if (!needTotal && !distinct && selects == null && flipper == null && node == null && info.getTableStrategy() == null) { return querySheetFullListDB(info); } SourceConnection conn = null; final long s = System.currentTimeMillis(); final SelectColumn sels = selects; 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); final String joinAndWhere = (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); final boolean mysqlOrPgsql = "mysql".equals(dbtype()) || "postgresql".equals(dbtype()); try { conn = readPool.pollConnection(); String[] sqls = createSheetListAndCountSql(info, readCache, needTotal, distinct, selects, flipper, mysqlOrPgsql, tables, joinAndWhere); String listSql = sqls[0]; String countSql = sqls[1]; try { return executeQuerySheet(info, needTotal, flipper, sels, s, conn, mysqlOrPgsql, listSql, countSql); } catch (SQLException se) { if (isTableNotExist(info, se.getSQLState())) { if (info.getTableStrategy() == null) { //读操作不自动创建表,可能存在读写分离 return new Sheet<>(0, new ArrayList()); } else if (tables != null && tables.length == 1) { //只查一个不存在的分表 return new Sheet<>(0, new ArrayList()); } else if (tables != null && tables.length > 1) { //多分表查询中一个或多个分表不存在 // String tableName = parseNotExistTableName(se); // if (tableName == null) { // throw new SourceException(se); // } String[] oldTables = tables; List notExistTables = checkNotExistTables(conn, tables); if (notExistTables.isEmpty()) { throw new SourceException(se); } for (String t : notExistTables) { tables = Utility.remove(tables, t); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "querySheet, old-tables: " + Arrays.toString(oldTables) + ", new-tables: " + Arrays.toString(tables)); } if (tables.length == 0) { //分表全部不存在 return new Sheet<>(0, new ArrayList()); } if (tables.length == oldTables.length) { //没有变化, 不异常会陷入死循环 throw new SourceException(se); } //重新查询一次 sqls = createSheetListAndCountSql(info, readCache, needTotal, distinct, selects, flipper, mysqlOrPgsql, tables, joinAndWhere); listSql = sqls[0]; countSql = sqls[1]; return executeQuerySheet(info, needTotal, flipper, sels, s, conn, mysqlOrPgsql, listSql, countSql); } else { throw new SourceException(se); } } throw new SourceException(se); } } catch (SourceException se) { throw se; } catch (Exception e) { throw new SourceException(e); } finally { if (conn != null) { readPool.offerConnection(conn); } } } private Sheet executeQuerySheet(EntityInfo info, boolean needTotal, Flipper flipper, SelectColumn sels, long s, SourceConnection conn, boolean mysqlOrPgsql, String listSql, String countSql) throws SQLException { final List list = new ArrayList(); if (mysqlOrPgsql) { //sql可以带limit、offset PreparedStatement prestmt = conn.prepareQueryStatement(listSql); ResultSet set = prestmt.executeQuery(); final DataResultSet rr = createDataResultSet(info, set); while (set.next()) { list.add(getEntityValue(info, sels, rr)); } set.close(); conn.offerQueryStatement(prestmt); long total = list.size(); if (needTotal) { prestmt = conn.prepareQueryStatement(countSql); set = prestmt.executeQuery(); if (set.next()) { total = set.getLong(1); } set.close(); conn.offerQueryStatement(prestmt); } slowLog(s, listSql); return new Sheet<>(total, list); } else { PreparedStatement prestmt = conn.prepareQueryStatement(listSql); if (flipper != null && flipper.getLimit() > 0) { prestmt.setFetchSize(flipper.getLimit()); } ResultSet set = prestmt.executeQuery(); if (flipper != null && flipper.getOffset() > 0) { set.absolute(flipper.getOffset()); } final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit(); int i = 0; final DataResultSet rr = createDataResultSet(info, set); EntityBuilder builder = info.getBuilder(); if (sels == null) { while (set.next()) { i++; list.add(builder.getFullEntityValue(rr)); if (limit <= i) { break; } } } else { while (set.next()) { i++; list.add(builder.getEntityValue(sels, rr)); if (limit <= i) { break; } } } long total = list.size(); if (needTotal && flipper != null) { set.last(); total = set.getRow(); } set.close(); conn.offerQueryStatement(prestmt); slowLog(s, listSql); return new Sheet<>(total, list); } } private String[] createSheetListAndCountSql(EntityInfo info, final boolean readCache, boolean needTotal, final boolean distinct, SelectColumn selects, Flipper flipper, boolean mysqlOrPgsql, String[] tables, String joinAndWhere) { String listSql = null; String countSql = null; { //组装listSql、countSql String listSubSql; StringBuilder union = new StringBuilder(); if (tables.length == 1) { listSubSql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getQueryColumns("a", selects) + " FROM " + tables[0] + " a" + joinAndWhere; } else { int b = 0; for (String table : tables) { if (union.length() > 0) { union.append(" UNION ALL "); } union.append("SELECT ").append(info.getQueryColumns("a", selects)).append(" FROM ").append(table).append(" a").append(joinAndWhere); } listSubSql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getQueryColumns("a", selects) + " FROM (" + (union) + ") a"; } listSql = listSubSql + createSQLOrderby(info, flipper); if (mysqlOrPgsql) { listSql += (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); } } else { 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()))); } } if (mysqlOrPgsql && needTotal) { 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"; } countSql = countSubSql; if (readCache && info.isLoggable(logger, Level.FINEST, countSql)) { logger.finest(info.getType().getSimpleName() + " querySheet countsql=" + countSql); } } } return new String[]{listSql, countSql}; } protected List checkNotExistTablesNoThrows(SourceConnection conn, String[] tables) { try { return checkNotExistTables(conn, tables); //, firstNotExistTable } catch (SQLException e) { throw new SourceException(e); } } protected List checkNotExistTables(SourceConnection conn, String[] tables) throws SQLException { //, String firstNotExistTable // 数据库不一定要按批量提交的SQL顺序执行, 所以第一个不存在的表不一定在tables的第一位, // 比如 DELETE FROM table1; DELETE FROM table2; 如果table1、table2都不存在,SQL可能会抛出table2不存在的异常 // List maybeNoTables = new ArrayList<>(); // String minTableName = (firstNotExistTable.indexOf('.') > 0) ? firstNotExistTable.substring(firstNotExistTable.indexOf('.') + 1) : null; // for (String t : tables) { // if (!maybeNoTables.isEmpty()) { // maybeNoTables.add(t); // } // if (t.equals(firstNotExistTable) || (minTableName != null && t.equals(minTableName))) { // maybeNoTables.add(t); // } // } // if (maybeNoTables.isEmpty()) { // return maybeNoTables; // } String[] tableTypes = new String[]{"TABLE"}; DatabaseMetaData dmd = conn.getMetaData(); List rs = new ArrayList<>(); for (String t : tables) { //maybeNoTables String catalog = null; String table = t; int pos = t.indexOf('.'); if (pos > 0) { catalog = t.substring(0, pos); table = t.substring(pos + 1); } ResultSet dmdrs = dmd.getTables(catalog, null, table, tableTypes); if (!dmdrs.next()) { //不存在表 rs.add(t); } dmdrs.close(); } return rs; } /** * 直接本地执行SQL语句进行增删改操作,远程模式不可用
* 通常用于复杂的更新操作
* * @param sql SQL语句 * * @return 结果数组 */ @Override public int executeUpdate(String sql) { return executeUpdate(new String[]{sql})[0]; } /** * 直接本地执行SQL语句进行增删改操作,远程模式不可用
* 通常用于复杂的更新操作
* * @param sqls SQL语句 * * @return 结果数组 */ @Override public int[] executeUpdate(String... sqls) { if (sqls.length == 0) { return new int[0]; } final long s = System.currentTimeMillis(); SourceConnection conn = writePool.pollConnection(); try { conn.setAutoCommit(false); final Statement stmt = conn.createUpdateStatement(); final int[] rs = new int[sqls.length]; int i = -1; for (String sql : sqls) { rs[++i] = stmt.execute(sql) ? 1 : 0; } conn.offerUpdateStatement(stmt); conn.commit(); slowLog(s, sqls); return rs; } catch (SQLException e) { try { conn.rollback(); } catch (SQLException se) { } throw new SourceException(e); } finally { if (conn != null) { writePool.offerConnection(conn); } } } /** * 直接本地执行SQL语句进行查询,远程模式不可用
* 通常用于复杂的关联查询
* * @param 泛型 * @param sql SQL语句 * @param handler 回调函数 * * @return 结果 */ @Override public V executeQuery(String sql, Function handler) { final long s = System.currentTimeMillis(); final SourceConnection conn = readPool.pollConnection(); try { if (logger.isLoggable(Level.FINEST)) { logger.finest("executeQuery sql=" + sql); } final Statement stmt = conn.createQueryStatement(); //final PreparedStatement prestmt = conn.prepareStatement(sql); final ResultSet set = stmt.executeQuery(sql);// prestmt.executeQuery(); V rs = handler.apply(createDataResultSet(null, set)); set.close(); conn.offerQueryStatement(stmt); slowLog(s, sql); return rs; } catch (Exception ex) { throw new SourceException(ex); } finally { if (conn != null) { readPool.offerConnection(conn); } } } @Deprecated public int directExecute(String sql) { return executeUpdate(sql); } @Deprecated public int[] directExecute(String... sqls) { return executeUpdate(sqls); } @Deprecated public V directQuery(String sql, Function handler) { return executeQuery(sql, handler); } public static DataResultSet createDataResultSet(EntityInfo info, ResultSet set) { return new DataJdbcResultSet(info).resultSet(set); } protected static class DataJdbcResultSet implements DataResultSet { EntityInfo info; ResultSet rr; public DataJdbcResultSet(EntityInfo info) { this.info = info; } public DataJdbcResultSet resultSet(ResultSet set) { this.rr = set; return this; } @Override public Serializable getObject(Attribute attr, int index, String column) { Class t = attr.type(); if (t == int.class || t == String.class) { return DataResultSet.getRowColumnValue(this, attr, index, column); } else if (t == java.util.Date.class) { Object val = index > 0 ? getObject(index) : getObject(column); return val == null ? null : new java.util.Date(((java.sql.Date) val).getTime()); } else if (t == java.time.LocalDate.class) { Object val = index > 0 ? getObject(index) : getObject(column); return val == null ? null : ((java.sql.Date) val).toLocalDate(); } else if (t == java.time.LocalTime.class) { Object val = index > 0 ? getObject(index) : getObject(column); return val == null ? null : ((java.sql.Time) val).toLocalTime(); } else if (t == java.time.LocalDateTime.class) { Object val = index > 0 ? getObject(index) : getObject(column); return val == null ? null : ((java.sql.Timestamp) val).toLocalDateTime(); } else if (t.getName().startsWith("java.sql.")) { return index > 0 ? (Serializable) getObject(index) : (Serializable) getObject(column); } return DataResultSet.getRowColumnValue(this, attr, index, column); } @Override public boolean next() { try { return rr.next(); } catch (SQLException e) { throw new SourceException(e); } } @Override public List getColumnLabels() { try { ResultSetMetaData meta = rr.getMetaData(); int count = meta.getColumnCount(); List labels = new ArrayList<>(count); for (int i = 1; i <= count; i++) { labels.add(meta.getColumnLabel(i)); } return labels; } catch (SQLException e) { throw new SourceException(e); } } @Override public boolean wasNull() { try { return rr.wasNull(); } catch (SQLException e) { throw new SourceException(e); } } @Override public void close() { try { rr.close(); } catch (SQLException e) { throw new SourceException(e); } } @Override public Object getObject(int index) { try { return rr.getObject(index); } catch (SQLException e) { throw new SourceException(e); } } @Override public Object getObject(String column) { try { return rr.getObject(column); } catch (SQLException e) { throw new SourceException(e); } } @Override public EntityInfo getEntityInfo() { return info; } } protected class ConnectionPool implements AutoCloseable { protected final LongAdder closeCounter = new LongAdder(); //已关闭连接数 protected final LongAdder usingCounter = new LongAdder(); //使用中连接数 protected final LongAdder creatCounter = new LongAdder(); //已创建连接数 protected final LongAdder cycleCounter = new LongAdder(); //已复用连接数 protected final java.sql.Driver driver; protected final Properties connectAttrs; protected ArrayBlockingQueue queue; protected int connectTimeoutSeconds; protected int maxConns; protected Semaphore maxSemaphore; protected String url; protected final AtomicInteger urlVersion = new AtomicInteger(); public ConnectionPool(Properties prop) { this.connectTimeoutSeconds = Integer.decode(prop.getProperty(DATA_SOURCE_CONNECTTIMEOUT_SECONDS, "30")); int defMaxConns = Utility.cpus() * 4; if (workExecutor instanceof ThreadPoolExecutor) { defMaxConns = ((ThreadPoolExecutor) workExecutor).getCorePoolSize(); } else if (workExecutor != null) { //maybe virtual thread pool defMaxConns = Math.min(1000, Utility.cpus() * 100); } this.maxConns = Math.max(1, Integer.decode(prop.getProperty(DATA_SOURCE_MAXCONNS, "" + defMaxConns))); this.maxSemaphore = new Semaphore(this.maxConns); this.queue = new ArrayBlockingQueue<>(maxConns); this.url = prop.getProperty(DATA_SOURCE_URL); String username = prop.getProperty(DATA_SOURCE_USER, ""); String password = prop.getProperty(DATA_SOURCE_PASSWORD, ""); this.connectAttrs = new Properties(); if (username != null) { this.connectAttrs.put("user", username); } if (password != null) { this.connectAttrs.put("password", password); } try { this.driver = DriverManager.getDriver(this.url); } catch (SQLException e) { throw new SourceException(e); } resetMaxConnection(); } @ResourceListener public void onResourceChange(ResourceEvent[] events) { int newConnectTimeoutSeconds = this.connectTimeoutSeconds; int newMaxconns = this.maxConns; String newUrl = this.url; String newUser = this.connectAttrs.getProperty("user"); String newPassword = this.connectAttrs.getProperty("password"); for (ResourceEvent event : events) { if (event.name().equals(DATA_SOURCE_URL) || event.name().endsWith("." + DATA_SOURCE_URL)) { newUrl = event.newValue().toString(); } else if (event.name().equals(DATA_SOURCE_CONNECTTIMEOUT_SECONDS) || event.name().endsWith("." + DATA_SOURCE_CONNECTTIMEOUT_SECONDS)) { newConnectTimeoutSeconds = Integer.decode(event.newValue().toString()); } else if (event.name().equals(DATA_SOURCE_USER) || event.name().endsWith("." + DATA_SOURCE_USER)) { newUser = event.newValue().toString(); } else if (event.name().equals(DATA_SOURCE_PASSWORD) || event.name().endsWith("." + DATA_SOURCE_PASSWORD)) { newPassword = event.newValue().toString(); } else if (event.name().equals(DATA_SOURCE_MAXCONNS) || event.name().endsWith("." + DATA_SOURCE_MAXCONNS)) { newMaxconns = Math.max(1, Integer.decode(event.newValue().toString())); } } if (!Objects.equals(newUser, this.connectAttrs.get("user")) || !Objects.equals(newPassword, this.connectAttrs.get("password")) || !Objects.equals(newUrl, url)) { this.urlVersion.incrementAndGet(); } this.url = newUrl; this.connectTimeoutSeconds = newConnectTimeoutSeconds; this.connectAttrs.put("user", newUser); this.connectAttrs.put("password", newPassword); if (newMaxconns != this.maxConns) { changeMaxConns(newMaxconns); } } private void resetMaxConnection() { if ("mysql".equals(dbtype()) || "postgresql".equals(dbtype())) { int newMaxconns = this.maxConns; try { Connection conn = driver.connect(url, connectAttrs); Statement stmt = conn.createStatement(); if ("mysql".equals(dbtype())) { ResultSet rs = stmt.executeQuery("SHOW VARIABLES LIKE 'max_connections'"); if (rs.next()) { newMaxconns = rs.getInt(2); } } else if ("postgresql".equals(dbtype())) { ResultSet rs = stmt.executeQuery("SHOW max_connections"); if (rs.next()) { newMaxconns = rs.getInt(1); } } stmt.close(); conn.close(); } catch (Exception e) { } if (this.maxConns > newMaxconns) { //配置连接数过大 changeMaxConns(newMaxconns); } } } private void changeMaxConns(int newMaxconns) { ArrayBlockingQueue newQueue = new ArrayBlockingQueue<>(newMaxconns); ArrayBlockingQueue oldQueue = this.queue; Semaphore oldSemaphore = this.maxSemaphore; this.queue = newQueue; this.maxConns = newMaxconns; this.maxSemaphore = new Semaphore(this.maxConns); SourceConnection c; while ((c = oldQueue.poll()) != null) { c.version = -1; offerConnection(c, oldSemaphore, this.queue); } } public SourceConnection pollConnection() { SourceConnection conn = queue.poll(); if (conn == null) { return newConnection(this.queue); } usingCounter.increment(); if (checkValid(conn)) { cycleCounter.increment(); return conn; } else { offerConnection(conn); conn = null; } return newConnection(this.queue); } //用于事务的连接 public SourceConnection pollTransConnection() { SourceConnection conn = queue.poll(); if (conn == null) { return newConnection(this.queue); } usingCounter.increment(); if (checkValid(conn)) { cycleCounter.increment(); return conn; } else { offerConnection(conn); conn = null; } return newConnection(this.queue); } private SourceConnection newConnection(ArrayBlockingQueue queue) { Semaphore semaphore = this.maxSemaphore; SourceConnection conn = null; if (semaphore.tryAcquire()) { try { conn = new SourceConnection(driver.connect(url, connectAttrs), this.urlVersion.get()); } catch (SQLException ex) { throw new SourceException(ex); } usingCounter.increment(); creatCounter.increment(); return conn; } else { try { conn = queue.poll(connectTimeoutSeconds, TimeUnit.SECONDS); } catch (InterruptedException t) { logger.log(Level.WARNING, "take pooled connection error", t); } if (conn == null) { throw new SourceException("create pooled connection timeout"); } return conn; } } public void offerConnection(final C connection) { offerConnection(connection, this.maxSemaphore, this.queue); } public void offerTransConnection(final C connection) { offerConnection(connection, this.maxSemaphore, this.queue); } private void offerConnection(final C connection, Semaphore semaphore, Queue queue) { SourceConnection conn = (SourceConnection) connection; if (conn != null) { try { if (checkValid(conn) && queue.offer(conn)) { usingCounter.decrement(); } else { usingCounter.decrement(); closeCounter.increment(); semaphore.release(); conn.close(); } } catch (Exception e) { logger.log(Level.WARNING, "closeSQLConnection abort", e); } } } protected boolean checkValid(SourceConnection conn) { try { return !conn.conn.isClosed() && conn.conn.isValid(1) && conn.version == this.urlVersion.get(); } catch (SQLException ex) { if (!"08S01".equals(ex.getSQLState())) {//MySQL特性, 长时间连接没使用会抛出com.mysql.jdbc.exceptions.jdbc4.CommunicationsException logger.log(Level.FINER, "result.getConnection from pooled connection abort [" + ex.getSQLState() + "]", ex); } return false; } } @Override public void close() { queue.stream().forEach(x -> { try { x.close(); } catch (Exception e) { } }); } } protected class SourceConnection { public int version; public final Connection conn; public SourceConnection(Connection conn, int version) { Objects.requireNonNull(conn); this.conn = conn; this.version = version; } public Statement createStreamStatement() throws SQLException { Statement statement = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); statement.setFetchSize(Integer.MIN_VALUE); return statement; } public void offerStreamStatement(final Statement stmt) throws SQLException { stmt.close(); } public Statement createQueryStatement() throws SQLException { return conn.createStatement(); } public void offerQueryStatement(final Statement stmt) throws SQLException { stmt.close(); } public Statement createUpdateStatement() throws SQLException { return conn.createStatement(); } public void offerUpdateStatement(final Statement stmt) throws SQLException { stmt.close(); } public PreparedStatement prepareQueryStatement(String sql) throws SQLException { return conn.prepareStatement(sql); } public void offerQueryStatement(final PreparedStatement stmt) throws SQLException { stmt.close(); } public PreparedStatement prepareUpdateStatement(String sql) throws SQLException { return conn.prepareStatement(sql); } public void offerUpdateStatement(final PreparedStatement stmt) throws SQLException { stmt.close(); } public void setAutoCommit(boolean autoCommit) throws SQLException { conn.setAutoCommit(autoCommit); } public void commit() throws SQLException { conn.commit(); } public void rollback() throws SQLException { conn.rollback(); } public DatabaseMetaData getMetaData() throws SQLException { return conn.getMetaData(); } public Blob createBlob() throws SQLException { return conn.createBlob(); } public void close() throws SQLException { conn.close(); } } }