Files
redkale/src/org/redkale/source/DataJdbcSource.java
Redkale 7463a8f6b5
2017-04-19 22:58:03 +08:00

2258 lines
106 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.source;
import java.io.*;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.*;
import java.util.logging.*;
import javax.annotation.Resource;
import org.redkale.service.*;
import org.redkale.util.*;
/**
* DataSource的JDBC实现类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@LocalService
@AutoLoad(false)
@SuppressWarnings("unchecked")
@ResourceType({DataSource.class})
public class DataJdbcSource extends AbstractService implements DataSource, Service, DataCacheListener, Function<Class, EntityInfo>, AutoCloseable, Resourcable {
private static final Flipper FLIPPER_ONE = new Flipper(1);
final Logger logger = Logger.getLogger(DataJdbcSource.class.getSimpleName());
final AtomicBoolean debug = new AtomicBoolean(logger.isLoggable(Level.FINEST));
final String name;
final URL conf;
final boolean cacheForbidden;
private final PoolJdbcSource readPool;
private final PoolJdbcSource writePool;
@Resource(name = "$")
private DataCacheListener cacheListener;
private final BiFunction<DataSource, Class, List> fullloader = (s, t) -> querySheet(false, false, t, null, null, (FilterNode) null).list(true);
public DataJdbcSource(String unitName, Properties readprop, Properties writeprop) {
this.name = unitName;
this.conf = null;
this.readPool = new PoolJdbcSource(this, "read", readprop);
this.writePool = new PoolJdbcSource(this, "write", writeprop);
this.cacheForbidden = "NONE".equalsIgnoreCase(readprop.getProperty("shared-cache-mode"));
}
@Override
public final String resourceName() {
return name;
}
@Override
public void close() throws Exception {
readPool.close();
writePool.close();
}
private Connection createReadSQLConnection() {
return readPool.poll();
}
private <T> Connection createWriteSQLConnection() {
return writePool.poll();
}
private void closeSQLConnection(final Connection sqlconn) {
if (sqlconn == null) return;
try {
sqlconn.close();
} catch (Exception e) {
logger.log(Level.WARNING, "closeSQLConnection abort", e);
}
}
@Override
public EntityInfo apply(Class t) {
return loadEntityInfo(t);
}
private <T> EntityInfo<T> loadEntityInfo(Class<T> clazz) {
return EntityInfo.load(clazz, this.cacheForbidden, this.readPool.props, this, fullloader);
}
/**
* 将entity的对象全部加载到Cache中去如果clazz没有被@javax.persistence.Cacheable注解则不做任何事
*
* @param <T> Entity类泛型
* @param clazz Entity类
*/
public <T> void refreshCache(Class<T> clazz) {
EntityInfo<T> info = loadEntityInfo(clazz);
EntityCache<T> cache = info.getCache();
if (cache == null) return;
cache.fullLoad();
}
//----------------------insertCache-----------------------------
/**
* 新增对象, 必须是Entity对象
*
* @param <T> Entity类泛型
* @param values Entity对象
*/
@Override
public <T> void insert(@RpcCall(DataCallArrayAttribute.class) T... values) {
if (values.length == 0) return;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.insert must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) {
insert(null, info, values);
return;
}
Connection conn = createWriteSQLConnection();
try {
insert(conn, info, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void insertAsync(final AsyncHandler<Void, T[]> handler, @RpcAttachment @RpcCall(DataCallArrayAttribute.class) final T... values) {
insert(values);
if (handler != null) handler.completed(null, values);
}
private <T> void insert(final Connection conn, final EntityInfo<T> info, T... values) {
if (values.length == 0) return;
try {
if (!info.isVirtualEntity()) {
final String sql = info.getInsertSQL(values[0]);
final Class primaryType = info.getPrimary().type();
final Attribute primary = info.getPrimary();
Attribute<T, Serializable>[] attrs = info.insertAttributes;
conn.setReadOnly(false);
PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, values);
try {
prestmt.executeBatch();
} catch (SQLException se) {
if (info.tableStrategy == null || !info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) throw se;
synchronized (info.tables) {
final String oldTable = info.table;
final String newTable = info.getTable(values[0]);
if (!info.tables.contains(newTable)) {
try {
Statement st = conn.createStatement();
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
st.close();
info.tables.add(newTable);
} catch (SQLException sqle) { //多进程并发时可能会出现重复建表
if (newTable.indexOf('.') > 0 && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) {
Statement st;
try {
st = conn.createStatement();
st.execute("CREATE DATABASE " + newTable.substring(0, newTable.indexOf('.')));
st.close();
} catch (SQLException sqle1) {
logger.log(Level.SEVERE, "create database(" + newTable.substring(0, newTable.indexOf('.')) + ") error", sqle1);
}
try {
st = conn.createStatement();
st.execute(info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable));
st.close();
info.tables.add(newTable);
} catch (SQLException sqle2) {
logger.log(Level.SEVERE, "create table2(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle2);
}
} else {
logger.log(Level.SEVERE, "create table(" + info.tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", oldTable) + ") error", sqle);
}
}
}
}
prestmt.close();
prestmt = createInsertPreparedStatement(conn, sql, info, values);
prestmt.executeBatch();
}
if (info.autoGenerated) { //由数据库自动生成主键值
ResultSet set = prestmt.getGeneratedKeys();
int i = -1;
while (set.next()) {
if (primaryType == int.class) {
primary.set(values[++i], set.getInt(1));
} else if (primaryType == long.class) {
primary.set(values[++i], set.getLong(1));
} else {
primary.set(values[++i], set.getObject(1));
}
}
set.close();
}
prestmt.close();
//------------------------------------------------------------
if (debug.get() && info.isLoggable(Level.FINEST)) { //打印调试信息
char[] sqlchars = sql.toCharArray();
for (final T value : values) {
//-----------------------------
StringBuilder sb = new StringBuilder(128);
int i = 0;
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = attrs[i++].get(value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
sb.append(FilterNode.formatToString(obj));
}
} else {
sb.append(ch);
}
}
logger.finest(info.getType().getSimpleName() + " insert sql=" + sb.toString().replaceAll("(\r|\n)", "\\n"));
}
} //打印结束
}
final EntityCache<T> cache = info.getCache();
if (cache != null) { //更新缓存
for (final T value : values) {
cache.insert(value);
}
if (cacheListener != null) cacheListener.insertCache(info.getType(), values);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
final EntityInfo<T> info, T... values) throws SQLException {
Attribute<T, Serializable>[] attrs = info.insertAttributes;
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
for (final T value : values) {
int i = 0;
if (info.autouuid) info.createPrimaryValue(value);
for (Attribute<T, Serializable> attr : attrs) {
Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++i, blob);
} else {
prestmt.setObject(++i, val);
}
}
prestmt.addBatch();
}
return prestmt;
}
@Override
public <T> int insertCache(Class<T> clazz, T... values) {
if (values.length == 0) return 0;
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache == null) return -1;
int c = 0;
for (T value : values) {
c += cache.insert(value);
}
return c;
}
//-------------------------deleteCache--------------------------
/**
* 删除对象, 必须是Entity对象
*
* @param <T> Entity类泛型
* @param values Entity对象
*
* @return 删除的数据条数
*/
@Override
public <T> int delete(T... values) {
if (values.length == 0) return -1;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.delete must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) { //虚拟表只更新缓存Cache
return delete(null, info, values);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void deleteAsync(final AsyncHandler<Integer, T[]> handler, @RpcAttachment final T... values) {
int rs = delete(values);
if (handler != null) handler.completed(rs, values);
}
private <T> int delete(final Connection conn, final EntityInfo<T> info, T... values) {
if (values.length == 0) return -1;
final Attribute primary = info.getPrimary();
Serializable[] ids = new Serializable[values.length];
int i = 0;
for (final T value : values) {
ids[i++] = (Serializable) primary.get(value);
}
return delete(conn, info, ids);
}
@Override
public <T> int delete(Class<T> clazz, Serializable... ids) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) { //虚拟表只更新缓存Cache
return delete(null, info, ids);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, ids);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void deleteAsync(final AsyncHandler<Integer, Serializable[]> handler, final Class<T> clazz, @RpcAttachment final Serializable... ids) {
int rs = delete(clazz, ids);
if (handler != null) handler.completed(rs, ids);
}
private <T> int delete(final Connection conn, final EntityInfo<T> info, Serializable... keys) {
if (keys.length == 0) return -1;
int c = -1;
int c2 = 0;
try {
if (!info.isVirtualEntity()) {
conn.setReadOnly(false);
final Statement stmt = conn.createStatement();
for (Serializable key : keys) {
String sql = "DELETE FROM " + info.getTable(key) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(key);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
stmt.addBatch(sql);
}
int[] pc = stmt.executeBatch();
c = 0;
for (int p : pc) {
if (p >= 0) c += p;
}
stmt.close();
}
//------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
for (Serializable key : keys) {
c2 += cache.delete(key);
}
if (cacheListener != null) cacheListener.deleteCache(info.getType(), keys);
return c >= 0 ? c : c2;
} catch (SQLException e) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + e.getSQLState() + ';')) return c >= 0 ? c : c2;
throw new RuntimeException(e);
}
}
@Override
public <T> int delete(Class<T> clazz, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return delete(null, info, null, node);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, null, node);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void deleteAsync(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
int rs = delete(clazz, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> int delete(Class<T> clazz, final Flipper flipper, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return delete(null, info, flipper, node);
}
Connection conn = createWriteSQLConnection();
try {
return delete(conn, info, flipper, node);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void deleteAsync(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment FilterNode node) {
int rs = delete(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
}
private <T> int delete(final Connection conn, final EntityInfo<T> info, final Flipper flipper, final FilterNode node) {
int c = -1;
try {
if (!info.isVirtualEntity()) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "DELETE " + (this.readPool.isMysql() ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1))
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper)
+ ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
conn.setReadOnly(false);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
//------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
Serializable[] ids = cache.delete(flipper, node);
if (cacheListener != null) cacheListener.deleteCache(info.getType(), ids);
return c >= 0 ? c : (ids == null ? 0 : ids.length);
} catch (SQLException e) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + e.getSQLState() + ';')) return c;
throw new RuntimeException(e);
}
}
@Override
public <T> int deleteCache(Class<T> clazz, Serializable... ids) {
if (ids.length == 0) return 0;
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache == null) return -1;
int c = 0;
for (Serializable id : ids) {
c += cache.delete(id);
}
return c;
}
//------------------------updateAsync---------------------------
/**
* 更新对象, 必须是Entity对象
*
* @param <T> Entity类泛型
* @param values Entity对象
*
* @return 更新的数据条数
*/
@Override
public <T> int update(T... values) {
if (values.length == 0) return 0;
if (values.length > 1) { //检查对象是否都是同一个Entity类
Class clazz = null;
for (T val : values) {
if (clazz == null) {
clazz = val.getClass();
continue;
}
if (clazz != val.getClass()) {
throw new RuntimeException("DataSource.update must the same Class Entity, but diff is " + clazz + " and " + val.getClass());
}
}
}
final EntityInfo<T> info = loadEntityInfo((Class<T>) values[0].getClass());
if (info.isVirtualEntity()) {
return update(null, info, values);
}
Connection conn = createWriteSQLConnection();
try {
return update(conn, info, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateAsync(final AsyncHandler<Integer, T[]> handler, @RpcAttachment final T... values) {
int rs = update(values);
if (handler != null) handler.completed(rs, values);
}
private <T> int update(final Connection conn, final EntityInfo<T> info, T... values) {
try {
Class clazz = info.getType();
int c = -1;
if (!info.isVirtualEntity()) {
final String updateSQL = info.getUpdateSQL(values[0]);
final Attribute<T, Serializable> primary = info.getPrimary();
conn.setReadOnly(false);
final PreparedStatement prestmt = conn.prepareStatement(updateSQL);
Attribute<T, Serializable>[] attrs = info.updateAttributes;
final boolean debugfinest = debug.get() && info.isLoggable(Level.FINEST);
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
for (final T value : values) {
int k = 0;
for (Attribute<T, Serializable> attr : attrs) {
Serializable val = attr.get(value);
if (val instanceof byte[]) {
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) val);
prestmt.setObject(++k, blob);
} else {
prestmt.setObject(++k, val);
}
}
prestmt.setObject(++k, primary.get(value));
prestmt.addBatch();//------------------------------------------------------------
if (debugfinest) { //打印调试信息
//-----------------------------
int i = 0;
StringBuilder sb = new StringBuilder(128);
for (char ch : sqlchars) {
if (ch == '?') {
Object obj = i == attrs.length ? primary.get(value) : attrs[i++].get(value);
if (obj != null && obj.getClass().isArray()) {
sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'");
} else {
sb.append(FilterNode.formatToString(obj));
}
} else {
sb.append(ch);
}
}
logger.finest(info.getType().getSimpleName() + " update sql=" + sb.toString().replaceAll("(\r|\n)", "\\n"));
} //打印结束
}
int[] pc = prestmt.executeBatch();
c = 0;
for (int p : pc) {
if (p >= 0) c += p;
}
prestmt.close();
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
int c2 = 0;
for (final T value : values) {
c2 += cache.update(value);
}
if (cacheListener != null) cacheListener.updateCache(clazz, values);
return c >= 0 ? c : c2;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 根据主键值更新对象的column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param id 主键值
* @param column 过滤字段名
* @param value 过滤字段值
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(Class<T> clazz, Serializable id, String column, Serializable value) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, id, column, value);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, id, column, value);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, Serializable> handler, final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
int rs = updateColumn(clazz, id, column, value);
if (handler != null) handler.completed(rs, id);
}
private <T> int updateColumn(Connection conn, final EntityInfo<T> info, Serializable id, String column, final Serializable value) {
try {
int c = -1;
if (!info.isVirtualEntity()) {
if (value instanceof byte[]) {
String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = ? WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
final PreparedStatement stmt = conn.prepareStatement(sql);
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) value);
stmt.setBlob(1, blob);
c = stmt.executeUpdate(sql);
stmt.close();
} else {
String sql = "UPDATE " + info.getTable(id) + " SET " + info.getSQLColumn(null, column) + " = "
+ info.formatToString(value) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T rs = cache.update(id, info.getAttribute(column), value);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
return c >= 0 ? c : (rs == null ? 0 : 1);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) closeSQLConnection(conn);
}
}
/**
* 根据主键值更新对象的column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param value 过滤字段值
* @param node 过滤node 不能为null
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(Class<T> clazz, String column, Serializable value, FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, column, value, node);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, column, value, node);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, final String column, final Serializable value, @RpcAttachment final FilterNode node) {
int rs = updateColumn(clazz, column, value, node);
if (handler != null) handler.completed(rs, node);
}
private <T> int updateColumn(Connection conn, final EntityInfo<T> info, String column, final Serializable value, FilterNode node) {
try {
int c = -1;
if (!info.isVirtualEntity()) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
if (value instanceof byte[]) {
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1))
+ " SET " + info.getSQLColumn("a", column) + " = ?"
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
Blob blob = conn.createBlob();
blob.setBytes(1, (byte[]) value);
final PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setBlob(1, blob);
c = stmt.executeUpdate(sql);
stmt.close();
} else {
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1))
+ " SET " + info.getSQLColumn("a", column) + " = " + info.formatToString(value)
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T[] rs = cache.update(info.getAttribute(column), value, node);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
return c >= 0 ? c : (rs == null ? 0 : rs.length);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) closeSQLConnection(conn);
}
}
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param id 主键值
* @param values 字段值
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, id, values);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, id, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable id, final ColumnValue... values) {
int rs = updateColumn(clazz, id, values);
if (handler != null) handler.completed(rs, id);
}
private <T> int updateColumn(final Connection conn, final EntityInfo<T> info, final Serializable id, final ColumnValue... values) {
if (values == null || values.length < 1) return -1;
try {
StringBuilder setsql = new StringBuilder();
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity();
List<byte[]> blobs = null;
for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue;
attrs.add(attr);
cols.add(col);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
String c = info.getSQLColumn(null, col.getColumn());
if (col.getValue() instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) col.getValue());
setsql.append(c).append(" = ?");
} else {
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
}
}
}
int c = -1;
if (!virtual) {
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + ": " + sql);
conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T rs = cache.updateColumn(id, attrs, cols);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
return c >= 0 ? c : (rs == null ? 0 : 1);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param node 过滤条件
* @param values 字段值
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, node, null, values);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, node, null, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node, final ColumnValue... values) {
int rs = updateColumn(clazz, node, values);
if (handler != null) handler.completed(rs, node);
}
/**
* 根据主键值更新对象的多个column对应的值 必须是Entity Class
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param node 过滤条件
* @param flipper 翻页对象
* @param values 字段值
*
* @return 更新的数据条数
*/
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
final EntityInfo<T> info = loadEntityInfo(clazz);
if (info.isVirtualEntity()) {
return updateColumn(null, info, node, flipper, values);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumn(conn, info, node, flipper, values);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node, final Flipper flipper, final ColumnValue... values) {
int rs = updateColumn(clazz, node, flipper, values);
if (handler != null) handler.completed(rs, node);
}
private <T> int updateColumn(final Connection conn, final EntityInfo<T> info, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
if (values == null || values.length < 1) return -1;
try {
StringBuilder setsql = new StringBuilder();
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
final List<ColumnValue> cols = new ArrayList<>();
final boolean virtual = info.isVirtualEntity();
List<byte[]> blobs = null;
for (ColumnValue col : values) {
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
if (attr == null) continue;
attrs.add(attr);
cols.add(col);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
String c = info.getSQLColumn("a", col.getColumn());
if (col.getValue() instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) col.getValue());
setsql.append(c).append(" = ?");
} else {
setsql.append(c).append(" = ").append(info.formatSQLValue(c, col));
}
}
}
int c = -1;
if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
//注LIMIT 仅支持MySQL 且在多表关联式会异常, 该BUG尚未解决
sql += info.createSQLOrderby(flipper) + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit()));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T[] rs = cache.updateColumn(node, flipper, attrs, cols);
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
return c >= 0 ? c : (rs == null ? 0 : rs.length);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public <T> int updateColumn(final T bean, final String... columns) {
return updateColumn(bean, SelectColumn.createIncludes(columns));
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, T> handler, @RpcAttachment final T bean, final String... columns) {
int rs = updateColumn(bean, columns);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> int updateColumn(final T bean, final SelectColumn selects) {
final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass());
if (info.isVirtualEntity()) {
return updateColumns(null, info, bean, selects);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumns(conn, info, bean, selects);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, T> handler, @RpcAttachment final T bean, final SelectColumn selects) {
int rs = updateColumn(bean, selects);
if (handler != null) handler.completed(rs, bean);
}
private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final SelectColumn selects) {
if (bean == null || selects == null) return -1;
try {
final Class<T> clazz = (Class<T>) bean.getClass();
StringBuilder setsql = new StringBuilder();
final Serializable id = info.getPrimary().get(bean);
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
List<byte[]> blobs = null;
final boolean virtual = info.isVirtualEntity();
for (Attribute<T, Serializable> attr : info.updateAttributes) {
if (!selects.test(attr.field())) continue;
attrs.add(attr);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn(null, attr.field()));
Serializable val = attr.get(bean);
if (val instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) val);
setsql.append(" = ?");
} else {
setsql.append(" = ").append(info.formatToString(val));
}
}
}
int c = -1;
if (!virtual) {
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(bean.getClass().getSimpleName() + ": " + sql);
conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T rs = cache.update(bean, attrs);
if (cacheListener != null) cacheListener.updateCache(clazz, rs);
return c >= 0 ? c : (rs == null ? 0 : 1);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public <T> int updateColumn(final T bean, final FilterNode node, final String... columns) {
return updateColumn(bean, node, SelectColumn.createIncludes(columns));
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, FilterNode> handler, final T bean, @RpcAttachment final FilterNode node, final String... columns) {
int rs = updateColumn(bean, node, columns);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> int updateColumn(final T bean, final FilterNode node, final SelectColumn selects) {
final EntityInfo<T> info = loadEntityInfo((Class<T>) bean.getClass());
if (info.isVirtualEntity()) {
return updateColumns(null, info, bean, node, selects);
}
Connection conn = createWriteSQLConnection();
try {
return updateColumns(conn, info, bean, node, selects);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void updateColumnAsync(final AsyncHandler<Integer, FilterNode> handler, final T bean, @RpcAttachment final FilterNode node, final SelectColumn selects) {
int rs = updateColumn(bean, node, selects);
if (handler != null) handler.completed(rs, node);
}
private <T> int updateColumns(final Connection conn, final EntityInfo<T> info, final T bean, final FilterNode node, final SelectColumn selects) {
if (bean == null || node == null || selects == null) return -1;
try {
final Class<T> clazz = (Class<T>) bean.getClass();
StringBuilder setsql = new StringBuilder();
final Serializable id = info.getPrimary().get(bean);
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
List<byte[]> blobs = null;
final boolean virtual = info.isVirtualEntity();
for (Attribute<T, Serializable> attr : info.updateAttributes) {
if (!selects.test(attr.field())) continue;
attrs.add(attr);
if (!virtual) {
if (setsql.length() > 0) setsql.append(", ");
setsql.append(info.getSQLColumn("a", attr.field()));
Serializable val = attr.get(bean);
if (val instanceof byte[]) {
if (blobs == null) blobs = new ArrayList<>();
blobs.add((byte[]) val);
setsql.append(" = ?");
} else {
setsql.append(" = ").append(info.formatToString(val));
}
}
}
int c = -1;
if (!virtual) {
Map<Class, String> joinTabalis = node.getJoinTabalis();
CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info);
CharSequence where = node.createSQLExpress(info, joinTabalis);
StringBuilder join1 = null;
StringBuilder join2 = null;
if (join != null) {
String joinstr = join.toString();
join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0);
join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0);
}
String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql
+ ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2))
: (" WHERE " + where + (join2 == null ? "" : (" AND " + join2))));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
conn.setReadOnly(false);
if (blobs != null) {
final PreparedStatement stmt = conn.prepareStatement(sql);
int idx = 0;
for (byte[] bs : blobs) {
Blob blob = conn.createBlob();
blob.setBytes(1, bs);
stmt.setBlob(++idx, blob);
}
c = stmt.executeUpdate();
stmt.close();
} else {
final Statement stmt = conn.createStatement();
c = stmt.executeUpdate(sql);
stmt.close();
}
}
//---------------------------------------------------
final EntityCache<T> cache = info.getCache();
if (cache == null) return c;
T[] rs = cache.update(bean, attrs, node);
if (cacheListener != null) cacheListener.updateCache(clazz, rs);
return c >= 0 ? c : (rs == null ? 0 : rs.length);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public <T> int updateCache(Class<T> clazz, T... values) {
if (values.length == 0) return 0;
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache == null) return -1;
int c = 0;
for (T value : values) {
c += cache.update(value);
}
return c;
}
public <T> int reloadCache(Class<T> clazz, Serializable... ids) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache == null) return -1;
String column = info.getPrimary().field();
int c = 0;
for (Serializable id : ids) {
Sheet<T> sheet = querySheet(false, true, clazz, null, FLIPPER_ONE, FilterNode.create(column, id));
T value = sheet.isEmpty() ? null : sheet.list().get(0);
if (value != null) c += cache.update(value);
}
return c;
}
//-----------------------getNumberResultAsync-----------------------------
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) {
return getNumberResult(entityClass, func, null, column, (FilterNode) null);
}
@Override
public void getNumberResultAsync(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, @RpcAttachment final String column) {
Number rs = getNumberResult(entityClass, func, column);
if (handler != null) handler.completed(rs, column);
}
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, null, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public <B extends FilterBean> void getNumberResultAsync(final AsyncHandler<Number, B> handler, final Class entityClass, final FilterFunc func, final String column, @RpcAttachment final B bean) {
Number rs = getNumberResult(entityClass, func, column, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) {
return getNumberResult(entityClass, func, null, column, node);
}
@Override
public void getNumberResultAsync(final AsyncHandler<Number, FilterNode> handler, final Class entityClass, final FilterFunc func, final String column, @RpcAttachment final FilterNode node) {
Number rs = getNumberResult(entityClass, func, column, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column) {
return getNumberResult(entityClass, func, defVal, column, (FilterNode) null);
}
@Override
public void getNumberResultAsync(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column) {
Number rs = getNumberResult(entityClass, func, defVal, column);
if (handler != null) handler.completed(rs, column);
}
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public void getNumberResultAsync(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column, final FilterBean bean) {
getNumberResultAsync(handler, entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterFuncColumn... columns) {
return getNumberMap(entityClass, (FilterNode) null, columns);
}
@Override
public <N extends Number> void getNumberMapAsync(final AsyncHandler<Map<String, N>, FilterFuncColumn[]> handler, final Class entityClass, @RpcAttachment final FilterFuncColumn... columns) {
Map<String, N> rs = getNumberMap(entityClass, columns);
if (handler != null) handler.completed(rs, columns);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) {
return getNumberMap(entityClass, FilterNodeBean.createFilterNode(bean), columns);
}
@Override
public <N extends Number, B extends FilterBean> void getNumberMapAsync(final AsyncHandler<Map<String, N>, B> handler, final Class entityClass, @RpcAttachment final B bean, final FilterFuncColumn... columns) {
Map<String, N> rs = getNumberMap(entityClass, bean, columns);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) {
if (columns == null || columns.length == 0) return new HashMap<>();
final EntityInfo info = loadEntityInfo(entityClass);
final Connection conn = createReadSQLConnection();
final Map map = new HashMap<>();
try {
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
for (FilterFuncColumn ffc : columns) {
for (String col : ffc.cols()) {
map.put(ffc.col(col), cache.getNumberResult(ffc.func, ffc.defvalue, col, node));
}
}
return map;
}
}
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final Set<String> haset = new HashSet<>();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
StringBuilder sb = new StringBuilder();
for (FilterFuncColumn ffc : columns) {
for (String col : ffc.cols()) {
if (sb.length() > 0) sb.append(", ");
sb.append(ffc.func.getColumn((col == null || col.isEmpty() ? "*" : ("a." + col))));
}
}
final String sql = "SELECT " + sb + " FROM " + info.getTable(node) + " a"
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement prestmt = conn.prepareStatement(sql);
ResultSet set = prestmt.executeQuery();
if (set.next()) {
int index = 0;
for (FilterFuncColumn ffc : columns) {
for (String col : ffc.cols()) {
Object o = set.getObject(++index);
Number rs = ffc.defvalue;
if (o != null) rs = (Number) o;
map.put(ffc.col(col), rs);
}
}
}
set.close();
prestmt.close();
return map;
} catch (SQLException e) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + e.getSQLState() + ';')) {
for (FilterFuncColumn ffc : columns) {
for (String col : ffc.cols()) {
map.put(ffc.col(col), ffc.defvalue);
}
}
return map;
}
throw new RuntimeException(e);
} finally {
if (conn != null) closeSQLConnection(conn);
}
}
@Override
public <N extends Number> void getNumberMapAsync(final AsyncHandler<Map<String, N>, FilterNode> handler, final Class entityClass, @RpcAttachment final FilterNode node, final FilterFuncColumn... columns) {
Map<String, N> rs = getNumberMap(entityClass, node, columns);
if (handler != null) handler.completed(rs, node);
}
@Override
public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final Connection conn = createReadSQLConnection();
try {
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return cache.getNumberResult(func, defVal, column, node);
}
}
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final Set<String> haset = new HashSet<>();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + func.getColumn((column == null || column.isEmpty() ? "*" : ("a." + column))) + " FROM " + info.getTable(node) + " a"
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement prestmt = conn.prepareStatement(sql);
Number rs = defVal;
ResultSet set = prestmt.executeQuery();
if (set.next()) {
Object o = set.getObject(1);
if (o != null) rs = (Number) o;
}
set.close();
prestmt.close();
return rs;
} catch (SQLException e) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + e.getSQLState() + ';')) return defVal;
throw new RuntimeException(e);
} finally {
if (conn != null) closeSQLConnection(conn);
}
}
@Override
public void getNumberResultAsync(final AsyncHandler<Number, String> handler, final Class entityClass, final FilterFunc func, final Number defVal, @RpcAttachment final String column, final FilterNode node) {
Number rs = getNumberResult(entityClass, func, defVal, column, node);
if (handler != null) handler.completed(rs, column);
}
//-----------------------queryColumnMapAsync-----------------------------
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn) {
return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null);
}
@Override
public <T, K extends Serializable, N extends Number> void queryColumnMapAsync(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn) {
Map<K, N> rs = queryColumnMap(entityClass, keyColumn, func, funcColumn);
if (handler != null) handler.completed(rs, keyColumn);
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterBean bean) {
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, K extends Serializable, N extends Number> void queryColumnMapAsync(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) {
queryColumnMapAsync(handler, entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) {
final EntityInfo info = loadEntityInfo(entityClass);
final Connection conn = createReadSQLConnection();
try {
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (node == null || node.isCacheUseable(this)) {
return cache.queryColumnMap(keyColumn, func, funcColumn, node);
}
}
final String sqlkey = info.getSQLColumn(null, keyColumn);
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final Set<String> haset = new HashSet<>();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a." + sqlkey + ", " + func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : ("a." + funcColumn)))
+ " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + sqlkey;
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement prestmt = conn.prepareStatement(sql);
Map<K, N> rs = new LinkedHashMap<>();
ResultSet set = prestmt.executeQuery();
ResultSetMetaData rsd = set.getMetaData();
boolean smallint = rsd.getColumnType(1) == Types.SMALLINT;
while (set.next()) {
rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2));
}
set.close();
prestmt.close();
return rs;
} catch (SQLException e) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + e.getSQLState() + ';')) return new LinkedHashMap<>();
throw new RuntimeException(e);
} finally {
if (conn != null) closeSQLConnection(conn);
}
}
@Override
public <T, K extends Serializable, N extends Number> void queryColumnMapAsync(final AsyncHandler<Map<K, N>, String> handler, final Class<T> entityClass, @RpcAttachment final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node) {
Map<K, N> rs = queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
if (handler != null) handler.completed(rs, keyColumn);
}
//-----------------------findAsync----------------------------
/**
* 根据主键获取对象
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param pk 主键值
*
* @return Entity对象
*/
@Override
public <T> T find(Class<T> clazz, Serializable pk) {
return find(clazz, (SelectColumn) null, pk);
}
@Override
public <T> void findAsync(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable pk) {
T rs = find(clazz, pk);
if (handler != null) handler.completed(rs, pk);
}
@Override
public <T> T find(Class<T> clazz, final SelectColumn selects, Serializable pk) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null) {
T rs = cache.find(selects, pk);
if (cache.isFullLoaded() || rs != null) return rs;
}
final Connection conn = createReadSQLConnection();
try {
final SelectColumn sels = selects;
final String sql = "SELECT * FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery();
T rs = set.next() ? info.getValue(sels, set) : null;
set.close();
ps.close();
return rs;
} catch (SQLException sex) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + sex.getSQLState() + ';')) return null;
throw new RuntimeException(sex);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void findAsync(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, SelectColumn selects, @RpcAttachment final Serializable pk) {
T rs = find(clazz, selects, pk);
if (handler != null) handler.completed(rs, pk);
}
@Override
public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
return find(clazz, null, FilterNode.create(column, key));
}
@Override
public <T> void findAsync(final AsyncHandler<T, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
T rs = find(clazz, column, key);
if (handler != null) handler.completed(rs, key);
}
@Override
public <T> T find(final Class<T> clazz, final FilterBean bean) {
return find(clazz, null, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void findAsync(final AsyncHandler<T, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
T rs = find(clazz, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> T find(final Class<T> clazz, final FilterNode node) {
return find(clazz, null, node);
}
@Override
public <T> void findAsync(final AsyncHandler<T, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
T rs = find(clazz, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void findAsync(final AsyncHandler<T, B> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final B bean) {
T rs = find(clazz, selects, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.find(selects, node);
final Connection conn = createReadSQLConnection();
try {
final SelectColumn sels = selects;
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a.* FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery();
T rs = set.next() ? info.getValue(sels, set) : null;
set.close();
ps.close();
return rs;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return null;
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void findAsync(final AsyncHandler<T, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final FilterNode node) {
T rs = find(clazz, selects, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk) {
return findColumn(clazz, column, null, pk);
}
@Override
public <T> void findColumnAsync(final AsyncHandler<Serializable, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable pk) {
Serializable rs = findColumn(clazz, column, pk);
if (handler != null) handler.completed(rs, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean) {
return findColumn(clazz, column, null, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void findColumnAsync(final AsyncHandler<Serializable, B> handler, final Class<T> clazz, final String column, @RpcAttachment final B bean) {
Serializable rs = findColumn(clazz, column, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node) {
return findColumn(clazz, column, null, node);
}
@Override
public <T> void findColumnAsync(final AsyncHandler<Serializable, FilterNode> handler, final Class<T> clazz, final String column, @RpcAttachment final FilterNode node) {
Serializable rs = findColumn(clazz, column, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null) {
Serializable val = cache.findColumn(column, defValue, pk);
if (cache.isFullLoaded() || val != null) return val;
}
final Connection conn = createReadSQLConnection();
try {
final Attribute<T, Serializable> attr = info.getAttribute(column);
final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery();
Serializable val = defValue;
if (set.next()) {
if (attr.type() == byte[].class) {
Blob blob = set.getBlob(1);
if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else {
val = (Serializable) set.getObject(1);
}
}
set.close();
ps.close();
return val == null ? defValue : val;
} catch (SQLException sex) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + sex.getSQLState() + ';')) return defValue;
throw new RuntimeException(sex);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void findColumnAsync(final AsyncHandler<Serializable, Serializable> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final Serializable pk) {
Serializable rs = findColumn(clazz, column, defValue, pk);
if (handler != null) handler.completed(rs, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean) {
return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void findColumnAsync(final AsyncHandler<Serializable, B> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final B bean) {
Serializable rs = findColumn(clazz, column, defValue, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.findColumn(column, defValue, node);
final Connection conn = createReadSQLConnection();
try {
final Attribute<T, Serializable> attr = info.getAttribute(column);
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " find sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(1);
final ResultSet set = ps.executeQuery();
Serializable val = defValue;
if (set.next()) {
if (attr.type() == byte[].class) {
Blob blob = set.getBlob(1);
if (blob != null) val = blob.getBytes(1, (int) blob.length());
} else {
val = (Serializable) set.getObject(1);
}
}
set.close();
ps.close();
return val == null ? defValue : val;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return defValue;
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
@Override
public <T> void findColumnAsync(final AsyncHandler<Serializable, FilterNode> handler, final Class<T> clazz, final String column, final Serializable defValue, @RpcAttachment final FilterNode node) {
Serializable rs = findColumn(clazz, column, defValue, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> boolean exists(Class<T> clazz, Serializable pk) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null) {
boolean rs = cache.exists(pk);
if (rs || cache.isFullLoaded()) return rs;
}
final Connection conn = createReadSQLConnection();
final boolean log = debug.get() && info.isLoggable(Level.FINEST);
String logstr = null;
try {
final String sql = "SELECT COUNT(*) FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(pk);
if (log) logstr = clazz.getSimpleName() + " exists sql=" + sql;
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
set.close();
ps.close();
if (log) logstr = clazz.getSimpleName() + " exists (" + rs + ") sql=" + sql;
return rs;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return false;
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (logstr != null) logger.finest(logstr);
closeSQLConnection(conn);
}
}
@Override
public <T> void existsAsync(final AsyncHandler<Boolean, Serializable> handler, final Class<T> clazz, @RpcAttachment final Serializable pk) {
boolean rs = exists(clazz, pk);
if (handler != null) handler.completed(rs, pk);
}
@Override
public <T> boolean exists(final Class<T> clazz, final FilterBean bean) {
return exists(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void existsAsync(final AsyncHandler<Boolean, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
boolean rs = exists(clazz, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> boolean exists(final Class<T> clazz, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (cache != null && cache.isFullLoaded() && (node == null || node.isCacheUseable(this))) return cache.exists(node);
final Connection conn = createReadSQLConnection();
final boolean log = debug.get() && info.isLoggable(Level.FINEST);
String logstr = null;
try {
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (log) logstr = clazz.getSimpleName() + " exists sql=" + sql;
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
boolean rs = set.next() ? (set.getInt(1) > 0) : false;
set.close();
ps.close();
if (log) logstr = clazz.getSimpleName() + " exists (" + rs + ") sql=" + sql;
return rs;
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return false;
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (logstr != null) logger.finest(logstr);
closeSQLConnection(conn);
}
}
@Override
public <T> void existsAsync(final AsyncHandler<Boolean, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
boolean rs = exists(clazz, node);
if (handler != null) handler.completed(rs, node);
}
//-----------------------list set----------------------------
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, String column, Serializable key) {
return queryColumnSet(selectedColumn, clazz, FilterNode.create(column, key));
}
@Override
public <T, V extends Serializable> void queryColumnSetAsync(final AsyncHandler<HashSet<V>, String> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final String column, final Serializable key) {
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, column, key);
if (handler != null) handler.completed(rs, column);
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, bean));
}
@Override
public <T, V extends Serializable, B extends FilterBean> void queryColumnSetAsync(final AsyncHandler<HashSet<V>, B> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final B bean) {
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
return new LinkedHashSet<>(queryColumnList(selectedColumn, clazz, node));
}
@Override
public <T, V extends Serializable> void queryColumnSetAsync(final AsyncHandler<HashSet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final FilterNode node) {
HashSet<V> rs = queryColumnSet(selectedColumn, clazz, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final String column, final Serializable key) {
return queryColumnList(selectedColumn, clazz, FilterNode.create(column, key));
}
@Override
public <T, V extends Serializable> void queryColumnListAsync(final AsyncHandler<List<V>, Serializable> handler, final String selectedColumn, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
List<V> rs = queryColumnList(selectedColumn, clazz, column, key);
if (handler != null) handler.completed(rs, key);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable, B extends FilterBean> void queryColumnListAsync(final AsyncHandler<List<V>, B> handler, String selectedColumn, Class<T> clazz, @RpcAttachment B bean) {
List<V> rs = queryColumnList(selectedColumn, clazz, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final FilterNode node) {
return (List<V>) queryColumnSheet(false, selectedColumn, clazz, null, node).list(true);
}
@Override
public <T, V extends Serializable> void queryColumnListAsync(final AsyncHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, @RpcAttachment final FilterNode node) {
List<V> rs = queryColumnList(selectedColumn, clazz, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable, B extends FilterBean> void queryColumnListAsync(final AsyncHandler<List<V>, B> handler, String selectedColumn, Class<T> clazz, Flipper flipper, @RpcAttachment B bean) {
List<V> rs = queryColumnList(selectedColumn, clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return (List<V>) queryColumnSheet(false, selectedColumn, clazz, flipper, node).list(true);
}
@Override
public <T, V extends Serializable> void queryColumnListAsync(final AsyncHandler<List<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, Flipper flipper, @RpcAttachment final FilterNode node) {
List<V> rs = queryColumnList(selectedColumn, clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
}
/**
* 根据指定参数查询对象某个字段的集合
* <p>
* @param <T> Entity类的泛型
* @param <V> 字段值的类型
* @param selectedColumn 字段名
* @param clazz Entity类
* @param flipper 翻页对象
* @param bean 过滤Bean
*
* @return 字段集合
*/
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable, B extends FilterBean> void queryColumnSheetAsync(final AsyncHandler<Sheet<V>, B> handler, String selectedColumn, Class<T> clazz, Flipper flipper, @RpcAttachment B bean) {
Sheet<V> rs = queryColumnSheet(selectedColumn, clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return queryColumnSheet(true, selectedColumn, clazz, flipper, node);
}
@Override
public <T, V extends Serializable> void queryColumnSheetAsync(final AsyncHandler<Sheet<V>, FilterNode> handler, final String selectedColumn, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<V> rs = queryColumnSheet(selectedColumn, clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
}
private <T, V extends Serializable> Sheet<V> queryColumnSheet(final boolean needtotal, final String selectedColumn, final Class<T> clazz, final Flipper flipper, final FilterNode node) {
Sheet<T> sheet = querySheet(true, needtotal, clazz, SelectColumn.createIncludes(selectedColumn), flipper, node);
final Sheet<V> rs = new Sheet<>();
if (sheet.isEmpty()) return rs;
rs.setTotal(sheet.getTotal());
final EntityInfo<T> info = loadEntityInfo(clazz);
final Attribute<T, V> selected = (Attribute<T, V>) info.getAttribute(selectedColumn);
final List<V> list = new ArrayList<>();
for (T t : sheet.getRows()) {
list.add(selected.get(t));
}
rs.setRows(list);
return rs;
}
/**
* 根据指定字段值查询对象集合
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param column 过滤字段名
* @param key 过滤字段值
*
* @return Entity对象的集合
*/
@Override
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) {
return queryList(clazz, FilterNode.create(column, key));
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, Serializable> handler, final Class<T> clazz, final String column, @RpcAttachment final Serializable key) {
List<T> rs = queryList(clazz, column, key);
if (handler != null) handler.completed(rs, key);
}
/**
* 根据过滤对象FilterBean查询对象集合
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param bean 过滤Bean
*
* @return Entity对象集合
*/
@Override
public <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) {
return queryList(clazz, (SelectColumn) null, bean);
}
@Override
public <T, B extends FilterBean> void queryListAsync(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, @RpcAttachment final B bean) {
List<T> rs = queryList(clazz, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
return queryList(clazz, (SelectColumn) null, node);
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, @RpcAttachment final FilterNode node) {
List<T> rs = queryList(clazz, node);
if (handler != null) handler.completed(rs, node);
}
/**
* 根据过滤对象FilterBean查询对象集合 对象只填充或排除SelectField指定的字段
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param selects 收集的字段
* @param bean 过滤Bean
*
* @return Entity对象的集合
*/
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
return queryList(clazz, selects, (Flipper) null, bean);
}
@Override
public <T, B extends FilterBean> void queryListAsync(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final B bean) {
List<T> rs = queryList(clazz, selects, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return queryList(clazz, selects, (Flipper) null, node);
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, @RpcAttachment final FilterNode node) {
List<T> rs = queryList(clazz, selects, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
return queryList(clazz, flipper, FilterNode.create(column, key));
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, Serializable> handler, final Class<T> clazz, final Flipper flipper, final String column, @RpcAttachment final Serializable key) {
List<T> rs = queryList(clazz, flipper, column, key);
if (handler != null) handler.completed(rs, key);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, null, flipper, bean);
}
@Override
public <T, B extends FilterBean> void queryListAsync(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final B bean) {
List<T> rs = queryList(clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return queryList(clazz, null, flipper, node);
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
List<T> rs = queryList(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return querySheet(true, false, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)).list(true);
}
@Override
public <T, B extends FilterBean> void queryListAsync(final AsyncHandler<List<T>, B> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final B bean) {
List<T> rs = queryList(clazz, selects, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return querySheet(true, false, clazz, selects, flipper, node).list(true);
}
@Override
public <T> void queryListAsync(final AsyncHandler<List<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final FilterNode node) {
List<T> rs = queryList(clazz, selects, flipper, node);
if (handler != null) handler.completed(rs, node);
}
//-----------------------sheet----------------------------
/**
* 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param flipper 翻页对象
* @param bean 过滤Bean
*
* @return Entity对象的集合
*/
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, null, flipper, bean);
}
@Override
public <T, B extends FilterBean> void querySheetAsync(final AsyncHandler<Sheet<T>, B> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final B bean) {
Sheet<T> rs = querySheet(clazz, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return querySheet(clazz, null, flipper, node);
}
@Override
public <T> void querySheetAsync(final AsyncHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<T> rs = querySheet(clazz, flipper, node);
if (handler != null) handler.completed(rs, node);
}
/**
* 根据过滤对象FilterBean和翻页对象Flipper查询一页的数据 对象只填充或排除SelectField指定的字段
*
* @param <T> Entity类的泛型
* @param clazz Entity类
* @param selects 收集的字段集合
* @param flipper 翻页对象
* @param bean 过滤Bean
*
* @return Entity对象的集合
*/
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return querySheet(true, true, clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, B extends FilterBean> void querySheetAsync(final AsyncHandler<Sheet<T>, B> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final B bean) {
Sheet<T> rs = querySheet(clazz, selects, flipper, bean);
if (handler != null) handler.completed(rs, bean);
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return querySheet(true, true, clazz, selects, flipper, node);
}
@Override
public <T> void querySheetAsync(final AsyncHandler<Sheet<T>, FilterNode> handler, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, @RpcAttachment final FilterNode node) {
Sheet<T> rs = querySheet(clazz, selects, flipper, node);
if (handler != null) handler.completed(rs, node);
}
private <T> Sheet<T> querySheet(final boolean readcache, final boolean needtotal, final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
final EntityInfo<T> info = loadEntityInfo(clazz);
final EntityCache<T> cache = info.getCache();
if (readcache && cache != null && cache.isFullLoaded()) {
if (node == null || node.isCacheUseable(this)) {
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache)));
return cache.querySheet(needtotal, selects, flipper, node);
}
}
final Connection conn = createReadSQLConnection();
try {
final SelectColumn sels = selects;
final List<T> list = new ArrayList();
final Map<Class, String> joinTabalis = node == null ? null : node.getJoinTabalis();
final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, joinTabalis);
final String sql = "SELECT a.* FROM " + info.getTable(node) + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
if (debug.get() && info.isLoggable(Level.FINEST)) {
logger.finest(clazz.getSimpleName() + " query sql=" + sql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getOffset() + "," + flipper.getLimit())));
}
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit());
final ResultSet set = ps.executeQuery();
if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset());
final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit();
int i = 0;
while (set.next()) {
i++;
list.add(info.getValue(sels, set));
if (limit <= i) break;
}
long total = list.size();
if (needtotal && flipper != null) {
set.last();
total = set.getRow();
}
set.close();
ps.close();
return new Sheet<>(total, list);
} catch (SQLException se) {
if (info.tableStrategy != null && info.tablenotexistSqlstates.contains(';' + se.getSQLState() + ';')) return new Sheet<>();
throw new RuntimeException(se);
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
private static StringBuilder multisplit(char ch1, char ch2, String split, StringBuilder sb, String str, int from) {
if (str == null) return sb;
int pos1 = str.indexOf(ch1, from);
if (pos1 < 0) return sb;
int pos2 = str.indexOf(ch2, from);
if (pos2 < 0) return sb;
if (sb.length() > 0) sb.append(split);
sb.append(str.substring(pos1 + 1, pos2));
return multisplit(ch1, ch2, split, sb, str, pos2 + 1);
}
@Override
public final int[] directExecute(String... sqls) {
Connection conn = createWriteSQLConnection();
try {
return directExecute(conn, sqls);
} finally {
closeSQLConnection(conn);
}
}
private int[] directExecute(final Connection conn, String... sqls) {
if (sqls.length == 0) return new int[0];
try {
conn.setReadOnly(false);
final Statement stmt = conn.createStatement();
final int[] rs = new int[sqls.length];
int i = -1;
for (String sql : sqls) {
rs[++i] = stmt.execute(sql) ? 1 : 0;
}
stmt.close();
return rs;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public final void directQuery(String sql, Consumer<ResultSet> consumer) {
final Connection conn = createReadSQLConnection();
try {
if (debug.get()) logger.finest("direct query sql=" + sql);
conn.setReadOnly(true);
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
final ResultSet set = ps.executeQuery();
consumer.accept(set);
set.close();
ps.close();
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
closeSQLConnection(conn);
}
}
}