From 330876f97f826ffef8b9c92098cb2a0c27b3cb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=B0=E5=B9=B3=E7=BA=BF?= <22250530@qq.com> Date: Sun, 31 May 2015 20:31:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E7=89=88EntityXInfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wentch/redkale/source/DataJDBCSource.java | 1375 ++--------------- .../wentch/redkale/source/DataJPASource.java | 147 +- src/com/wentch/redkale/source/DataSource.java | 303 +--- .../wentch/redkale/source/EntityCache.java | 2 +- src/com/wentch/redkale/source/FilterNode.java | 59 +- .../wentch/redkale/source/JDBCPoolSource.java | 234 +++ 6 files changed, 539 insertions(+), 1581 deletions(-) create mode 100644 src/com/wentch/redkale/source/JDBCPoolSource.java diff --git a/src/com/wentch/redkale/source/DataJDBCSource.java b/src/com/wentch/redkale/source/DataJDBCSource.java index 6bcab6858..c8edd37ef 100644 --- a/src/com/wentch/redkale/source/DataJDBCSource.java +++ b/src/com/wentch/redkale/source/DataJDBCSource.java @@ -5,25 +5,17 @@ */ package com.wentch.redkale.source; -import com.wentch.redkale.source.DistributeGenerator.DistributeTables; -import static com.wentch.redkale.source.FilterInfo.formatToString; +import static com.wentch.redkale.source.FilterNode.*; import com.wentch.redkale.util.*; import java.io.*; -import java.lang.ref.*; import java.lang.reflect.*; -import java.lang.reflect.Array; import java.net.*; -import java.nio.file.*; -import static java.nio.file.StandardWatchEventKinds.*; import java.sql.*; import java.util.*; -import java.util.AbstractMap.SimpleEntry; -import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.function.*; import java.util.logging.*; import javax.annotation.*; -import javax.persistence.*; import javax.sql.*; import javax.xml.stream.*; @@ -36,27 +28,27 @@ public final class DataJDBCSource implements DataSource { public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; - private static final String JDBC_CONNECTIONMAX = "javax.persistence.connection.limit"; + static final String JDBC_CONNECTIONMAX = "javax.persistence.connection.limit"; - private static final String JDBC_URL = "javax.persistence.jdbc.url"; + static final String JDBC_URL = "javax.persistence.jdbc.url"; - private static final String JDBC_USER = "javax.persistence.jdbc.user"; + static final String JDBC_USER = "javax.persistence.jdbc.user"; - private static final String JDBC_PWD = "javax.persistence.jdbc.password"; + static final String JDBC_PWD = "javax.persistence.jdbc.password"; - private static final String JDBC_DRIVER = "javax.persistence.jdbc.driver"; + static final String JDBC_DRIVER = "javax.persistence.jdbc.driver"; - private static final String JDBC_SOURCE = "javax.persistence.jdbc.source"; + static final String JDBC_SOURCE = "javax.persistence.jdbc.source"; private static final Flipper FLIPPER_ONE = new Flipper(1); - private final Logger logger = Logger.getLogger(DataJDBCSource.class.getSimpleName()); + final Logger logger = Logger.getLogger(DataJDBCSource.class.getSimpleName()); - private final AtomicBoolean debug = new AtomicBoolean(logger.isLoggable(Level.FINEST)); + final AtomicBoolean debug = new AtomicBoolean(logger.isLoggable(Level.FINEST)); - private final String name; + final String name; - private final URL conf; + final URL conf; private final JDBCPoolSource readPool; @@ -114,6 +106,8 @@ public final class DataJDBCSource implements DataSource { } } + private final Function fullloader = (t) -> queryList(t, (FilterNode) null); + public DataJDBCSource() throws IOException { this(""); } @@ -206,7 +200,7 @@ public final class DataJDBCSource implements DataSource { return result; } - private static Map loadProperties(final InputStream in0) { + static Map loadProperties(final InputStream in0) { final Map map = new LinkedHashMap(); Properties result = new Properties(); boolean flag = false; @@ -235,7 +229,7 @@ public final class DataJDBCSource implements DataSource { return map; } - private static ConnectionPoolDataSource createDataSource(Properties property) { + static ConnectionPoolDataSource createDataSource(Properties property) { try { return createDataSource(property.getProperty(JDBC_SOURCE, property.getProperty(JDBC_DRIVER)), property.getProperty(JDBC_URL), property.getProperty(JDBC_USER), property.getProperty(JDBC_PWD)); @@ -244,7 +238,7 @@ public final class DataJDBCSource implements DataSource { } } - private static ConnectionPoolDataSource createDataSource(final String source0, String url, String user, String password) throws Exception { + static ConnectionPoolDataSource createDataSource(final String source0, String url, String user, String password) throws Exception { String source = source0; if (source0.contains("Driver")) { //为了兼容JPA的配置文件 switch (source0) { @@ -337,8 +331,6 @@ public final class DataJDBCSource implements DataSource { } } - private final Function fullloader = (t) -> queryList(t, null); - private EntityInfo loadEntityInfo(Class clazz) { return EntityInfo.load(clazz, this.nodeid, fullloader); } @@ -354,7 +346,7 @@ public final class DataJDBCSource implements DataSource { EntityInfo info = EntityInfo.load(clazz, this.nodeid, fullloader); EntityCache cache = info.getCache(); if (cache == null) return; - cache.fullLoad(queryList(clazz, null)); + cache.fullLoad(queryList(clazz, (FilterNode) null)); } //----------------------insert----------------------------- @@ -530,13 +522,6 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 删除对象, 必须是Entity对象 - * - * @param - * @param conn - * @param values - */ @Override public void delete(final DataConnection conn, T... values) { delete((Connection) conn.getConnection(), values); @@ -555,13 +540,6 @@ public final class DataJDBCSource implements DataSource { delete(conn, clazz, ids); } - /** - * 根据主键值删除对象, 必须是Entity Class - * - * @param - * @param clazz - * @param ids 主键值 - */ @Override public void delete(Class clazz, Serializable... ids) { Connection conn = createWriteSQLConnection(); @@ -572,85 +550,17 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 根据主键值删除对象, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param ids - */ @Override public void delete(final DataConnection conn, Class clazz, Serializable... ids) { delete((Connection) conn.getConnection(), clazz, ids); } - private void delete(final Connection conn, Class clazz, Serializable... ids) { - deleteByColumn(conn, clazz, loadEntityInfo(clazz).getPrimary().field(), ids); - } - - /** - * 根据column字段的值删除对象, 必须是Entity Class - * - * @param - * @param clazz - * @param column - * @param keys - */ - @Override - public void deleteByColumn(Class clazz, String column, Serializable... keys) { - Connection conn = createWriteSQLConnection(); - try { - deleteByColumn(conn, clazz, column, keys); - } finally { - closeSQLConnection(conn); - } - } - - /** - * 根据column字段的值删除对象, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param column - * @param keys - */ - @Override - public void deleteByColumn(final DataConnection conn, Class clazz, String column, Serializable... keys) { - deleteByColumn((Connection) conn.getConnection(), clazz, column, keys); - } - - private void deleteByColumn(final Connection conn, Class clazz, String column, Serializable... keys) { + private void delete(final Connection conn, Class clazz, Serializable... keys) { if (keys.length == 0) return; try { final EntityInfo info = loadEntityInfo(clazz); - String sql = "DELETE FROM " + info.getTable() + " WHERE " + info.getSQLColumn(column); - if (keys.length == 1 && !keys[0].getClass().isArray()) { - sql += " = " + formatToString(keys[0]); - } else { - sql += " IN ("; - boolean flag = false; - if (keys.length == 1 && keys[0].getClass().isArray()) { - Class keytype = keys[0].getClass(); - if (keytype.getComponentType().isPrimitive()) { - Object array = keys[0]; - Serializable[] keys0 = new Serializable[Array.getLength(array)]; - for (int i = 0; i < keys0.length; i++) { - keys0[i] = (Serializable) Array.get(array, i); - } - keys = keys0; - } else { - keys = (Serializable[]) keys[0]; - } - } - for (final Serializable value : keys) { - if (flag) sql += ","; - sql += formatToString(value); - flag = true; - } - sql += ")"; - } + String sql = "DELETE FROM " + info.getTable() + " WHERE " + info.getPrimarySQLColumn() + + " IN " + formatToString(keys); if (debug.get()) logger.finest(clazz.getSimpleName() + " delete sql=" + sql); final Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -659,7 +569,7 @@ public final class DataJDBCSource implements DataSource { //------------------------------------ final EntityCache cache = info.getCache(); if (cache == null) return; - final Attribute attr = info.getAttribute(column); + final Attribute attr = info.getPrimary(); final Serializable[] keys2 = keys; Serializable[] ids = cache.delete((T t) -> Arrays.binarySearch(keys2, attr.get(t)) >= 0); if (cacheListener != null) cacheListener.delete(name, clazz, ids); @@ -668,47 +578,25 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 根据两个column字段的值删除对象, 必须是Entity Class - * - * @param - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - */ @Override - public void deleteByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2) { + public void delete(Class clazz, FilterNode node) { Connection conn = createWriteSQLConnection(); try { - deleteByTwoColumn(conn, clazz, column1, key1, column2, key2); + delete(conn, clazz, node); } finally { closeSQLConnection(conn); } } - /** - * 根据两个column字段的值删除对象, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - */ @Override - public void deleteByTwoColumn(final DataConnection conn, Class clazz, String column1, Serializable key1, String column2, Serializable key2) { - deleteByTwoColumn((Connection) conn.getConnection(), clazz, column1, key1, column2, key2); + public void delete(final DataConnection conn, Class clazz, FilterNode node) { + delete((Connection) conn.getConnection(), clazz, node); } - private void deleteByTwoColumn(final Connection conn, Class clazz, String column1, Serializable key1, String column2, Serializable key2) { + private void delete(final Connection conn, Class clazz, FilterNode node) { try { final EntityInfo info = loadEntityInfo(clazz); - String sql = "DELETE FROM " + info.getTable() + " WHERE " + info.getSQLColumn(column1) + " = " + formatToString(key1) - + " AND " + info.getSQLColumn(column2) + " = " + formatToString(key2); + String sql = "DELETE FROM " + info.getTable() + " a" + node.createFilterSQLExpress(info, null); if (debug.get()) logger.finest(clazz.getSimpleName() + " delete sql=" + sql); final Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -717,9 +605,7 @@ public final class DataJDBCSource implements DataSource { //------------------------------------ final EntityCache cache = info.getCache(); if (cache == null) return; - final Attribute attr1 = info.getAttribute(column1); - final Attribute attr2 = info.getAttribute(column2); - Serializable[] ids = cache.delete((T t) -> key1.equals(attr1.get(t)) && key2.equals(attr2.get(t))); + Serializable[] ids = cache.delete(node.createFilterPredicate(info, null)); if (cacheListener != null) cacheListener.delete(name, clazz, ids); } catch (SQLException e) { throw new RuntimeException(e); @@ -753,13 +639,6 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 更新对象, 必须是Entity对象 - * - * @param - * @param conn - * @param values - */ @Override public void update(final DataConnection conn, T... values) { update((Connection) conn.getConnection(), values); @@ -841,16 +720,6 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 根据主键值更新对象的column对应的值, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param id - * @param column - * @param value - */ @Override public void updateColumn(DataConnection conn, Class clazz, Serializable id, String column, Serializable value) { updateColumn((Connection) conn.getConnection(), clazz, id, column, value); @@ -859,7 +728,8 @@ public final class DataJDBCSource implements DataSource { private void updateColumn(Connection conn, Class clazz, Serializable id, String column, Serializable value) { try { final EntityInfo info = loadEntityInfo(clazz); - String sql = "UPDATE " + info.getTable() + " SET " + info.getSQLColumn(column) + " = " + formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + formatToString(id); + String sql = "UPDATE " + info.getTable() + " SET " + info.getSQLColumn(column) + " = " + + formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + formatToString(id); if (debug.get()) logger.finest(clazz.getSimpleName() + " update sql=" + sql); final Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -896,16 +766,6 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 根据主键值给对象的column对应的值+incvalue, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param id - * @param column - * @param incvalue - */ @Override public void updateColumnIncrement(DataConnection conn, Class clazz, Serializable id, String column, long incvalue) { updateColumnIncrement((Connection) conn.getConnection(), clazz, id, column, incvalue); @@ -915,7 +775,8 @@ public final class DataJDBCSource implements DataSource { try { final EntityInfo info = loadEntityInfo(clazz); String col = info.getSQLColumn(column); - String sql = "UPDATE " + info.getTable() + " SET " + col + " = " + col + " + (" + incvalue + ") WHERE " + info.getPrimarySQLColumn() + " = " + formatToString(id); + String sql = "UPDATE " + info.getTable() + " SET " + col + " = " + col + " + (" + incvalue + + ") WHERE " + info.getPrimarySQLColumn() + " = " + formatToString(id); if (debug.get()) logger.finest(clazz.getSimpleName() + " update sql=" + sql); final Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -951,36 +812,27 @@ public final class DataJDBCSource implements DataSource { } } - /** - * 更新对象指定的一些字段, 必须是Entity对象 - * - * @param - * @param conn - * @param value - * @param columns - */ @Override public void updateColumns(final DataConnection conn, final T value, final String... columns) { updateColumns((Connection) conn.getConnection(), value, columns); } private void updateColumns(final Connection conn, final T value, final String... columns) { - if (columns.length < 1) return; + if (value == null || columns.length < 1) return; try { final Class clazz = (Class) value.getClass(); final EntityInfo info = loadEntityInfo(clazz); StringBuilder setsql = new StringBuilder(); - Attribute[] attrs = new Attribute[columns.length]; - int i = - 1; - final Serializable id = (Serializable) info.getPrimary().get(value); + final Serializable id = info.getPrimary().get(value); + final List> attrs = new ArrayList<>(); for (String col : columns) { if (setsql.length() > 0) setsql.append(','); - attrs[++i] = info.getAttribute(col); - setsql.append(info.getSQLColumn(col)).append(" = ") - .append(formatToString(attrs[i].get(value))); + Attribute attr = info.getUpdateAttribute(col); + if (attr == null) continue; + setsql.append(info.getSQLColumn(col)).append(" = ").append(formatToString(attr.get(value))); } - String sql = "UPDATE " + info.getTable() + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " - + formatToString(id); + String sql = "UPDATE " + info.getTable() + " SET " + setsql + + " WHERE " + info.getPrimarySQLColumn() + " = " + formatToString(id); if (debug.get()) logger.finest(value.getClass().getSimpleName() + ": " + sql); final Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -1010,8 +862,10 @@ public final class DataJDBCSource implements DataSource { final EntityInfo info = loadEntityInfo(clazz); final EntityCache cache = info.getCache(); if (cache == null) return; + String column = info.getPrimary().field(); for (Serializable id : ids) { - T value = find(clazz, null, false, id); + Sheet sheet = querySheet(false, clazz, null, FLIPPER_ONE, FilterNode.create(column, id), null); + T value = sheet.isEmpty() ? null : sheet.list().get(0); if (value != null) cache.update(value); } } @@ -1020,84 +874,111 @@ public final class DataJDBCSource implements DataSource { //-----------------------------MAX----------------------------- @Override public Number getMaxSingleResult(final Class entityClass, final String column) { - return getMaxSingleResult(entityClass, column, null); + return getMaxSingleResult(entityClass, column, (FilterNode) null); } @Override public Number getMaxSingleResult(final Class entityClass, final String column, FilterBean bean) { - return getSingleResult(ReckonType.MAX, entityClass, column, bean); + return getSingleResult(ReckonType.MAX, entityClass, column, null, bean); + } + + @Override + public Number getMaxSingleResult(final Class entityClass, final String column, FilterNode node) { + return getSingleResult(ReckonType.MAX, entityClass, column, node, null); } //-----------------------------MIN----------------------------- @Override public Number getMinSingleResult(final Class entityClass, final String column) { - return getMinSingleResult(entityClass, column, null); + return getMinSingleResult(entityClass, column, (FilterNode) null); } @Override public Number getMinSingleResult(final Class entityClass, final String column, FilterBean bean) { - return getSingleResult(ReckonType.MIN, entityClass, column, bean); + return getSingleResult(ReckonType.MIN, entityClass, column, null, bean); + } + + @Override + public Number getMinSingleResult(final Class entityClass, final String column, FilterNode node) { + return getSingleResult(ReckonType.MIN, entityClass, column, node, null); } //-----------------------------SUM----------------------------- @Override public Number getSumSingleResult(final Class entityClass, final String column) { - return getSumSingleResult(entityClass, column, null); + return getSumSingleResult(entityClass, column, (FilterNode) null); } @Override public Number getSumSingleResult(final Class entityClass, final String column, FilterBean bean) { - return getSingleResult(ReckonType.SUM, entityClass, column, bean); + return getSingleResult(ReckonType.SUM, entityClass, column, null, bean); + } + + @Override + public Number getSumSingleResult(final Class entityClass, final String column, FilterNode node) { + return getSingleResult(ReckonType.SUM, entityClass, column, node, null); } //----------------------------COUNT---------------------------- @Override public Number getCountSingleResult(final Class entityClass) { - return getCountSingleResult(entityClass, null); + return getCountSingleResult(entityClass, (FilterNode) null); } @Override public Number getCountSingleResult(final Class entityClass, FilterBean bean) { - return getSingleResult(ReckonType.COUNT, entityClass, null, bean); + return getSingleResult(ReckonType.COUNT, entityClass, null, null, bean); + } + + @Override + public Number getCountSingleResult(final Class entityClass, FilterNode node) { + return getSingleResult(ReckonType.COUNT, entityClass, null, node, null); } @Override public Number getCountDistinctSingleResult(final Class entityClass, String column) { - return getCountDistinctSingleResult(entityClass, column, null); + return getCountDistinctSingleResult(entityClass, column, (FilterNode) null); } @Override public Number getCountDistinctSingleResult(final Class entityClass, String column, FilterBean bean) { - return getSingleResult(ReckonType.DISTINCTCOUNT, entityClass, column, bean); + return getSingleResult(ReckonType.DISTINCTCOUNT, entityClass, column, null, bean); + } + + @Override + public Number getCountDistinctSingleResult(final Class entityClass, final String column, FilterNode node) { + return getSingleResult(ReckonType.DISTINCTCOUNT, entityClass, column, node, null); } //-----------------------------AVG----------------------------- @Override public Number getAvgSingleResult(final Class entityClass, final String column) { - return getAvgSingleResult(entityClass, column, null); + return getAvgSingleResult(entityClass, column, (FilterNode) null); } @Override public Number getAvgSingleResult(final Class entityClass, final String column, FilterBean bean) { - return getSingleResult(ReckonType.AVG, entityClass, column, bean); + return getSingleResult(ReckonType.AVG, entityClass, column, null, bean); } - private Number getSingleResult(final ReckonType type, final Class entityClass, final String column, FilterBean bean) { + @Override + public Number getAvgSingleResult(final Class entityClass, final String column, FilterNode node) { + return getSingleResult(ReckonType.AVG, entityClass, column, node, null); + } + + private Number getSingleResult(final ReckonType type, final Class entityClass, final String column, FilterNode node, FilterBean bean) { final Connection conn = createReadSQLConnection(); try { final EntityInfo info = loadEntityInfo(entityClass); final EntityCache cache = info.getCache(); if (cache != null && cache.isFullLoaded()) { - Predicate filter = null; - boolean valid = true; - if (bean != null) { - FilterInfo finfo = FilterInfo.load(bean.getClass(), this); - valid = finfo.isValidCacheJoin(); - if (valid) filter = finfo.getFilterPredicate(info, bean); + Predicate filter = node == null ? null : node.createFilterPredicate(info, bean); + if (node == null || node.isJoinAllCached()) { + return cache.getSingleResult(type, column == null ? null : info.getAttribute(column), filter); } - if (valid) return cache.getSingleResult(type, column == null ? null : info.getAttribute(column), filter); } - final String sql = "SELECT " + type.getReckonColumn("a." + column) + " FROM " + info.getTable() + " a" + createWhereExpression(info, null, bean); + final String sql = "SELECT " + type.getReckonColumn("a." + column) + " FROM " + info.getTable() + " a" + + (node == null ? "" : node.createFilterSQLExpress(info, bean)); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql); final PreparedStatement prestmt = conn.prepareStatement(sql); Number rs = null; @@ -1126,333 +1007,62 @@ public final class DataJDBCSource implements DataSource { */ @Override public T find(Class clazz, Serializable pk) { - return find(clazz, null, true, pk); + return find(clazz, (SelectColumn) null, pk); } @Override public T find(Class clazz, final SelectColumn selects, Serializable pk) { - return find(clazz, selects, true, pk); + String column = loadEntityInfo(clazz).getPrimary().field(); + Sheet sheet = querySheet(clazz, selects, FLIPPER_ONE, FilterNode.create(column, pk)); + return sheet.isEmpty() ? null : sheet.list().get(0); } - private T find(Class clazz, final SelectColumn selects, boolean readcache, Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (readcache && cache != null) { - T r = cache.find(pk); - if (r != null || cache.isFullLoaded()) return r; - } - final Connection conn = createReadSQLConnection(); - try { - if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + info.querySQL.replace("?", String.valueOf(pk))); - final PreparedStatement prestmt = conn.prepareStatement(info.querySQL); - prestmt.setObject(1, pk); - T rs = null; - ResultSet set = prestmt.executeQuery(); - if (set.next()) { - rs = info.getValue(selects, set); - } - set.close(); - prestmt.close(); - return rs; - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - if (conn != null) closeSQLConnection(conn); - } - } - - /** - * 根据主键值集合获取对象集合 - * - * @param - * @param clazz - * @param ids - * @return - */ - @Override - public T[] find(Class clazz, Serializable... ids) { - EntityInfo info = loadEntityInfo(clazz); - return findByColumn(clazz, info, null, info.getPrimarySQLColumn(), ids); - } - - /** - * 根据唯一索引获取单个对象 - * - * @param - * @param clazz - * @param column - * @param key - * @return - */ @Override public T findByColumn(Class clazz, String column, Serializable key) { - EntityInfo info = loadEntityInfo(clazz); - return findByColumn(clazz, info, null, info.getSQLColumn(column), key)[0]; + return find(clazz, FilterNode.create(column, key)); } - /** - * 根据两个字段的值获取单个对象 - * - * @param - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - * @return - */ - @Override - public T findByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - final Attribute attr1 = info.getAttribute(column1); - final Attribute attr2 = info.getAttribute(column2); - T r = cache.find((T t) -> key1.equals(attr1.get(t)) && key2.equals(attr2.get(t))); - if (r != null || cache.isFullLoaded()) return r; - } - final Connection conn = createReadSQLConnection(); - try { - final String sql = "SELECT * FROM " + info.getTable() + " WHERE " + info.getSQLColumn(column1) + " = ? AND " + info.getSQLColumn(column2) + " = ?"; - if (debug.get() && info.isLoggable(Level.FINEST)) - logger.finest(clazz.getSimpleName() + " find sql=" + sql.replaceFirst("\\?", String.valueOf(key1)).replaceFirst("\\?", String.valueOf(key2))); - final PreparedStatement prestmt = conn.prepareStatement(sql); - prestmt.setObject(1, key1); - prestmt.setObject(2, key2); - T rs = null; - ResultSet set = prestmt.executeQuery(); - if (set.next()) { - rs = info.getValue(null, set); - } - set.close(); - prestmt.close(); - return rs; - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - if (conn != null) closeSQLConnection(conn); - } - } - - /** - * 根据过滤对象FilterBean查询第一个符合条件的对象 - * - * @param - * @param clazz - * @param bean - * @return - */ @Override public T find(final Class clazz, final FilterBean bean) { Sheet sheet = querySheet(clazz, FLIPPER_ONE, bean); return sheet.isEmpty() ? null : sheet.list().get(0); } - /** - * 根据唯一索引获取对象 - * - * @param - * @param clazz - * @param column - * @param keys - * @return - */ @Override - public T[] findByColumn(Class clazz, String column, Serializable... keys) { - return findByColumn(clazz, (SelectColumn) null, column, keys); - } - - /** - * 根据字段值拉去对象, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects 只拉起指定字段名或者排除指定字段名的值 - * @param column - * @param keys - * @return - */ - @Override - - public T[] findByColumn(Class clazz, final SelectColumn selects, String column, Serializable... keys) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Attribute idattr = info.getAttribute(column); - List list = cache.queryList(selects, (x) -> Arrays.binarySearch(keys, idattr.get(x)) >= 0, null); - final T[] rs = (T[]) Array.newInstance(clazz, keys.length); - if (!list.isEmpty()) { - for (int i = 0; i < rs.length; i++) { - T item = null; - for (T s : list) { - if (keys[i].equals(idattr.get(s))) { - item = s; - break; - } - } - rs[i] = item; - } - } - if (!list.isEmpty() || cache.isFullLoaded()) return rs; - } - return findByColumn(clazz, info, selects, info.getSQLColumn(column), keys); - } - - private T[] findByColumn(Class clazz, final EntityInfo info, final SelectColumn selects, String sqlcolumn, Serializable... keys) { - if (keys.length < 1) return (T[]) Array.newInstance(clazz, 0); - final Connection conn = createReadSQLConnection(); - try { - final String sql = "SELECT * FROM " + info.getTable() + " WHERE " + sqlcolumn + " = ?"; - if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " query sql=" + sql); - final PreparedStatement prestmt = conn.prepareStatement(sql); - T[] rs = (T[]) Array.newInstance(clazz, keys.length); - for (int i = 0; i < keys.length; i++) { - prestmt.clearParameters(); - prestmt.setObject(1, keys[i]); - T one = null; - ResultSet set = prestmt.executeQuery(); - if (set.next()) { - one = info.getValue(selects, set); - } - rs[i] = one; - set.close(); - } - prestmt.close(); - return rs; - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - if (conn != null) closeSQLConnection(conn); - } + public T find(final Class clazz, final FilterNode node) { + Sheet sheet = querySheet(clazz, FLIPPER_ONE, node); + return sheet.isEmpty() ? null : sheet.list().get(0); } //-----------------------list set---------------------------- - @Override - public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, Serializable key) { - return formatCollectionToIntArray(queryColumnSet(selectedColumn, clazz, column, key)); - } - - @Override - public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, Serializable key) { - return formatCollectionToLongArray(queryColumnSet(selectedColumn, clazz, column, key)); - } - - @Override - public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, Serializable key) { - return formatCollectionToIntArray(queryColumnList(selectedColumn, clazz, column, key)); - } - - @Override - public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, Serializable key) { - return formatCollectionToLongArray(queryColumnList(selectedColumn, clazz, column, key)); - } - @Override public Set queryColumnSet(String selectedColumn, Class clazz, String column, Serializable key) { - return queryColumnSet(selectedColumn, clazz, column, FilterExpress.EQUAL, key); + return queryColumnSet(selectedColumn, clazz, FilterNode.create(column, key)); + } + + @Override + public Set queryColumnSet(String selectedColumn, Class clazz, FilterBean bean) { + return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, bean)); + } + + @Override + public Set queryColumnSet(String selectedColumn, Class clazz, FilterNode node) { + return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, node)); } @Override public List queryColumnList(String selectedColumn, Class clazz, String column, Serializable key) { - return queryColumnList(selectedColumn, clazz, column, FilterExpress.EQUAL, key); + return queryColumnList(selectedColumn, clazz, FilterNode.create(column, key)); } @Override - public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return formatCollectionToIntArray(queryColumnSet(selectedColumn, clazz, column, express, key)); + public List queryColumnList(String selectedColumn, Class clazz, FilterBean bean) { + return (List) queryColumnSheet(selectedColumn, clazz, null, bean).list(true); } @Override - public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return formatCollectionToLongArray(queryColumnSet(selectedColumn, clazz, column, express, key)); - } - - @Override - public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return formatCollectionToIntArray(queryColumnList(selectedColumn, clazz, column, express, key)); - } - - @Override - public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return formatCollectionToLongArray(queryColumnList(selectedColumn, clazz, column, express, key)); - } - - @Override - public Set queryColumnSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return (Set) queryColumnCollection(true, selectedColumn, clazz, column, express, key); - } - - @Override - public List queryColumnList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - return (List) queryColumnCollection(false, selectedColumn, clazz, column, express, key); - } - - private static int[] formatCollectionToIntArray(Collection collection) { - if (collection == null || collection.isEmpty()) return new int[0]; - int[] rs = new int[collection.size()]; - int i = 0; - for (int v : collection) { - rs[i++] = v; - } - return rs; - } - - private static long[] formatCollectionToLongArray(Collection collection) { - if (collection == null || collection.isEmpty()) return new long[0]; - long[] rs = new long[collection.size()]; - int i = 0; - for (long v : collection) { - rs[i++] = v; - } - return rs; - } - - /** - * 根据指定字段值查询对象某个字段的集合 - * - * @param - * @param - * @param set - * @param selectedColumn - * @param clazz - * @param column - * @param express - * @param key - * @return - */ - protected final Collection queryColumnCollection(final boolean set, String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Predicate filter = genFilter(info.getAttribute(column), express, key); - List list = cache.queryList(SelectColumn.createIncludes(selectedColumn), filter, null); - final Collection rs = set ? new LinkedHashSet<>() : new ArrayList<>(); - if (!list.isEmpty()) { - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - for (T t : list) { - rs.add(selected.get(t)); - } - } - if (!rs.isEmpty() || cache.isFullLoaded()) return rs; - } - final Connection conn = createReadSQLConnection(); - try { - final Collection collection = set ? new LinkedHashSet<>() : new ArrayList<>(); - final String sql = genSQL(info.getSQLColumn(selectedColumn), info, column, express, key); - if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " query sql=" + sql); - final Statement ps = conn.createStatement(); - final ResultSet rs = ps.executeQuery(sql); - while (rs.next()) { - collection.add((V) rs.getObject(1)); - } - rs.close(); - ps.close(); - return collection; - } catch (Exception ex) { - throw new RuntimeException(ex); - } finally { - closeSQLConnection(conn); - } + public List queryColumnList(String selectedColumn, Class clazz, FilterNode node) { + return (List) queryColumnSheet(selectedColumn, clazz, null, node).list(true); } /** @@ -1466,195 +1076,7 @@ public final class DataJDBCSource implements DataSource { */ @Override public List queryList(Class clazz, String column, Serializable key) { - return queryList(clazz, (SelectColumn) null, column, key); - } - - @Override - public List queryList(Class clazz, String column, FilterExpress express, Serializable key) { - return queryList(clazz, (SelectColumn) null, column, express, key); - } - - /** - * 根据指定字段值查询对象集合, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param column - * @param key - * @return - */ - @Override - public List queryList(Class clazz, final SelectColumn selects, String column, Serializable key) { - return queryList(clazz, selects, column, FilterExpress.EQUAL, key); - } - - /** - * 根据指定字段值查询对象集合, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param column - * @param express - * @param key - * @return - */ - @Override - public List queryList(Class clazz, final SelectColumn selects, String column, FilterExpress express, Serializable key) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Predicate filter = genFilter(info.getAttribute(column), express, key); - List rs = cache.queryList(selects, filter, null); - if (!rs.isEmpty() || cache.isFullLoaded()) return rs; - } - final Connection conn = createReadSQLConnection(); - try { - final SelectColumn sels = selects; - final List list = new ArrayList(); - final String sql = genSQL("*", info, column, express, key); - if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " query sql=" + sql); - final Statement ps = conn.createStatement(); - final ResultSet set = ps.executeQuery(sql); - while (set.next()) { - list.add(info.getValue(sels, set)); - } - set.close(); - ps.close(); - return list; - } catch (Exception ex) { - throw new RuntimeException(ex); - } finally { - closeSQLConnection(conn); - } - } - - private String genSQL(String queryColumn, EntityInfo info, String column, FilterExpress express, Serializable key) { - String sql = "SELECT " + queryColumn + " FROM " + info.getTable(); - if (key instanceof Number) { - sql += " WHERE " + info.getSQLColumn(column) + " " + express.value() + " " + key; - } else if (key instanceof Collection) { - Collection list = (Collection) key; - if (list.isEmpty()) { - sql += " WHERE 1 " + (express == FilterExpress.NOTIN ? "=" : "!=") + " 1"; - } else { - StringBuilder sb = new StringBuilder(); - for (Object o : list) { - if (sb.length() > 0) sb.append(','); - if (o instanceof Number) { - sb.append('"').append(o).append('"'); - } else { - sb.append('"').append(o.toString().replace("\"", "\\\"")).append('"'); - } - } - sql += " WHERE " + info.getSQLColumn(column) + " " + express.value() + " (" + sb + ")"; - } - } else if (key.getClass().isArray()) { - int len = Array.getLength(key); - if (len == 0) { - sql += " WHERE 1 " + (express == FilterExpress.NOTIN ? "=" : "!=") + " 1"; - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < len; i++) { - Object o = Array.get(key, i); - if (sb.length() > 0) sb.append(','); - if (o instanceof Number) { - sb.append('"').append(o).append('"'); - } else { - sb.append('"').append(o.toString().replace("\"", "\\\"")).append('"'); - } - } - sql += " WHERE " + info.getSQLColumn(column) + " " + express.value() + " (" + sb + ")"; - } - } else { - sql += " WHERE " + info.getSQLColumn(column) + " " + express.value() + " \"" + key.toString().replace("\"", "\\\"") + "\""; - } - return sql; - } - - private Predicate genFilter(final Attribute attr, FilterExpress express, Serializable key) { - Predicate filter = null; - switch (express) { - case EQUAL: - filter = (T t) -> key.equals(attr.get(t)); - break; - case NOTEQUAL: - filter = (T t) -> !key.equals(attr.get(t)); - break; - case GREATERTHAN: - filter = (T t) -> ((Number) attr.get(t)).longValue() > ((Number) key).longValue(); - break; - case LESSTHAN: - filter = (T t) -> ((Number) attr.get(t)).longValue() < ((Number) key).longValue(); - break; - case GREATERTHANOREQUALTO: - filter = (T t) -> ((Number) attr.get(t)).longValue() >= ((Number) key).longValue(); - break; - case LESSTHANOREQUALTO: - filter = (T t) -> ((Number) attr.get(t)).longValue() <= ((Number) key).longValue(); - break; - case IN: - case NOTIN: - if (key instanceof Collection) { - filter = (T t) -> { - Object rs = attr.get(t); - return rs != null && ((Collection) key).contains(rs); - }; - } else { - Serializable[] keys; - if (key.getClass().isArray()) { - Class keytype = key.getClass(); - if (keytype.getComponentType().isPrimitive()) { - Object array = key; - Serializable[] keys0 = new Serializable[Array.getLength(array)]; - for (int i = 0; i < keys0.length; i++) { - keys0[i] = (Serializable) Array.get(array, i); - } - keys = keys0; - } else { - keys = (Serializable[]) key; - } - } else { - keys = new Serializable[]{key}; - } - Serializable[] keys0 = keys; - filter = (T t) -> { - Object rs = attr.get(t); - return rs != null && Arrays.binarySearch(keys0, rs) > -1; - }; - } - if (express == FilterExpress.NOTIN) filter = filter.negate(); - break; - case LIKE: - filter = (T t) -> { - Object rs = attr.get(t); - return rs != null && rs.toString().contains(key.toString()); - }; - break; - case NOTLIKE: - filter = (T t) -> { - Object rs = attr.get(t); - return rs == null || !rs.toString().contains(key.toString()); - }; - break; - case ISNULL: - filter = (T t) -> attr.get(t) == null; - break; - case ISNOTNULL: - filter = (T t) -> attr.get(t) != null; - break; - case OPAND: - filter = (T t) -> (((Number) attr.get(t)).longValue() & ((Number) key).longValue()) > 0; - break; - case OPOR: - filter = (T t) -> (((Number) attr.get(t)).longValue() | ((Number) key).longValue()) > 0; - break; - case OPANDNO: - filter = (T t) -> (((Number) attr.get(t)).longValue() & ((Number) key).longValue()) == 0; - break; - } - return filter; + return queryList(clazz, FilterNode.create(column, key)); } /** @@ -1670,6 +1092,11 @@ public final class DataJDBCSource implements DataSource { return queryList(clazz, null, bean); } + @Override + public List queryList(final Class clazz, final FilterNode node) { + return queryList(clazz, null, node); + } + /** * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectColumn指定的字段 * @@ -1684,6 +1111,11 @@ public final class DataJDBCSource implements DataSource { return querySheet(clazz, selects, null, bean).list(true); } + @Override + public List queryList(final Class clazz, final SelectColumn selects, final FilterNode node) { + return querySheet(clazz, selects, null, node).list(true); + } + //-----------------------sheet---------------------------- /** * 根据指定参数查询对象某个字段的集合 @@ -1698,7 +1130,16 @@ public final class DataJDBCSource implements DataSource { */ @Override public Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterBean bean) { - Sheet sheet = querySheet(clazz, SelectColumn.createIncludes(selectedColumn), flipper, bean); + return queryColumnSheet(selectedColumn, clazz, flipper, null, bean); + } + + @Override + public Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterNode node) { + return queryColumnSheet(selectedColumn, clazz, flipper, node, null); + } + + private Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterNode node, final FilterBean bean) { + Sheet sheet = querySheet(true, clazz, SelectColumn.createIncludes(selectedColumn), flipper, node, bean); final Sheet rs = new Sheet<>(); if (sheet.isEmpty()) return rs; rs.setTotal(sheet.getTotal()); @@ -1726,6 +1167,11 @@ public final class DataJDBCSource implements DataSource { return querySheet(clazz, null, flipper, bean); } + @Override + public Sheet querySheet(Class clazz, final Flipper flipper, final FilterNode node) { + return querySheet(clazz, null, flipper, node); + } + /** * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据, 对象只填充或排除SelectColumn指定的字段 * @@ -1738,17 +1184,20 @@ public final class DataJDBCSource implements DataSource { */ @Override public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySheet(true, clazz, selects, flipper, null, bean); + } + + @Override + public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheet(true, clazz, selects, flipper, node, null); + } + + private Sheet querySheet(boolean readcache, Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) { final EntityInfo info = loadEntityInfo(clazz); final EntityCache cache = info.getCache(); - if (cache != null) { - Predicate filter = null; - boolean valid = true; - if (bean != null) { - FilterInfo finfo = FilterInfo.load(bean.getClass(), this); - valid = finfo.isValidCacheJoin(); - if (valid) filter = finfo.getFilterPredicate(info, bean); - } - if (valid) { + if (readcache && cache != null) { + Predicate filter = node == null ? null : node.createFilterPredicate(info, bean); + if (node == null || node.isJoinAllCached()) { Sheet sheet = cache.querySheet(selects, filter, flipper, FilterNode.createFilterComparator(info, flipper)); if (!sheet.isEmpty() || cache.isFullLoaded()) return sheet; } @@ -1757,7 +1206,8 @@ public final class DataJDBCSource implements DataSource { try { final SelectColumn sels = selects; final List list = new ArrayList(); - final String sql = "SELECT a.* FROM " + info.getTable() + " a" + createWhereExpression(info, flipper, bean); + final String sql = "SELECT a.* FROM " + info.getTable() + " a" + + (node == null ? "" : node.createFilterSQLExpress(info, bean)) + createFilterSQLOrderBy(info, flipper); if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " query sql=" + sql + (flipper == null ? "" : (" LIMIT " + flipper.index() + "," + flipper.getSize()))); final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); @@ -1786,519 +1236,4 @@ public final class DataJDBCSource implements DataSource { closeSQLConnection(conn); } } - - private String createWhereExpression(final EntityInfo info, final Flipper flipper, final FilterBean bean) { - if (bean == null && flipper == null) return ""; - boolean emptySort = flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty(); - StringBuilder where = null; - boolean join = false; - if (bean != null) { - final FilterInfo filter = FilterInfo.load(bean.getClass(), this); - join = filter.isJoin(); - where = filter.createWhereSql(info.getPrimarySQLColumn(), bean); - } - if (emptySort) return where == null ? "" : where.toString(); - if (where == null) where = new StringBuilder(); - where.append(" ORDER BY "); - if (info.isNoAlias() && !join) { - where.append(flipper.getSort()); - } else { - boolean flag = false; - for (String item : flipper.getSort().split(",")) { - if (item.isEmpty()) continue; - String[] sub = item.split("\\s+"); - if (flag) where.append(','); - if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) { - where.append("a.").append(info.getSQLColumn(sub[0])).append(" ASC"); - } else { - where.append("a.").append(info.getSQLColumn(sub[0])).append(" DESC"); - } - flag = true; - } - } - return where.toString(); - } - - //---------------------------------------------------------------------- - public static final class JDBCPoolSource { - - private static final Map>>> maps = new HashMap<>(); - - private final AtomicLong usingCounter = new AtomicLong(); - - private final AtomicLong creatCounter = new AtomicLong(); - - private final AtomicLong cycleCounter = new AtomicLong(); - - private final AtomicLong saveCounter = new AtomicLong(); - - private final ConnectionPoolDataSource source; - - private final ArrayBlockingQueue queue; - - private final ConnectionEventListener listener; - - private final DataJDBCSource dataSource; - - private final String stype; // "" 或 "read" 或 "write" - - private final int max; - - private String url; - - private String user; - - private String password; - - public JDBCPoolSource(DataJDBCSource source, String stype, Properties prop) { - this.dataSource = source; - this.stype = stype; - this.source = createDataSource(prop); - this.url = prop.getProperty(JDBC_URL); - this.user = prop.getProperty(JDBC_USER); - this.password = prop.getProperty(JDBC_PWD); - this.max = Integer.decode(prop.getProperty(JDBC_CONNECTIONMAX, "" + Runtime.getRuntime().availableProcessors() * 16)); - this.queue = new ArrayBlockingQueue<>(this.max); - this.listener = new ConnectionEventListener() { - - @Override - public void connectionClosed(ConnectionEvent event) { - PooledConnection pc = (PooledConnection) event.getSource(); - if (queue.offer(pc)) saveCounter.incrementAndGet(); - } - - @Override - public void connectionErrorOccurred(ConnectionEvent event) { - usingCounter.decrementAndGet(); - if ("08S01".equals(event.getSQLException().getSQLState())) return; //MySQL特性, 长时间连接没使用会抛出com.mysql.jdbc.exceptions.jdbc4.CommunicationsException - dataSource.logger.log(Level.WARNING, "connectionErronOccurred [" + event.getSQLException().getSQLState() + "]", event.getSQLException()); - } - }; - try { - this.watch(); - } catch (Exception e) { - dataSource.logger.log(Level.WARNING, DataSource.class.getSimpleName() + " watch " + dataSource.conf + " error", e); - } - } - - private void watch() throws IOException { - if (dataSource.conf == null || dataSource.name == null) return; - final String file = dataSource.conf.getFile(); - final File f = new File(file); - if (!f.isFile() || !f.canRead()) return; - synchronized (maps) { - SimpleEntry>> entry = maps.get(file); - if (entry != null) { - entry.getValue().add(new WeakReference<>(this)); - return; - } - final WatchService watcher = f.toPath().getFileSystem().newWatchService(); - final List> list = new CopyOnWriteArrayList<>(); - Thread watchThread = new Thread() { - - @Override - public void run() { - try { - while (!this.isInterrupted()) { - final WatchKey key = watcher.take(); - Thread.sleep(3000); //防止文件正在更新过程中去读取 - final Map m = loadProperties(new FileInputStream(file)); - key.pollEvents().stream().forEach((event) -> { - if (event.kind() != ENTRY_MODIFY) return; - if (!((Path) event.context()).toFile().getName().equals(f.getName())) return; - for (WeakReference ref : list) { - JDBCPoolSource pool = ref.get(); - if (pool == null) continue; - try { - Properties property = m.get(pool.dataSource.name); - if (property == null) property = m.get(pool.dataSource.name + "." + pool.stype); - if (property != null) pool.change(property); - } catch (Exception ex) { - dataSource.logger.log(Level.INFO, event.context() + " occur error", ex); - } - } - }); - key.reset(); - } - } catch (Exception e) { - dataSource.logger.log(Level.WARNING, "DataSource watch " + file + " occur error", e); - } - } - }; - f.getParentFile().toPath().register(watcher, ENTRY_MODIFY); - watchThread.setName("DataSource-Watch-" + maps.size() + "-Thread"); - watchThread.setDaemon(true); - watchThread.start(); - dataSource.logger.log(Level.FINER, watchThread.getName() + " start watching " + file); - //----------------------------------------------------------- - list.add(new WeakReference<>(this)); - maps.put(file, new SimpleEntry<>(watcher, list)); - } - } - - public void change(Properties property) { - Method seturlm; - Class clazz = source.getClass(); - String newurl = property.getProperty(JDBC_URL); - String newuser = property.getProperty(JDBC_USER); - String newpassword = property.getProperty(JDBC_PWD); - if (this.url.equals(newurl) && this.user.equals(newuser) && this.password.equals(newpassword)) return; - try { - try { - seturlm = clazz.getMethod("setUrl", String.class); - } catch (Exception e) { - seturlm = clazz.getMethod("setURL", String.class); - } - seturlm.invoke(source, newurl); - clazz.getMethod("setUser", String.class).invoke(source, newuser); - clazz.getMethod("setPassword", String.class).invoke(source, newpassword); - this.url = newurl; - this.user = newuser; - this.password = newpassword; - dataSource.logger.log(Level.INFO, DataSource.class.getSimpleName() + "(" + dataSource.name + "." + stype + ") change (" + property + ")"); - } catch (Exception e) { - dataSource.logger.log(Level.SEVERE, DataSource.class.getSimpleName() + " dynamic change JDBC (url userName password) error", e); - } - } - - public Connection poll() { - return poll(0, null); - } - - private Connection poll(final int count, SQLException e) { - if (count >= 3) { - dataSource.logger.log(Level.WARNING, "create pooled connection error", e); - throw new RuntimeException(e); - } - PooledConnection result = queue.poll(); - if (result == null) { - if (usingCounter.get() >= max) { - try { - result = queue.poll(6, TimeUnit.SECONDS); - } catch (Exception t) { - dataSource.logger.log(Level.WARNING, "take pooled connection error", t); - } - } - if (result == null) { - try { - result = source.getPooledConnection(); - result.addConnectionEventListener(listener); - usingCounter.incrementAndGet(); - } catch (SQLException ex) { - return poll(count + 1, ex); - } - creatCounter.incrementAndGet(); - } - } else { - cycleCounter.incrementAndGet(); - } - Connection conn; - try { - conn = result.getConnection(); - if (!conn.isValid(1)) { - dataSource.logger.info("sql connection is not vaild"); - usingCounter.decrementAndGet(); - return poll(0, null); - } - } catch (SQLException ex) { - if (!"08S01".equals(ex.getSQLState())) {//MySQL特性, 长时间连接没使用会抛出com.mysql.jdbc.exceptions.jdbc4.CommunicationsException - dataSource.logger.log(Level.FINER, "result.getConnection from pooled connection abort [" + ex.getSQLState() + "]", ex); - } - return poll(0, null); - } - return conn; - } - - public long getCreatCount() { - return creatCounter.longValue(); - } - - public long getCycleCount() { - return cycleCounter.longValue(); - } - - public long getSaveCount() { - return saveCounter.longValue(); - } - - public void close() { - queue.stream().forEach(x -> { - try { - x.close(); - } catch (Exception e) { - } - }); - } - } - - //---------------------------------------------------------------------- - private static class AttributeX implements Attribute { - - private final Class clazz; - - private final Class type; - - private final Attribute attribute; - - private final String fieldName; - - public AttributeX(Class clazz, Class type, Attribute attribute, String fieldname) { - this.clazz = clazz; - this.type = type; - this.attribute = attribute; - this.fieldName = fieldname; - } - - @Override - public Class type() { - return type; - } - - @Override - public Class declaringClass() { - return clazz; - } - - @Override - public String field() { - return attribute.field(); - } - - @Override - public F get(T obj) { - return attribute.get(obj); - } - - @Override - public void set(T obj, F value) { - Object o = value; - if (o != null) { - if (type == long.class) { - o = ((Number) o).longValue(); - } else if (type == int.class) { - o = ((Number) o).intValue(); - } else if (type == short.class) { - o = ((Number) o).shortValue(); - } - } - attribute.set(obj, (F) o); - } - - public void setValue(SelectColumn sels, T obj, ResultSet set) throws SQLException { - if (sels == null || sels.validate(this.fieldName)) { - Object o = set.getObject(this.attribute.field()); - if (o != null) { - if (type == long.class) { - o = ((Number) o).longValue(); - } else if (type == int.class) { - o = ((Number) o).intValue(); - } else if (type == short.class) { - o = ((Number) o).shortValue(); - } - } - attribute.set(obj, (F) o); - } - } - - } - - private static class EntityXXInfo { - - private static final ConcurrentHashMap entityxInfos = new ConcurrentHashMap<>(); - - private final int nodeid; - - private final EntityInfo inner; - - final Class[] distributeTables; - - final boolean autoGenerated; - - final boolean distributed; - - boolean initedPrimaryValue = false; - - final AtomicLong primaryValue = new AtomicLong(0); - - final int allocationSize; - - private final ActionInfo query; - - private final ActionInfo insert; - - private final ActionInfo update; - - private final ActionInfo delete; - - //表字段与字段名是否全部一致 - private final boolean same; - - private final int logLevel; - - private class ActionInfo { - - final String sql; - - final AttributeX[] attributes; - - public ActionInfo(String sql, List> list) { - this.sql = sql; - this.attributes = list.toArray(new AttributeX[list.size()]); - } - - public ActionInfo(String sql, AttributeX... attributes) { - this.sql = sql; - this.attributes = attributes; - } - } - - public EntityXXInfo(DataJDBCSource source, Class type) { - this.inner = EntityInfo.load(type, source.nodeid, null); - this.nodeid = source.nodeid; - DistributeTables dt = type.getAnnotation(DistributeTables.class); - this.distributeTables = dt == null ? null : dt.value(); - - LogLevel ll = type.getAnnotation(LogLevel.class); - this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue(); - - Class cltmp = type; - Set fields = new HashSet<>(); - boolean auto = false; - boolean sqldistribute = false; - int allocationSize0 = 0; - String wheresql = ""; - List> queryattrs = new ArrayList<>(); - List insertcols = new ArrayList<>(); - List> insertattrs = new ArrayList<>(); - List updatecols = new ArrayList<>(); - List> updateattrs = new ArrayList<>(); - boolean same0 = true; - Class idfieldtype = int.class; - do { - for (Field field : cltmp.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (Modifier.isFinal(field.getModifiers())) continue; - if (field.getAnnotation(Transient.class) != null) continue; - final String fieldname = field.getName(); - if (fields.contains(fieldname)) continue; - fields.add(fieldname); - final Column col = field.getAnnotation(Column.class); - final String sqlfield = col == null || col.name().isEmpty() ? fieldname : col.name(); - if (same0) same0 = fieldname.equals(sqlfield); - final Class fieldtype = field.getType(); - Attribute attribute = inner.getAttribute(fieldname); - if (attribute == null) continue; - AttributeX attr = new AttributeX(cltmp, fieldtype, attribute, fieldname); - if (field.getAnnotation(Id.class) != null) { - idfieldtype = fieldtype; - GeneratedValue gv = field.getAnnotation(GeneratedValue.class); - auto = gv != null; - if (gv != null && gv.strategy() != GenerationType.IDENTITY) { - throw new RuntimeException(cltmp.getName() + "'s @ID primary not a GenerationType.IDENTITY"); - } - DistributeGenerator dg = field.getAnnotation(DistributeGenerator.class); - if (dg != null) { - if (!fieldtype.isPrimitive()) throw new RuntimeException(cltmp.getName() + "'s @DistributeGenerator primary must be primitive class type field"); - sqldistribute = true; - auto = false; - allocationSize0 = dg.allocationSize(); - primaryValue.set(dg.initialValue()); - } - wheresql = " WHERE " + sqlfield + " = ?"; - if (!auto) { - insertcols.add(sqlfield); - insertattrs.add(attr); - } - } else { - if (col == null || col.insertable()) { - insertcols.add(sqlfield); - insertattrs.add(attr); - } - if (col == null || col.updatable()) { - updatecols.add(sqlfield); - updateattrs.add(attr); - } - } - queryattrs.add(attr); - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - AttributeX idxattr = new AttributeX(type, idfieldtype, inner.getPrimary(), inner.getPrimary().field()); - updateattrs.add(idxattr); - this.autoGenerated = auto; - this.delete = new ActionInfo("DELETE FROM " + inner.getTable() + wheresql, idxattr); - StringBuilder updatesb = new StringBuilder(); - for (String col : updatecols) { - if (updatesb.length() > 0) updatesb.append(','); - updatesb.append(col).append(" = ?"); - } - this.update = new ActionInfo("UPDATE " + inner.getTable() + " SET " + updatesb + wheresql, updateattrs); - StringBuilder insertsb = new StringBuilder(); - StringBuilder insertsb2 = new StringBuilder(); - for (String col : insertcols) { - if (insertsb.length() > 0) insertsb.append(','); - insertsb.append(col); - if (insertsb2.length() > 0) insertsb2.append(','); - insertsb2.append('?'); - } - String insertsql = "INSERT INTO " + inner.getTable() + "(" + insertsb + ") VALUES(" + insertsb2 + ")"; - this.same = same0; - this.distributed = sqldistribute; - this.allocationSize = allocationSize0; - this.insert = new ActionInfo(insertsql, insertattrs); - this.query = new ActionInfo("SELECT * FROM " + inner.getTable() + wheresql, queryattrs); - } - - public static EntityXXInfo load(DataJDBCSource source, Class clazz) { - EntityXXInfo rs = entityxInfos.get(clazz); - if (rs != null) return rs; - synchronized (entityxInfos) { - rs = entityxInfos.get(clazz); - if (rs == null) { - rs = new EntityXXInfo(source, clazz); - entityxInfos.put(clazz, rs); - } - return rs; - } - } - - public boolean isLoggable(Level l) { - return l.intValue() >= this.logLevel; - } - - public T createInstance() { - return inner.getCreator().create(); - } - - public void createPrimaryValue(T src) { - long v = allocationSize > 1 ? (primaryValue.incrementAndGet() * allocationSize + nodeid) : primaryValue.incrementAndGet(); - Class p = inner.getPrimary().type(); - if (p == int.class || p == Integer.class) { - getPrimary().set(src, (Integer) ((Long) v).intValue()); - } else { - getPrimary().set(src, v); - } - } - - public Attribute getPrimary() { - return inner.getPrimary(); - } - - public String getTable() { - return inner.getTable(); - } - - public String getPrimarySQLColumn() { - return inner.getPrimary().field(); - } - - public String getSQLColumn(String fieldname) { - if (same) return fieldname; - return inner.getAttribute(fieldname).field(); - } - - public Attribute getAttribute(String fieldname) { - return inner.getAttribute(fieldname); - } - } - } diff --git a/src/com/wentch/redkale/source/DataJPASource.java b/src/com/wentch/redkale/source/DataJPASource.java index 8dc2dc064..e27168c8c 100644 --- a/src/com/wentch/redkale/source/DataJPASource.java +++ b/src/com/wentch/redkale/source/DataJPASource.java @@ -29,101 +29,154 @@ final class DataJPASource implements DataSource { private final Logger logger = Logger.getLogger(DataJPASource.class.getSimpleName()); - @Override public void updateColumnIncrement(Class clazz, Serializable id, String column, long incvalue) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public void updateColumnIncrement(DataConnection conn, Class clazz, Serializable id, String column, long incvalue) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public void refreshCache(Class clazz) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public T find(Class clazz, FilterBean bean) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public Number getCountDistinctSingleResult(Class entityClass, String column) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public Number getCountDistinctSingleResult(Class entityClass, String column, FilterBean bean) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public Sheet queryColumnSheet(String selectedColumn, Class clazz, Flipper flipper, FilterBean bean) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public Set queryColumnSet(String selectedColumn, Class clazz, String column, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public Set queryColumnSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public List queryColumnList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override public T find(Class clazz, SelectColumn selects, Serializable pk) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + public void delete(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public void delete(DataConnection conn, Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getMaxSingleResult(Class entityClass, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getMinSingleResult(Class entityClass, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getSumSingleResult(Class entityClass, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getCountSingleResult(Class entityClass, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getCountDistinctSingleResult(Class entityClass, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Number getAvgSingleResult(Class entityClass, String column, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public T find(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public List queryList(Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public List queryList(Class clazz, SelectColumn selects, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Sheet querySheet(Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Sheet querySheet(Class clazz, SelectColumn selects, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Set queryColumnSet(String selectedColumn, Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Set queryColumnSet(String selectedColumn, Class clazz, FilterBean bean) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public List queryColumnList(String selectedColumn, Class clazz, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public List queryColumnList(String selectedColumn, Class clazz, FilterBean bean) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public Sheet queryColumnSheet(String selectedColumn, Class clazz, Flipper flipper, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + private static class DataJPAConnection extends DataConnection { private final EntityManager manager; @@ -133,12 +186,10 @@ final class DataJPASource implements DataSource { this.manager = m; } - @Override public void close() { manager.close(); } - @Override public boolean commit() { try { manager.getTransaction().commit(); @@ -148,7 +199,6 @@ final class DataJPASource implements DataSource { } } - @Override public void rollback() { manager.getTransaction().rollback(); } @@ -176,12 +226,10 @@ final class DataJPASource implements DataSource { if (flag) logger.setLevel(Level.FINEST); } - @Override public DataConnection createReadConnection() { return new DataJPAConnection(factory.createEntityManager()); } - @Override public DataConnection createWriteConnection() { return new DataJPAConnection(factory.createEntityManager()); } @@ -197,7 +245,6 @@ final class DataJPASource implements DataSource { * @param * @param values */ - @Override public void insert(T... values) { final EntityManager manager = factory.createEntityManager(); try { @@ -218,7 +265,6 @@ final class DataJPASource implements DataSource { * @param conn * @param values */ - @Override public void insert(final DataConnection conn, T... values) { final EntityManager manager = conn.getConnection(); for (T value : values) { @@ -233,7 +279,6 @@ final class DataJPASource implements DataSource { * @param * @param values */ - @Override public void delete(T... values) { final EntityManager manager = factory.createEntityManager(); try { @@ -252,7 +297,6 @@ final class DataJPASource implements DataSource { * @param conn * @param values */ - @Override public void delete(final DataConnection conn, T... values) { final EntityManager manager = conn.getConnection(); delete(manager, values); @@ -271,7 +315,6 @@ final class DataJPASource implements DataSource { * @param clazz * @param ids 主键值 */ - @Override public void delete(Class clazz, Serializable... ids) { final EntityManager manager = factory.createEntityManager(); try { @@ -291,7 +334,6 @@ final class DataJPASource implements DataSource { * @param clazz * @param ids */ - @Override public void delete(final DataConnection conn, Class clazz, Serializable... ids) { final EntityManager manager = conn.getConnection(); delete(manager, clazz, ids); @@ -312,7 +354,6 @@ final class DataJPASource implements DataSource { * @param column * @param keys */ - @Override public void deleteByColumn(Class clazz, String column, Serializable... keys) { final EntityManager manager = factory.createEntityManager(); try { @@ -333,7 +374,6 @@ final class DataJPASource implements DataSource { * @param column * @param keys */ - @Override public void deleteByColumn(final DataConnection conn, Class clazz, String column, Serializable... keys) { final EntityManager manager = conn.getConnection(); deleteByColumn(manager, clazz, column, keys); @@ -356,7 +396,6 @@ final class DataJPASource implements DataSource { * @param column2 * @param key2 */ - @Override public void deleteByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2) { final EntityManager manager = factory.createEntityManager(); try { @@ -379,7 +418,6 @@ final class DataJPASource implements DataSource { * @param column2 * @param key2 */ - @Override public void deleteByTwoColumn(final DataConnection conn, Class clazz, String column1, Serializable key1, String column2, Serializable key2) { deleteByTwoColumn((EntityManager) conn.getConnection(), clazz, column1, key1, column2, key2); } @@ -447,7 +485,6 @@ final class DataJPASource implements DataSource { * @param * @param values */ - @Override public void update(T... values) { final EntityManager manager = factory.createEntityManager(); try { @@ -466,7 +503,6 @@ final class DataJPASource implements DataSource { * @param conn * @param values */ - @Override public void update(final DataConnection conn, T... values) { final EntityManager manager = conn.getConnection(); update(manager, values); @@ -487,7 +523,6 @@ final class DataJPASource implements DataSource { * @param column * @param value */ - @Override public void updateColumn(Class clazz, Serializable id, String column, Serializable value) { final EntityManager manager = factory.createEntityManager(); try { @@ -509,7 +544,6 @@ final class DataJPASource implements DataSource { * @param column * @param value */ - @Override public void updateColumn(final DataConnection conn, Class clazz, Serializable id, String column, Serializable value) { final EntityManager manager = conn.getConnection(); updateColumn(manager, clazz, id, column, value); @@ -530,7 +564,6 @@ final class DataJPASource implements DataSource { * @param value * @param columns */ - @Override public void updateColumns(final T value, final String... columns) { final EntityManager manager = factory.createEntityManager(); try { @@ -550,7 +583,6 @@ final class DataJPASource implements DataSource { * @param value * @param columns */ - @Override public void updateColumns(final DataConnection conn, final T value, final String... columns) { final EntityManager manager = conn.getConnection(); updateColumns(manager, value, columns); @@ -571,56 +603,46 @@ final class DataJPASource implements DataSource { //-----------------------getSingleResult----------------------------- //-----------------------------MAX----------------------------- - @Override public Number getMaxSingleResult(final Class entityClass, final String column) { - return getMaxSingleResult(entityClass, column, null); + return getMaxSingleResult(entityClass, column, (FilterBean) null); } - @Override public Number getMaxSingleResult(final Class entityClass, final String column, FilterBean bean) { return getSingleResult(ReckonType.MAX, entityClass, column, bean); } //-----------------------------MIN----------------------------- - @Override public Number getMinSingleResult(final Class entityClass, final String column) { - return getMinSingleResult(entityClass, column, null); + return getMinSingleResult(entityClass, column, (FilterBean) null); } - @Override public Number getMinSingleResult(final Class entityClass, final String column, FilterBean bean) { return getSingleResult(ReckonType.MIN, entityClass, column, bean); } //-----------------------------SUM----------------------------- - @Override public Number getSumSingleResult(final Class entityClass, final String column) { - return getSumSingleResult(entityClass, column, null); + return getSumSingleResult(entityClass, column, (FilterBean) null); } - @Override public Number getSumSingleResult(final Class entityClass, final String column, FilterBean bean) { return getSingleResult(ReckonType.SUM, entityClass, column, bean); } //----------------------------COUNT---------------------------- - @Override public Number getCountSingleResult(final Class entityClass) { - return getCountSingleResult(entityClass, null); + return getCountSingleResult(entityClass, (FilterBean) null); } - @Override public Number getCountSingleResult(final Class entityClass, FilterBean bean) { return getSingleResult(ReckonType.COUNT, entityClass, null, bean); } //-----------------------------AVG----------------------------- - @Override public Number getAvgSingleResult(final Class entityClass, final String column) { - return getAvgSingleResult(entityClass, column, null); + return getAvgSingleResult(entityClass, column, (FilterBean) null); } - @Override public Number getAvgSingleResult(final Class entityClass, final String column, FilterBean bean) { return getSingleResult(ReckonType.AVG, entityClass, column, bean); } @@ -673,7 +695,6 @@ final class DataJPASource implements DataSource { * @param pk * @return */ - @Override public T find(Class clazz, Serializable pk) { final EntityManager manager = factory.createEntityManager(); try { @@ -691,7 +712,6 @@ final class DataJPASource implements DataSource { * @param ids * @return */ - @Override public T[] find(Class clazz, Serializable... ids) { final EntityManager manager = factory.createEntityManager(); try { @@ -715,7 +735,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public T findByColumn(Class clazz, String column, Serializable key) { final EntityManager manager = factory.createEntityManager(); try { @@ -740,7 +759,6 @@ final class DataJPASource implements DataSource { * @param key2 * @return */ - @Override public T findByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2) { final EntityManager manager = factory.createEntityManager(); try { @@ -789,7 +807,6 @@ final class DataJPASource implements DataSource { * @param keys * @return */ - @Override public T[] findByColumn(Class clazz, String column, Serializable... keys) { return findByColumn(clazz, null, column, keys); } @@ -804,7 +821,6 @@ final class DataJPASource implements DataSource { * @param keys * @return */ - @Override public T[] findByColumn(Class clazz, final SelectColumn selects, String column, Serializable... keys) { final EntityManager manager = factory.createEntityManager(); try { @@ -831,7 +847,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public List queryColumnList(String selectedColumn, Class clazz, String column, Serializable key) { final EntityManager manager = factory.createEntityManager(); try { @@ -855,7 +870,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public List queryList(Class clazz, String column, Serializable key) { return queryList(clazz, (SelectColumn) null, column, key); } @@ -870,7 +884,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public List queryList(Class clazz, String column, FilterExpress express, Serializable key) { return queryList(clazz, (SelectColumn) null, column, express, key); } @@ -885,7 +898,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public List queryList(Class clazz, final SelectColumn selects, String column, Serializable key) { return queryList(clazz, selects, column, FilterExpress.EQUAL, key); } @@ -901,7 +913,6 @@ final class DataJPASource implements DataSource { * @param key * @return */ - @Override public List queryList(Class clazz, final SelectColumn selects, String column, FilterExpress express, Serializable key) { final EntityManager manager = factory.createEntityManager(); try { @@ -923,7 +934,6 @@ final class DataJPASource implements DataSource { * @param bean * @return */ - @Override public List queryList(final Class clazz, final FilterBean bean) { return queryList(clazz, null, bean); } @@ -937,7 +947,6 @@ final class DataJPASource implements DataSource { * @param bean * @return */ - @Override public List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean) { final EntityManager manager = factory.createEntityManager(); try { @@ -962,7 +971,6 @@ final class DataJPASource implements DataSource { * @param bean * @return */ - @Override public Sheet querySheet(Class clazz, final Flipper flipper, final FilterBean bean) { return querySheet(clazz, null, flipper, bean); } @@ -977,7 +985,6 @@ final class DataJPASource implements DataSource { * @param bean * @return */ - @Override public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { final EntityManager manager = factory.createEntityManager(); try { diff --git a/src/com/wentch/redkale/source/DataSource.java b/src/com/wentch/redkale/source/DataSource.java index ce9194d12..538fabc0d 100644 --- a/src/com/wentch/redkale/source/DataSource.java +++ b/src/com/wentch/redkale/source/DataSource.java @@ -79,7 +79,7 @@ public interface DataSource { * * @param * @param clazz - * @param ids 主键值 + * @param ids 主键值 */ public void delete(Class clazz, Serializable... ids); @@ -94,50 +94,23 @@ public interface DataSource { public void delete(final DataConnection conn, Class clazz, Serializable... ids); /** - * 根据column字段的值删除对象, 必须是Entity Class + * 根据FilterNode的值删除对象, 必须是Entity Class * * @param * @param clazz - * @param column - * @param keys + * @param node */ - public void deleteByColumn(Class clazz, String column, Serializable... keys); + public void delete(Class clazz, FilterNode node); /** - * 根据column字段的值删除对象, 必须是Entity Class + * 根据FilterNode的值删除对象, 必须是Entity Class * * @param * @param conn * @param clazz - * @param column - * @param keys + * @param node */ - public void deleteByColumn(final DataConnection conn, Class clazz, String column, Serializable... keys); - - /** - * 根据两个column字段的值删除对象, 必须是Entity Class - * - * @param - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - */ - public void deleteByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2); - - /** - * 根据两个column字段的值删除对象, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - */ - public void deleteByTwoColumn(final DataConnection conn, Class clazz, String column1, Serializable key1, String column2, Serializable key2); + public void delete(final DataConnection conn, Class clazz, FilterNode node); //------------------------update--------------------------- /** @@ -148,13 +121,6 @@ public interface DataSource { */ public void update(T... values); - /** - * 更新对象, 必须是Entity对象 - * - * @param - * @param conn - * @param values - */ public void update(final DataConnection conn, T... values); /** @@ -168,17 +134,7 @@ public interface DataSource { */ public void updateColumn(Class clazz, Serializable id, String column, Serializable value); - /** - * 根据主键值更新对象的column对应的值, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param id - * @param column - * @param value - */ - public void updateColumn(final DataConnection conn, Class clazz, Serializable id, String column, Serializable value); + public void updateColumn(DataConnection conn, Class clazz, Serializable id, String column, Serializable value); /** * 根据主键值给对象的column对应的值+incvalue, 必须是Entity Class @@ -191,16 +147,6 @@ public interface DataSource { */ public void updateColumnIncrement(Class clazz, Serializable id, String column, long incvalue); - /** - * 根据主键值给对象的column对应的值+incvalue, 必须是Entity Class - * - * @param - * @param conn - * @param clazz - * @param id - * @param column - * @param incvalue - */ public void updateColumnIncrement(final DataConnection conn, Class clazz, Serializable id, String column, long incvalue); /** @@ -212,14 +158,6 @@ public interface DataSource { */ public void updateColumns(final T value, final String... columns); - /** - * 更新对象指定的一些字段, 必须是Entity对象 - * - * @param - * @param conn - * @param value - * @param columns - */ public void updateColumns(final DataConnection conn, final T value, final String... columns); //-----------------------getSingleResult----------------------------- @@ -228,30 +166,42 @@ public interface DataSource { public Number getMaxSingleResult(final Class entityClass, final String column, FilterBean bean); + public Number getMaxSingleResult(final Class entityClass, final String column, FilterNode node); + //-----------------------------MIN----------------------------- public Number getMinSingleResult(final Class entityClass, final String column); public Number getMinSingleResult(final Class entityClass, final String column, FilterBean bean); + public Number getMinSingleResult(final Class entityClass, final String column, FilterNode node); + //-----------------------------SUM----------------------------- public Number getSumSingleResult(final Class entityClass, final String column); public Number getSumSingleResult(final Class entityClass, final String column, FilterBean bean); + public Number getSumSingleResult(final Class entityClass, final String column, FilterNode node); + //----------------------------COUNT---------------------------- public Number getCountSingleResult(final Class entityClass); public Number getCountSingleResult(final Class entityClass, FilterBean bean); + public Number getCountSingleResult(final Class entityClass, FilterNode node); + public Number getCountDistinctSingleResult(final Class entityClass, String column); public Number getCountDistinctSingleResult(final Class entityClass, String column, FilterBean bean); + public Number getCountDistinctSingleResult(final Class entityClass, String column, FilterNode node); + //-----------------------------AVG----------------------------- public Number getAvgSingleResult(final Class entityClass, final String column); public Number getAvgSingleResult(final Class entityClass, final String column, FilterBean bean); + public Number getAvgSingleResult(final Class entityClass, final String column, FilterNode node); + //-----------------------find---------------------------- /** * 根据主键获取对象 @@ -263,93 +213,15 @@ public interface DataSource { */ public T find(Class clazz, Serializable pk); - /** - * 根据主键获取对象 - * - * @param - * @param clazz - * @param selects - * @param pk - * @return - */ public T find(Class clazz, final SelectColumn selects, Serializable pk); - /** - * 根据主键值集合获取对象集合 - * - * @param - * @param clazz - * @param ids - * @return - */ - public T[] find(Class clazz, Serializable... ids); - - /** - * 根据唯一索引获取单个对象 - * - * @param - * @param clazz - * @param column - * @param key - * @return - */ public T findByColumn(Class clazz, String column, Serializable key); - /** - * 根据两个字段的值获取单个对象 - * - * @param - * @param clazz - * @param column1 - * @param key1 - * @param column2 - * @param key2 - * @return - */ - public T findByTwoColumn(Class clazz, String column1, Serializable key1, String column2, Serializable key2); + public T find(final Class clazz, final FilterNode node); - /** - * 根据唯一索引获取对象 - * - * @param - * @param clazz - * @param column - * @param keys - * @return - */ - public T[] findByColumn(Class clazz, String column, Serializable... keys); - - /** - * 根据字段值拉去对象, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects 只拉起指定字段名或者排除指定字段名的值 - * @param column - * @param keys - * @return - */ - public T[] findByColumn(Class clazz, final SelectColumn selects, String column, Serializable... keys); - - /** - * 根据过滤对象FilterBean查询第一个符合条件的对象 - * - * @param - * @param clazz - * @param bean - * @return - */ public T find(final Class clazz, final FilterBean bean); //-----------------------list set---------------------------- - public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, Serializable key); - - public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, Serializable key); - - public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, Serializable key); - - public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, Serializable key); - /** * 根据指定字段值查询对象某个字段的集合 * @@ -363,54 +235,15 @@ public interface DataSource { */ public Set queryColumnSet(String selectedColumn, Class clazz, String column, Serializable key); - /** - * 根据指定字段值查询对象某个字段的集合 - * - * @param - * @param - * @param selectedColumn - * @param clazz - * @param column - * @param key - * @return - */ + public Set queryColumnSet(String selectedColumn, Class clazz, FilterNode node); + + public Set queryColumnSet(String selectedColumn, Class clazz, FilterBean bean); + public List queryColumnList(String selectedColumn, Class clazz, String column, Serializable key); - public int[] queryColumnIntSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); + public List queryColumnList(String selectedColumn, Class clazz, FilterNode node); - public long[] queryColumnLongSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); - - public int[] queryColumnIntList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); - - public long[] queryColumnLongList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); - - /** - * 根据指定字段值查询对象某个字段的集合 - * - * @param - * @param - * @param selectedColumn - * @param clazz - * @param column - * @param express - * @param key - * @return - */ - public Set queryColumnSet(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); - - /** - * 根据指定字段值查询对象某个字段的集合 - * - * @param - * @param - * @param selectedColumn - * @param clazz - * @param column - * @param express - * @param key - * @return - */ - public List queryColumnList(String selectedColumn, Class clazz, String column, FilterExpress express, Serializable key); + public List queryColumnList(String selectedColumn, Class clazz, FilterBean bean); /** * 根据指定字段值查询对象集合 @@ -423,63 +256,12 @@ public interface DataSource { */ public List queryList(Class clazz, String column, Serializable key); - /** - * 根据指定字段值查询对象集合 - * - * @param - * @param clazz - * @param column - * @param express - * @param key - * @return - */ - public List queryList(Class clazz, String column, FilterExpress express, Serializable key); + public List queryList(final Class clazz, final FilterNode node); - //-----------------------list---------------------------- - /** - * 根据指定字段值查询对象集合, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param column - * @param express - * @param key - * @return - */ - public List queryList(Class clazz, final SelectColumn selects, String column, FilterExpress express, Serializable key); - - /** - * 根据指定字段值查询对象集合, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param column - * @param key - * @return - */ - public List queryList(Class clazz, final SelectColumn selects, String column, Serializable key); - - /** - * 根据过滤对象FilterBean查询对象集合 - * - * @param - * @param clazz - * @param bean - * @return - */ public List queryList(final Class clazz, final FilterBean bean); - /** - * 根据过滤对象FilterBean查询对象集合, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param bean - * @return - */ + public List queryList(final Class clazz, final SelectColumn selects, final FilterNode node); + public List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean); //-----------------------sheet---------------------------- @@ -496,27 +278,14 @@ public interface DataSource { */ public Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterBean bean); - /** - * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据 - * - * @param - * @param clazz - * @param flipper - * @param bean - * @return - */ + public Sheet queryColumnSheet(String selectedColumn, Class clazz, final Flipper flipper, final FilterNode node); + public Sheet querySheet(Class clazz, final Flipper flipper, final FilterBean bean); - /** - * 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据, 对象只填充或排除SelectColumn指定的字段 - * - * @param - * @param clazz - * @param selects - * @param flipper - * @param bean - * @return - */ + public Sheet querySheet(Class clazz, final Flipper flipper, final FilterNode node); + public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean); + public Sheet querySheet(Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + } diff --git a/src/com/wentch/redkale/source/EntityCache.java b/src/com/wentch/redkale/source/EntityCache.java index 96b1d2c7c..c29c9ced7 100644 --- a/src/com/wentch/redkale/source/EntityCache.java +++ b/src/com/wentch/redkale/source/EntityCache.java @@ -262,7 +262,7 @@ final class EntityCache { this.reproduce.copy(rs, value); } - public void update(final T value, Attribute[] attrs) { + public void update(final T value, Collection> attrs) { if (value == null) return; T rs = this.map.get(this.primary.get(value)); if (rs == null) return; diff --git a/src/com/wentch/redkale/source/FilterNode.java b/src/com/wentch/redkale/source/FilterNode.java index 10071dfbf..d5ad4900c 100644 --- a/src/com/wentch/redkale/source/FilterNode.java +++ b/src/com/wentch/redkale/source/FilterNode.java @@ -143,6 +143,29 @@ public class FilterNode { return rs; } + protected static String createFilterSQLOrderBy(EntityInfo info, Flipper flipper) { + if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return ""; + final StringBuilder sb = new StringBuilder(); + sb.append(" ORDER BY "); + if (info.isNoAlias()) { + sb.append(flipper.getSort()); + } else { + boolean flag = false; + for (String item : flipper.getSort().split(",")) { + if (item.isEmpty()) continue; + String[] sub = item.split("\\s+"); + if (flag) sb.append(','); + if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) { + sb.append("a.").append(info.getSQLColumn(sub[0])).append(" ASC"); + } else { + sb.append("a.").append(info.getSQLColumn(sub[0])).append(" DESC"); + } + flag = true; + } + } + return sb.toString(); + } + private StringBuilder createFilterSQLExpress(final EntityInfo info, Serializable val0) { final StringBuilder val = formatValue(val0); if (val == null) return null; @@ -272,29 +295,6 @@ public class FilterNode { return null; } - protected static StringBuilder createFilterSQLOrderBy(EntityInfo info, Flipper flipper) { - if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return null; - final StringBuilder sb = new StringBuilder(); - sb.append(" ORDER BY "); - if (info.isNoAlias()) { - sb.append(flipper.getSort()); - } else { - boolean flag = false; - for (String item : flipper.getSort().split(",")) { - if (item.isEmpty()) continue; - String[] sub = item.split("\\s+"); - if (flag) sb.append(','); - if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) { - sb.append("a.").append(info.getSQLColumn(sub[0])).append(" ASC"); - } else { - sb.append("a.").append(info.getSQLColumn(sub[0])).append(" DESC"); - } - flag = true; - } - } - return sb; - } - protected static Comparator createFilterComparator(EntityInfo info, Flipper flipper) { if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return null; Comparator comparator = null; @@ -320,6 +320,15 @@ public class FilterNode { } protected StringBuilder formatValue(Object value) { + return formatValue(express, value); + } + + protected static String formatToString(Object value) { + StringBuilder sb = formatValue(null, value); + return sb == null ? null : sb.toString(); + } + + private static StringBuilder formatValue(FilterExpress express, Object value) { if (value == null) return null; if (value instanceof Number) return new StringBuilder().append(value); if (value instanceof CharSequence) { @@ -344,6 +353,10 @@ public class FilterNode { } else if (value.getClass().isArray()) { int len = Array.getLength(value); if (len == 0) return null; + if (len == 1) { + Object firstval = Array.get(value, 0); + if (firstval != null && firstval.getClass().isArray()) return formatValue(express, firstval); + } StringBuilder sb = new StringBuilder(); sb.append('('); for (int i = 0; i < len; i++) { diff --git a/src/com/wentch/redkale/source/JDBCPoolSource.java b/src/com/wentch/redkale/source/JDBCPoolSource.java new file mode 100644 index 000000000..69605236b --- /dev/null +++ b/src/com/wentch/redkale/source/JDBCPoolSource.java @@ -0,0 +1,234 @@ +/* + * 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 com.wentch.redkale.source; + +import static com.wentch.redkale.source.DataJDBCSource.*; +import java.io.*; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import java.sql.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import javax.sql.*; + +/** + * + * @author zhangjx + */ +public class JDBCPoolSource { + + private static final Map>>> maps = new HashMap<>(); + + private final AtomicLong usingCounter = new AtomicLong(); + + private final AtomicLong creatCounter = new AtomicLong(); + + private final AtomicLong cycleCounter = new AtomicLong(); + + private final AtomicLong saveCounter = new AtomicLong(); + + private final ConnectionPoolDataSource source; + + private final ArrayBlockingQueue queue; + + private final ConnectionEventListener listener; + + private final DataJDBCSource dataSource; + + private final String stype; // "" 或 "read" 或 "write" + + private final int max; + + private String url; + + private String user; + + private String password; + + public JDBCPoolSource(DataJDBCSource source, String stype, Properties prop) { + this.dataSource = source; + this.stype = stype; + this.source = createDataSource(prop); + this.url = prop.getProperty(JDBC_URL); + this.user = prop.getProperty(JDBC_USER); + this.password = prop.getProperty(JDBC_PWD); + this.max = Integer.decode(prop.getProperty(JDBC_CONNECTIONMAX, "" + Runtime.getRuntime().availableProcessors() * 16)); + this.queue = new ArrayBlockingQueue<>(this.max); + this.listener = new ConnectionEventListener() { + + @Override + public void connectionClosed(ConnectionEvent event) { + PooledConnection pc = (PooledConnection) event.getSource(); + if (queue.offer(pc)) saveCounter.incrementAndGet(); + } + + @Override + public void connectionErrorOccurred(ConnectionEvent event) { + usingCounter.decrementAndGet(); + if ("08S01".equals(event.getSQLException().getSQLState())) return; //MySQL特性, 长时间连接没使用会抛出com.mysql.jdbc.exceptions.jdbc4.CommunicationsException + dataSource.logger.log(Level.WARNING, "connectionErronOccurred [" + event.getSQLException().getSQLState() + "]", event.getSQLException()); + } + }; + try { + this.watch(); + } catch (Exception e) { + dataSource.logger.log(Level.WARNING, DataSource.class.getSimpleName() + " watch " + dataSource.conf + " error", e); + } + } + + private void watch() throws IOException { + if (dataSource.conf == null || dataSource.name == null) return; + final String file = dataSource.conf.getFile(); + final File f = new File(file); + if (!f.isFile() || !f.canRead()) return; + synchronized (maps) { + AbstractMap.SimpleEntry>> entry = maps.get(file); + if (entry != null) { + entry.getValue().add(new WeakReference<>(this)); + return; + } + final WatchService watcher = f.toPath().getFileSystem().newWatchService(); + final List> list = new CopyOnWriteArrayList<>(); + Thread watchThread = new Thread() { + + @Override + public void run() { + try { + while (!this.isInterrupted()) { + final WatchKey key = watcher.take(); + Thread.sleep(3000); //防止文件正在更新过程中去读取 + final Map m = loadProperties(new FileInputStream(file)); + key.pollEvents().stream().forEach((event) -> { + if (event.kind() != ENTRY_MODIFY) return; + if (!((Path) event.context()).toFile().getName().equals(f.getName())) return; + for (WeakReference ref : list) { + JDBCPoolSource pool = ref.get(); + if (pool == null) continue; + try { + Properties property = m.get(pool.dataSource.name); + if (property == null) property = m.get(pool.dataSource.name + "." + pool.stype); + if (property != null) pool.change(property); + } catch (Exception ex) { + dataSource.logger.log(Level.INFO, event.context() + " occur error", ex); + } + } + }); + key.reset(); + } + } catch (Exception e) { + dataSource.logger.log(Level.WARNING, "DataSource watch " + file + " occur error", e); + } + } + }; + f.getParentFile().toPath().register(watcher, ENTRY_MODIFY); + watchThread.setName("DataSource-Watch-" + maps.size() + "-Thread"); + watchThread.setDaemon(true); + watchThread.start(); + dataSource.logger.log(Level.FINER, watchThread.getName() + " start watching " + file); + //----------------------------------------------------------- + list.add(new WeakReference<>(this)); + maps.put(file, new AbstractMap.SimpleEntry<>(watcher, list)); + } + } + + public void change(Properties property) { + Method seturlm; + Class clazz = source.getClass(); + String newurl = property.getProperty(JDBC_URL); + String newuser = property.getProperty(JDBC_USER); + String newpassword = property.getProperty(JDBC_PWD); + if (this.url.equals(newurl) && this.user.equals(newuser) && this.password.equals(newpassword)) return; + try { + try { + seturlm = clazz.getMethod("setUrl", String.class); + } catch (Exception e) { + seturlm = clazz.getMethod("setURL", String.class); + } + seturlm.invoke(source, newurl); + clazz.getMethod("setUser", String.class).invoke(source, newuser); + clazz.getMethod("setPassword", String.class).invoke(source, newpassword); + this.url = newurl; + this.user = newuser; + this.password = newpassword; + dataSource.logger.log(Level.INFO, DataSource.class.getSimpleName() + "(" + dataSource.name + "." + stype + ") change (" + property + ")"); + } catch (Exception e) { + dataSource.logger.log(Level.SEVERE, DataSource.class.getSimpleName() + " dynamic change JDBC (url userName password) error", e); + } + } + + public Connection poll() { + return poll(0, null); + } + + private Connection poll(final int count, SQLException e) { + if (count >= 3) { + dataSource.logger.log(Level.WARNING, "create pooled connection error", e); + throw new RuntimeException(e); + } + PooledConnection result = queue.poll(); + if (result == null) { + if (usingCounter.get() >= max) { + try { + result = queue.poll(6, TimeUnit.SECONDS); + } catch (Exception t) { + dataSource.logger.log(Level.WARNING, "take pooled connection error", t); + } + } + if (result == null) { + try { + result = source.getPooledConnection(); + result.addConnectionEventListener(listener); + usingCounter.incrementAndGet(); + } catch (SQLException ex) { + return poll(count + 1, ex); + } + creatCounter.incrementAndGet(); + } + } else { + cycleCounter.incrementAndGet(); + } + Connection conn; + try { + conn = result.getConnection(); + if (!conn.isValid(1)) { + dataSource.logger.info("sql connection is not vaild"); + usingCounter.decrementAndGet(); + return poll(0, null); + } + } catch (SQLException ex) { + if (!"08S01".equals(ex.getSQLState())) {//MySQL特性, 长时间连接没使用会抛出com.mysql.jdbc.exceptions.jdbc4.CommunicationsException + dataSource.logger.log(Level.FINER, "result.getConnection from pooled connection abort [" + ex.getSQLState() + "]", ex); + } + return poll(0, null); + } + return conn; + } + + public long getCreatCount() { + return creatCounter.longValue(); + } + + public long getCycleCount() { + return cycleCounter.longValue(); + } + + public long getSaveCount() { + return saveCounter.longValue(); + } + + public void close() { + queue.stream().forEach(x -> { + try { + x.close(); + } catch (Exception e) { + } + }); + } +}