Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.util.SQLExecutor Maven / Gradle / Ivy
/*
* Copyright (C) 2015 HaiYang Li
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.landawn.abacus.util;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.DataSource;
import com.landawn.abacus.DataSourceManager;
import com.landawn.abacus.DataSourceSelector;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.IsolationLevel;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory.L;
import com.landawn.abacus.condition.Equal;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.core.sql.dataSource.SQLDataSource;
import com.landawn.abacus.dataChannel.StatementDataChannel;
import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.exception.NonUniqueResultException;
import com.landawn.abacus.exception.UncheckedSQLException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.Options.Query;
import com.landawn.abacus.util.SQLBuilder.NE;
import com.landawn.abacus.util.SQLBuilder.NE2;
import com.landawn.abacus.util.SQLBuilder.NE3;
import com.landawn.abacus.util.SQLBuilder.SP;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.stream.Stream;
/**
* SQLExecutor is a simple sql/jdbc utility class. SQL is supported with different format:
*
*
*
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (?, ?, ?, ?, ?)
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (#{firstName}, #{lastName}, #{gui}, #{lastUpdateTime}, #{createTime})
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (:firstName, :lastName, :gui, :lastUpdateTime, :createTime)
*
* All these kinds of SQLs can be generated by SQLBuilder
conveniently. Parameters with format of Array/List parameters are supported for parameterized sql with '?'.
* Parameters with format of Array/List/Map/Entity are supported for parameterized SQL with named parameters.
*
*
* Here is sample of CRUD(create/read/update/delete):
*
========================================================================
*
*
static final DataSource dataSource = JdbcUtil.createDataSource(...);
static final SQLExecutor sqlExecutor = new SQLExecutor(dataSource);
...
Account account = createAccount();
// create
String sql_insert = NE.insert(GUI, FIRST_NAME, LAST_NAME, LAST_UPDATE_TIME, CREATE_TIME).into(Account.class).sql();
N.println(sql_insert);
sqlExecutor.insert(sql_insert, account);
// read
String sql_selectByGUI = NE.selectFrom(Account.class, N.asSet(DEVICES)).where(L.eq(GUI, L.QME)).sql();
N.println(sql_selectByGUI);
Account dbAccount = sqlExecutor.queryForEntity(Account.class, sql_selectByGUI, account);
assertEquals(account.getFirstName(), dbAccount.getFirstName());
// update
String sql_updateByLastName = NE.update(Account.class).set(FIRST_NAME).where(L.eq(LAST_NAME, L.QME)).sql();
N.println(sql_updateByLastName);
dbAccount.setFirstName("newFirstName");
sqlExecutor.update(sql_updateByLastName, dbAccount);
// delete
String sql_deleteByFirstName = NE.deleteFrom(Account.class).where(L.eq(FIRST_NAME, L.QME)).sql();
N.println(sql_deleteByFirstName);
sqlExecutor.update(sql_deleteByFirstName, dbAccount);
dbAccount = sqlExecutor.queryForEntity(Account.class, sql_selectByGUI, account);
assertNull(dbAccount);
*
*
* ========================================================================
*
*
* If {@code conn} argument is null or not specified, {@code SQLExecutor} is responsible to get the connection from the
* internal {@code DataSource}, start and commit/roll back transaction for batch operations if needed, and close the
* connection finally. otherwise it's user's responsibility to do such jobs if {@code conn} is specified and not null.
*
*
* The general programming way with SQLExeucte is to execute sql scripts(generated by SQLBuilder) with array/list/map/entity by calling (batch)insert/update/delete/query/... methods.
* if Transaction is required. it can be started:
*
*
* final SQLTransaction tran = sqlExecutor.beginTransaction(IsolationLevel.READ_COMMITTED);
boolean noException = false;
try {
// sqlExecutor.insert(tran.getConnection(), ...);
// sqlExecutor.update(tran.getConnection(), ...);
// sqlExecutor.query(tran.getConnection(), ...);
noException = true;
} finally {
// The connection will be automatically closed after the transaction is committed or rolled back.
if (noException) {
tran.commit();
} else {
tran.rollback();
}
}
*
*
*
* SQLExecutor is tread-safe.
*
* @since 0.8
*
* @author Haiyang Li
*
* @see
JdbcUtil
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/PreparedStatement.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
*/
public final class SQLExecutor implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(SQLExecutor.class);
static final String ID = "id";
static final StatementSetter DEFAULT_STATEMENT_SETTER = new DefaultStatementSetter();
static final ResultSetExtractor> DEFAULT_RESULT_SET_EXTRACTOR = new DefaultResultSetExtractor();
static final ResultSetExtractor
ROW_ITERATOR_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@Override
public RowIterator extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
return RowIterator.of(rs, jdbcSettings.getOffset(), jdbcSettings.getCount());
}
};
static final ResultSetExtractor EXISTS_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@Override
public Boolean extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
return offset <= 0 && rs.next();
}
};
static final ResultSetExtractor> SINGLE_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor>() {
@Override
public NullabLe> extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && rs.next()) {
return NullabLe.of(rs.getObject(1));
}
return NullabLe.empty();
}
};
@SuppressWarnings("rawtypes")
private static final ResultSetExtractor ENTITY_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@Override
public Object extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && rs.next()) {
final List columnLabelList = getColumnLabelList(namedSQL, rs);
final int columnCount = columnLabelList.size();
final Object entity = N.newInstance(cls);
if (Map.class.isAssignableFrom(cls)) {
final Map m = (Map) entity;
for (int i = 0; i < columnCount; i++) {
m.put(columnLabelList.get(i), rs.getObject(i + 1));
}
} else {
// Method method = null;
//
// for (int i = 0; i < columnCount; i++) {
// method = N.getPropSetMethod(cls, columnLabelList.get(i));
//
// if (method != null) {
// N.setPropValue(entity, method, rs.getObject(i + 1));
// }
// }
for (int i = 0; i < columnCount; i++) {
RefUtil.setPropValue(entity, columnLabelList.get(i), rs.getObject(i + 1), true);
}
if (N.isDirtyMarker(cls)) {
((DirtyMarker) entity).markDirty(false);
}
}
return entity;
}
return null;
}
};
@SuppressWarnings("rawtypes")
private static final ResultSetExtractor ENTITY_LIST_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor>() {
@Override
public List extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
final List resultList = new ArrayList<>();
long offset = jdbcSettings.getOffset();
long count = jdbcSettings.getCount();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && count > 0) {
final List columnLabelList = getColumnLabelList(namedSQL, rs);
final int columnCount = columnLabelList.size();
final boolean isMap = Map.class.isAssignableFrom(cls);
final boolean isDirtyMarker = N.isDirtyMarker(cls);
while ((count-- > 0) && rs.next()) {
final Object entity = N.newInstance(cls);
if (isMap) {
final Map m = (Map) entity;
for (int i = 0; i < columnCount; i++) {
m.put(columnLabelList.get(i), rs.getObject(i + 1));
}
} else {
// Method method = null;
//
// for (int i = 0; i < columnCount; i++) {
// method = N.getPropSetMethod(cls, columnLabelList.get(i));
//
// if (method != null) {
// N.setPropValue(entity, method, rs.getObject(i + 1));
// }
// }
for (int i = 0; i < columnCount; i++) {
RefUtil.setPropValue(entity, columnLabelList.get(i), rs.getObject(i + 1), true);
}
if (isDirtyMarker) {
((DirtyMarker) entity).markDirty(false);
}
}
resultList.add(entity);
}
}
return resultList;
}
};
private static final int SQL_CACHE_SIZE = 3000;
private static final Map> _sqlColumnLabelPool = new ConcurrentHashMap<>();
private final Map> _tableColumnNamePool = new ConcurrentHashMap<>();
private final DataSource _ds;
private final DataSourceManager _dsm;
private final DataSourceSelector _dss;
private final JdbcSettings _jdbcSettings;
private final SQLMapper _sqlMapper;
private final NamingPolicy _namingPolicy;
private final AsyncExecutor _asyncExecutor;
private final boolean _isReadOnly;
private final String _dbProudctName;
private final String _dbProudctVersion;
private final DBVersion _dbVersion;
private final IsolationLevel _defaultIsolationLevel;
private final AsyncSQLExecutor _asyncSQLExecutor;
private final Map, Mapper>> mapperPool = new ConcurrentHashMap<>();
/**
*
* @param dataSource
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource) {
this(dataSource, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings) {
this(dataSource, jdbcSettings, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper) {
this(dataSource, jdbcSettings, sqlMapper, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @param namingPolicy
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy) {
this(dataSource, jdbcSettings, sqlMapper, namingPolicy, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @param asyncExecutor
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy,
final AsyncExecutor asyncExecutor) {
this(null, JdbcUtil.wrap(dataSource), jdbcSettings, sqlMapper, namingPolicy, asyncExecutor, false);
}
/**
*
* @param dataSourceManager
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager) {
this(dataSourceManager, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings) {
this(dataSourceManager, jdbcSettings, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper) {
this(dataSourceManager, jdbcSettings, sqlMapper, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @param namingPolicy
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy) {
this(dataSourceManager, jdbcSettings, sqlMapper, namingPolicy, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @param asyncExecutor
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy,
final AsyncExecutor asyncExecutor) {
this(dataSourceManager, null, jdbcSettings, sqlMapper, namingPolicy, asyncExecutor, false);
}
protected SQLExecutor(final DataSourceManager dataSourceManager, final DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper,
final NamingPolicy namingPolicy, final AsyncExecutor asyncExecutor, final boolean isReadOnly) {
if (dataSourceManager == null) {
this._ds = dataSource;
this._dsm = null;
this._dss = null;
} else {
this._ds = dataSourceManager.getPrimaryDataSource();
this._dsm = dataSourceManager;
this._dss = dataSourceManager.getDataSourceSelector();
}
this._jdbcSettings = (jdbcSettings == null) ? JdbcSettings.create() : jdbcSettings.copy();
if (_jdbcSettings.getBatchSize() == 0) {
_jdbcSettings.setBatchSize(JdbcSettings.DEFAULT_BATCH_SIZE);
}
_jdbcSettings.freeze();
this._sqlMapper = sqlMapper;
this._namingPolicy = namingPolicy == null ? NamingPolicy.LOWER_CASE_WITH_UNDERSCORE : namingPolicy;
this._asyncExecutor = asyncExecutor == null ? new AsyncExecutor(64, 300, TimeUnit.SECONDS) : asyncExecutor;
this._isReadOnly = isReadOnly;
Connection conn = getConnection();
try {
_dbProudctName = conn.getMetaData().getDatabaseProductName();
_dbProudctVersion = conn.getMetaData().getDatabaseProductVersion();
_dbVersion = JdbcUtil.getDBVersion(conn);
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
closeQuietly(conn);
}
_defaultIsolationLevel = this._ds instanceof SQLDataSource ? ((SQLDataSource) this._ds).getDefaultIsolationLevel() : IsolationLevel.DEFAULT;
this._asyncSQLExecutor = new AsyncSQLExecutor(this, _asyncExecutor);
}
// public static SQLExecutor create(final String dataSourceFile) {
// return new SQLExecutor(JdbcUtil.createDataSourceManager(dataSourceFile));
// }
//
// public static SQLExecutor create(final InputStream dataSourceInputStream) {
// return new SQLExecutor(JdbcUtil.createDataSourceManager(dataSourceInputStream));
// }
//
// public static SQLExecutor create(final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(url, user, password));
// }
//
// public static SQLExecutor create(final String driver, final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(driver, url, user, password));
// }
//
// public static SQLExecutor create(final Class extends Driver> driverClass, final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(driverClass, url, user, password));
// }
//
// /**
// *
// * @param props refer to Connection.xsd for the supported properties.
// * @return
// */
// public static SQLExecutor create(final Map props) {
// return new SQLExecutor(JdbcUtil.createDataSource(props));
// }
//
// public static SQLExecutor create(final javax.sql.DataSource sqlDataSource) {
// return new SQLExecutor(JdbcUtil.wrap(sqlDataSource));
// }
//
// public SQLMapper sqlMapper() {
// return _sqlMapper;
// }
public static SQLExecutor w(final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(url, user, password));
}
public static SQLExecutor w(final String driver, final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(driver, url, user, password));
}
public static SQLExecutor w(final Class extends Driver> driverClass, final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(driverClass, url, user, password));
}
public Mapper mapper(final Class targetClass) {
Mapper mapper = (Mapper) mapperPool.get(targetClass);
if (mapper == null) {
N.checkArgument(N.isEntity(targetClass), RefUtil.getCanonicalClassName(targetClass) + " is not an entity class with getter/setter methods");
mapper = new Mapper(targetClass, this, this._namingPolicy);
mapperPool.put(targetClass, mapper);
}
return mapper;
}
// /**
// * Create a Mapper
which has the same life cycle as the specified Connection
.
// * To start transaction for a Mapper
:
// *
// *
// * final Transaction tran = sqlExecutor.beginTransaction(isolationLevel);
// * final ExMapper mapper = sqlExecutor.mapper(targetClass, tran.connection());
// * boolean isOk = false;
// * try {
// * // Do something with sqlExecutor and mapper
// * isOk = true;
// * } finally {
// * if (isOk) {
// * tran.commit();
// * } else {
// * tran.rollback();
// * }
// * }
// *
// *
// *
// * @param targetClass
// * @param conn
// * @return
// */
// public ExMapper mapper(final Class targetClass, final Connection conn) {
// if (conn == null) {
// return mapper(targetClass);
// }
//
// return new ExMapper(conn, targetClass, this, this._namingPolicy);
// }
public AsyncSQLExecutor async() {
return _asyncSQLExecutor;
}
public DataSource dataSource() {
return _ds;
}
public JdbcSettings jdbcSettings() {
return _jdbcSettings;
}
public String dbProudctName() {
return _dbProudctName;
}
public String dbProudctVersion() {
return _dbProudctVersion;
}
public DBVersion dbVersion() {
return _dbVersion;
}
@SafeVarargs
public final T insert(final String sql, final Object... parameters) {
return insert(null, sql, null, null, parameters);
}
@SafeVarargs
public final T insert(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return insert(null, sql, statementSetter, null, parameters);
}
@SafeVarargs
public final T insert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return insert(null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final T insert(final Connection conn, final String sql, final Object... parameters) {
return insert(conn, sql, null, null, parameters);
}
@SafeVarargs
public final T insert(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return insert(conn, sql, statementSetter, null, parameters);
}
/**
* @see #batchInsert(Connection, String, StatementSetter, JdbcSettings, String, Object[])
*/
@SuppressWarnings({ "unchecked", "deprecation" })
@SafeVarargs
public final T insert(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
String idPropName = checkGeneratedIdPropName(jdbcSettings);
DataSource ds = null;
Connection localConn = null;
Object result = null;
PreparedStatement stmt = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.RETURN_GENERATED_KEYS, false, parameters);
result = executeInsert(namedSQL, stmt);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
closeQuietly(stmt, localConn, conn);
}
if ((result != null) && isEntityOrMapParameter(namedSQL, parameters)) {
Object parameter_0 = (parameters[0] instanceof TypedParameters) ? ((TypedParameters) parameters[0]).parameters[0] : parameters[0];
if (parameter_0 instanceof Map) {
// // don't update input map ?
// Map m = (Map) parameter_0;
// Object idPropValue = m.get(generatedIdPropName);
//
// if ((idPropValue == null)
// || (idPropValue instanceof Number
// && (((Number) idPropValue).longValue() == 0))) {
// m.put(generatedIdPropName, result);
// }
} else {
final Object entity = parameter_0;
try {
Method idGetMethod = RefUtil.getPropGetMethod(entity.getClass(), idPropName);
Method idSetMethod = RefUtil.getPropSetMethod(entity.getClass(), idPropName);
if ((idGetMethod != null) && (idSetMethod != null)) {
Object idPropValue = RefUtil.getPropValue(entity, idGetMethod);
if ((idPropValue == null) || (idPropValue instanceof Number && (((Number) idPropValue).longValue() == 0))) {
RefUtil.setPropValue(entity, idSetMethod, result);
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("Failed to set the returned id property to entity. no get/set method for id property (" + idPropName + ") found. ");
}
}
} catch (Exception e) {
logger.error("Failed to set the returned id property to entity", e);
}
if (entity instanceof DirtyMarker) {
((DirtyMarker) entity).dirtyPropNames().clear();
}
}
}
return (T) result;
}
protected Object executeInsert(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
stmt.executeUpdate();
Object id = null;
ResultSet rs = null;
try {
rs = stmt.getGeneratedKeys();
if (rs.next()) {
id = rs.getObject(1);
}
} catch (SQLException e) {
logger.error("Failed to retrieve the auto-generated Ids", e);
} finally {
closeQuietly(rs);
}
return id;
}
List batchInsert(final String sql, final Object[] batchParameters) {
return batchInsert(null, sql, null, null, batchParameters);
}
List batchInsert(final String sql, final StatementSetter statementSetter, final Object[] batchParameters) {
return batchInsert(null, sql, statementSetter, null, batchParameters);
}
List batchInsert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object[] batchParameters) {
return batchInsert(null, sql, statementSetter, jdbcSettings, batchParameters);
}
List batchInsert(final Connection conn, final String sql, final Object[] batchParameters) {
return batchInsert(conn, sql, null, null, batchParameters);
}
List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final Object[] batchParameters) {
return batchInsert(conn, sql, statementSetter, null, batchParameters);
}
/**
* Returns the auto-generated key by preparing statement
* {@code prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)} {@code null} is returned if no auto-generated key.
*
* Call {@code update} instead if there is no auto-generated key.
*
* @param conn
* @param sql
* @param statementSetter
* @param props
* @param batchParameters
* @return
*/
List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object[] batchParameters) {
return batchInsert(conn, sql, statementSetter, jdbcSettings, Arrays.asList(batchParameters));
}
public List batchInsert(final String sql, final List> batchParameters) {
return batchInsert(null, sql, null, null, batchParameters);
}
public List batchInsert(final String sql, final StatementSetter statementSetter, final List> batchParameters) {
return batchInsert(null, sql, statementSetter, null, batchParameters);
}
public List batchInsert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final List> batchParameters) {
return batchInsert(null, sql, statementSetter, jdbcSettings, batchParameters);
}
public List batchInsert(final Connection conn, final String sql, final List> batchParameters) {
return batchInsert(conn, sql, null, null, batchParameters);
}
public List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final List> batchParameters) {
return batchInsert(conn, sql, statementSetter, null, batchParameters);
}
/**
*
* @see #batchInsert(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
@SuppressWarnings("deprecation")
public List batchInsert(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings,
final List> batchParameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
String idPropName = checkGeneratedIdPropName(jdbcSettings);
final int len = batchParameters.size();
final int batchSize = getBatchSize(jdbcSettings);
List resultIdList = new ArrayList<>(len);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
boolean autoCommit = true;
try {
ds = getDataSource(namedSQL.getPureSQL(), batchParameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
try {
autoCommit = localConn.getAutoCommit();
} catch (SQLException e) {
closeQuietly(null, localConn, conn);
throw new UncheckedSQLException(e, namedSQL.toString());
}
if ((conn == null) && (len > batchSize)) {
localConn.setAutoCommit(false);
}
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.RETURN_GENERATED_KEYS, true, batchParameters);
if (len <= batchSize) {
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, batchParameters.get(i));
stmt.addBatch();
}
executeBatchInsert(resultIdList, namedSQL, stmt);
} else {
int num = 0;
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, batchParameters.get(i));
stmt.addBatch();
num++;
if ((num % batchSize) == 0) {
executeBatchInsert(resultIdList, namedSQL, stmt);
}
}
if ((num % batchSize) > 0) {
executeBatchInsert(resultIdList, namedSQL, stmt);
}
}
if ((conn == null) && (len > batchSize)) {
localConn.commit();
}
} catch (SQLException e) {
if ((conn == null) && (len > batchSize)) {
if (logger.isWarnEnabled()) {
logger.warn("Trying to roll back ...");
}
try {
localConn.rollback();
if (logger.isWarnEnabled()) {
logger.warn("succeeded to roll back");
}
} catch (SQLException e1) {
logger.error("Failed to roll back", e1);
}
}
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if ((conn == null) && (len > batchSize)) {
try {
localConn.setAutoCommit(autoCommit);
} catch (SQLException e) {
logger.error("Failed to reset AutoCommit", e);
}
}
closeQuietly(stmt, localConn, conn);
}
if (N.notNullOrEmpty(resultIdList)) {
if (isEntityOrMapParameter(namedSQL, batchParameters.get(0))) {
if (resultIdList.size() == len) {
boolean isTypedParameter = batchParameters.get(0) instanceof TypedParameters;
Object parameter_0 = isTypedParameter ? ((TypedParameters) batchParameters.get(0)).parameters[0] : batchParameters.get(0);
if (parameter_0 instanceof Map) {
// // don't update input map ?
// Map m = null;
// Object idPropValue = null;
//
// for (int i = 0; i < parameters.length; i++) {
// m = (Map) (isTypedParameter
// ? ((TypedParameters) parameters[i]).parameters[0] :
// parameters[i]);
// idPropValue = m.get(generatedIdPropName);
//
// if ((idPropValue == null)
// || (idPropValue instanceof Number
// && (((Number) idPropValue).longValue() == 0))) {
// m.put(generatedIdPropName, resultList.get(i));
// }
// }
} else {
try {
Method idGetMethod = RefUtil.getPropGetMethod(parameter_0.getClass(), idPropName);
Method idSetMethod = RefUtil.getPropSetMethod(parameter_0.getClass(), idPropName);
if ((idGetMethod != null) && (idSetMethod != null)) {
Object entity = null;
Object idPropValue = null;
for (int i = 0; i < len; i++) {
entity = (isTypedParameter ? ((TypedParameters) batchParameters.get(i)).parameters[0] : batchParameters.get(i));
idPropValue = RefUtil.invokeMethod(entity, idGetMethod);
if ((idPropValue == null) || (idPropValue instanceof Number && (((Number) idPropValue).longValue() == 0))) {
RefUtil.setPropValue(entity, idSetMethod, resultIdList.get(i));
}
if (entity instanceof DirtyMarker) {
((DirtyMarker) entity).dirtyPropNames().clear();
}
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to set the returned id property to entity. no get/set method for id property (" + idPropName + ") found. ");
}
}
} catch (Exception e) {
logger.error("Failed to set the returned id property to entity", e);
}
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to set the returned id property to entity/map. because the size of returned key not equals the lenght of the input arrray");
}
}
}
}
return resultIdList;
}
protected void executeBatchInsert(final List resultIdList, final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
stmt.executeBatch();
ResultSet rs = null;
try {
rs = stmt.getGeneratedKeys();
while (rs.next()) {
resultIdList.add((T) rs.getObject(1));
}
} catch (SQLException e) {
logger.error("Failed to retrieve the auto-generated Ids", e);
} finally {
closeQuietly(rs);
}
stmt.clearBatch();
}
@SafeVarargs
public final int update(final String sql, final Object... parameters) {
return update(null, sql, null, null, parameters);
}
@SafeVarargs
public final int update(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return update(null, sql, statementSetter, null, parameters);
}
@SafeVarargs
public final int update(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return update(null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final int update(final Connection conn, final String sql, final Object... parameters) {
return update(conn, sql, null, null, parameters);
}
@SafeVarargs
public final int update(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return update(conn, sql, statementSetter, null, parameters);
}
/**
* @see #batchUpdate(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
@SafeVarargs
public final int update(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, false, parameters);
return executeUpdate(namedSQL, stmt);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
closeQuietly(stmt, localConn, conn);
}
}
protected int executeUpdate(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
return stmt.executeUpdate();
}
int batchUpdate(final String sql, final Object[] batchParameters) {
return batchUpdate(null, sql, null, null, batchParameters);
}
int batchUpdate(final String sql, final StatementSetter statementSetter, final Object[] batchParameters) {
return batchUpdate(null, sql, statementSetter, null, batchParameters);
}
int batchUpdate(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object[] batchParameters) {
return batchUpdate(null, sql, statementSetter, jdbcSettings, batchParameters);
}
int batchUpdate(final Connection conn, final String sql, final Object[] batchParameters) {
return batchUpdate(conn, sql, null, null, batchParameters);
}
int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final Object[] batchParameters) {
return batchUpdate(conn, sql, statementSetter, null, batchParameters);
}
/**
* batch insert/update/delete sql scripts are supported
*
* @param conn
* @param sql
* @param statementSetter
* @param props
* @param batchParameters
* @return
*/
int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object[] batchParameters) {
return batchUpdate(conn, sql, statementSetter, jdbcSettings, Arrays.asList(batchParameters));
}
public int batchUpdate(final String sql, final List> batchParameters) {
return batchUpdate(null, sql, null, null, batchParameters);
}
public int batchUpdate(final String sql, final StatementSetter statementSetter, final List> batchParameters) {
return batchUpdate(null, sql, statementSetter, null, batchParameters);
}
public int batchUpdate(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final List> batchParameters) {
return batchUpdate(null, sql, statementSetter, jdbcSettings, batchParameters);
}
public int batchUpdate(final Connection conn, final String sql, final List> batchParameters) {
return batchUpdate(conn, sql, null, null, batchParameters);
}
public int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final List> batchParameters) {
return batchUpdate(conn, sql, statementSetter, null, batchParameters);
}
/**
* @see #batchUpdate(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
public int batchUpdate(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final List> batchParameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
final int len = batchParameters.size();
final int batchSize = getBatchSize(jdbcSettings);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
boolean autoCommit = true;
try {
ds = getDataSource(namedSQL.getPureSQL(), batchParameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
try {
autoCommit = localConn.getAutoCommit();
} catch (SQLException e) {
closeQuietly(null, localConn, conn);
throw new UncheckedSQLException(e, namedSQL.toString());
}
if ((conn == null) && (len > batchSize)) {
localConn.setAutoCommit(false);
}
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, true, batchParameters);
int result = 0;
if (len <= batchSize) {
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, batchParameters.get(i));
stmt.addBatch();
}
result += executeBatchUpdate(namedSQL, stmt);
} else {
int num = 0;
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, batchParameters.get(i));
stmt.addBatch();
num++;
if ((num % batchSize) == 0) {
result += executeBatchUpdate(namedSQL, stmt);
}
}
if ((num % batchSize) > 0) {
result += executeBatchUpdate(namedSQL, stmt);
}
}
if ((conn == null) && (len > batchSize)) {
localConn.commit();
}
return result;
} catch (SQLException e) {
if ((conn == null) && (len > batchSize)) {
if (logger.isWarnEnabled()) {
logger.warn("Trying to roll back ...");
}
try {
localConn.rollback();
if (logger.isWarnEnabled()) {
logger.warn("succeeded to roll back");
}
} catch (SQLException e1) {
logger.error("Failed to roll back", e1);
}
}
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if ((conn == null) && (len > batchSize)) {
try {
localConn.setAutoCommit(autoCommit);
} catch (SQLException e) {
logger.error("Failed to reset AutoCommit", e);
}
}
closeQuietly(stmt, localConn, conn);
}
}
protected int executeBatchUpdate(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
final int[] results = stmt.executeBatch();
stmt.clearBatch();
if ((results == null) || (results.length == 0)) {
return 0;
}
int sum = 0;
for (int i = 0; i < results.length; i++) {
sum += results[i];
}
return sum;
}
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int update(final EntityId entityId, final Map props) {
// return update(null, entityId, props);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int update(final Connection conn, final EntityId entityId, final Map props) {
// final Pair2 pair = generateUpdateSQL(entityId, props);
//
// return update(conn, pair.sql, pair.parameters);
// }
//
// private Pair2 generateUpdateSQL(final EntityId entityId, final Map props) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int delete(final EntityId entityId) {
// return delete(null, entityId);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int delete(final Connection conn, final EntityId entityId) {
// final Pair2 pair = generateDeleteSQL(entityId);
//
// return update(conn, pair.sql, pair.parameters);
// }
//
// private Pair2 generateDeleteSQL(final EntityId entityId) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// boolean exists(final EntityId entityId) {
// return exists(null, entityId);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// boolean exists(final Connection conn, final EntityId entityId) {
// final Pair2 pair = generateQuerySQL(entityId, NE._1_list);
//
// return query(conn, pair.sql, null, EXISTS_RESULT_SET_EXTRACTOR, null, pair.parameters);
// }
@SafeVarargs
public final boolean exists(final String sql, final Object... parameters) {
return exists(null, sql, parameters);
}
@SafeVarargs
public final boolean exists(final Connection conn, final String sql, final Object... parameters) {
return query(conn, sql, null, EXISTS_RESULT_SET_EXTRACTOR, null, parameters);
}
@SafeVarargs
public final int count(final String sql, final Object... parameters) {
return count(null, sql, parameters);
}
@SafeVarargs
public final int count(final Connection conn, final String sql, final Object... parameters) {
return queryForSingleResult(int.class, conn, sql, parameters).or(0);
}
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final EntityId entityId, final String... selectPropNames) {
// return get(targetClass, entityId, N.asList(selectPropNames));
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final EntityId entityId, final Collection selectPropNames) {
// return get(targetClass, null, entityId, selectPropNames);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final Connection conn, final EntityId entityId, final String... selectPropNames) {
// return get(targetClass, conn, entityId, N.asList(selectPropNames));
// }
//
// /**
// *
// * @param targetClass
// * @param conn
// * @param entityId
// * @param selectPropNames
// * @return NonUniqueResultException if more than one records are found.
// */
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final Connection conn, final EntityId entityId, final Collection selectPropNames) {
// final Pair2 pair = generateQuerySQL(entityId, selectPropNames);
// final List entities = find(targetClass, conn, pair.sql, pair.parameters);
//
// if (entities.size() > 1) {
// throw new NonUniqueResultException("More than one records found by EntityId: " + entityId.toString());
// }
//
// return (entities.size() > 0) ? entities.get(0) : null;
// }
//
// private Pair2 generateQuerySQL(final EntityId entityId, final Collection selectPropNames) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
@SafeVarargs
public final T get(final Class targetClass, final String sql, final Object... parameters) {
return get(targetClass, sql, null, null, parameters);
}
public T get(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return get(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final T get(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return get(targetClass, conn, sql, null, null, parameters);
}
/**
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
* @throws NonUniqueResultException if two or more records are found.
*/
@SuppressWarnings("unchecked")
public T get(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
jdbcSettings = jdbcSettings == null ? _jdbcSettings.copy() : jdbcSettings.copy();
jdbcSettings.setCount(2);
final List entities = find(targetClass, conn, sql, statementSetter, jdbcSettings, parameters);
if (entities.size() > 1) {
throw new NonUniqueResultException("More than one records found by sql: " + sql);
}
return (entities.size() > 0) ? entities.get(0) : null;
}
@SafeVarargs
public final List find(final Class targetClass, final String sql, final Object... parameters) {
return find(targetClass, sql, null, null, parameters);
}
public List find(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return find(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final List find(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return find(targetClass, conn, sql, null, null, parameters);
}
/**
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SuppressWarnings("unchecked")
public List find(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return (List) query(targetClass, conn, sql, statementSetter, ENTITY_LIST_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
}
@SafeVarargs
public final List findAll(final Class targetClass, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, sql, null, jdbcSettings, parameters);
}
public List findAll(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return findAll(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
List findAll(final Class targetClass, final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List findAll(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List iterators = this.iterateAll(conn, sql, statementSetter, newJdbcSettings, parameters);
try (final Stream stream = (jdbcSettings.isQueryInParallel() ? Stream.parallelConcat2(iterators, iterators.size())
: Stream.concat2(iterators)).skip(jdbcSettings.getOffset()).limit(jdbcSettings.getCount())) {
final NamedSQL namedSQL = getNamedSQL(sql);
final ResultSet rs = iterators.get(0).resultSet();
final String[] columnLabels = getColumnLabelList(namedSQL.getPureSQL(), rs).toArray(new String[0]);
final int columnCount = columnLabels.length;
final boolean isMap = Map.class.isAssignableFrom(targetClass);
final boolean isDirtyMarker = N.isDirtyMarker(targetClass);
final List resultList = new ArrayList<>();
stream.forEach(new Consumer() {
@Override
public void accept(Object[] a) {
if (isMap) {
final Map m = (Map) N.newInstance(targetClass);
for (int i = 0; i < columnCount; i++) {
m.put(columnLabels[i], a[i]);
}
resultList.add((T) m);
} else {
final Object entity = N.newInstance(targetClass);
for (int i = 0; i < columnCount; i++) {
if (columnLabels[i] == null) {
continue;
}
if (RefUtil.setPropValue(entity, columnLabels[i], a[i], true) == false) {
columnLabels[i] = null;
}
}
if (isDirtyMarker) {
((DirtyMarker) entity).markDirty(false);
}
resultList.add((T) entity);
}
}
});
return resultList;
} catch (
SQLException e) {
throw new UncheckedSQLException(e);
} finally {
IOUtil.closeQuietly(iterators);
}
}
@SafeVarargs
public final List findAll(final Class targetClass, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, sqls, null, jdbcSettings, parameters);
}
public List findAll(final Class targetClass, final List sqls, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return findAll(targetClass, null, sqls, statementSetter, jdbcSettings, parameters);
}
List findAll(final Class targetClass, final Connection conn, final List sqls, final JdbcSettings jdbcSettings,
final Object... parameters) {
return findAll(targetClass, conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param targetClass
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List findAll(final Class targetClass, final Connection conn, final List sqls, final StatementSetter statementSetter,
JdbcSettings jdbcSettings, final Object... parameters) {
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List iterators = this.iterateAll(conn, sqls, statementSetter, newJdbcSettings, parameters);
try (final Stream stream = (jdbcSettings.isQueryInParallel() ? Stream.parallelConcat2(iterators, iterators.size())
: Stream.concat2(iterators)).skip(jdbcSettings.getOffset()).limit(jdbcSettings.getCount())) {
final NamedSQL namedSQL = getNamedSQL(sqls.get(0));
final ResultSet rs = iterators.get(0).resultSet();
final String[] columnLabels = getColumnLabelList(namedSQL.getPureSQL(), rs).toArray(new String[0]);
final int columnCount = columnLabels.length;
final boolean isMap = Map.class.isAssignableFrom(targetClass);
final boolean isDirtyMarker = N.isDirtyMarker(targetClass);
final List resultList = new ArrayList<>();
stream.forEach(new Consumer() {
@Override
public void accept(Object[] a) {
if (isMap) {
final Map m = (Map) N.newInstance(targetClass);
for (int i = 0; i < columnCount; i++) {
m.put(columnLabels[i], a[i]);
}
resultList.add((T) m);
} else {
final Object entity = N.newInstance(targetClass);
for (int i = 0; i < columnCount; i++) {
if (columnLabels[i] == null) {
continue;
}
if (RefUtil.setPropValue(entity, columnLabels[i], a[i], true) == false) {
columnLabels[i] = null;
}
}
if (isDirtyMarker) {
((DirtyMarker) entity).markDirty(false);
}
resultList.add((T) entity);
}
}
});
return resultList;
} catch (
SQLException e) {
throw new UncheckedSQLException(e);
} finally {
IOUtil.closeQuietly(iterators);
}
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalBoolean queryForBoolean(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(boolean.class, null, sql, parameters);
return result.isPresent() ? OptionalBoolean.of(result.get()) : OptionalBoolean.empty();
}
/**
*
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalChar queryForChar(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(char.class, null, sql, parameters);
return result.isPresent() ? OptionalChar.of(result.get()) : OptionalChar.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalByte queryForByte(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(byte.class, null, sql, parameters);
return result.isPresent() ? OptionalByte.of(result.get()) : OptionalByte.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalShort queryForShort(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(short.class, null, sql, parameters);
return result.isPresent() ? OptionalShort.of(result.get()) : OptionalShort.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalInt queryForInt(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(int.class, null, sql, parameters);
return result.isPresent() ? OptionalInt.of(result.get()) : OptionalInt.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalLong queryForLong(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(long.class, null, sql, parameters);
return result.isPresent() ? OptionalLong.of(result.get()) : OptionalLong.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalFloat queryForFloat(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(float.class, null, sql, parameters);
return result.isPresent() ? OptionalFloat.of(result.get()) : OptionalFloat.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalDouble queryForDouble(final String sql, final Object... parameters) {
final NullabLe result = queryForSingleResult(double.class, null, sql, parameters);
return result.isPresent() ? OptionalDouble.of(result.get()) : OptionalDouble.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final NullabLe queryForString(final String sql, final Object... parameters) {
return queryForSingleResult(String.class, null, sql, parameters);
}
@SafeVarargs
public final NullabLe queryForSingleResult(final Class targetClass, final String sql, final Object... parameters) {
return queryForSingleResult(targetClass, sql, null, null, parameters);
}
public NullabLe queryForSingleResult(final Class targetClass, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return queryForSingleResult(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final NullabLe queryForSingleResult(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return queryForSingleResult(targetClass, conn, sql, null, null, parameters);
}
/**
* Just fetch the result in the 1st row and 1st column. {@code null} is returned if no result is found. And this
* method will try to convert the result to the specified {@code targetClass} if {@code targetClass} is not null and it's not
* assignable from the result.
*
* Special note for type conversion for {@code boolean} or {@code Boolean} type: {@code true} is returned if the
* {@code String} value of the target column is {@code "true"}, case insensitive. or it's an integer with value > 0.
* Otherwise, {@code false} is returned.
*
* Remember to add {@code limit} condition if big result will be returned by the query.
*
* @param targetClass
* set result type to avoid the NullPointerException if result is null and T is primitive type
* "int, long. short ... char, boolean..".
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @throws ClassCastException
*/
@SuppressWarnings("unchecked")
public NullabLe queryForSingleResult(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
final NullabLe> result = query(conn, sql, statementSetter, SINGLE_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
return result.isPresent() ? NullabLe.of(N.as(targetClass, result.get())) : (NullabLe) NullabLe.empty();
}
//
// public Map queryForMap(String sql, Object... parameters) {
// return queryForMap(sql, null, parameters);
// }
//
// public Map queryForMap(String sql, StatementSetter statementSetter, Object... parameters) {
// return queryForMap(null, sql, statementSetter, parameters);
// }
//
// public Map queryForMap(final Connection conn, final String sql, Object... parameters) {
// return queryForMap(conn, sql, null, parameters);
// }
//
// /**
// * Just fetch the result in the 1st row. {@code null} is returned if no result is found.
// *
// * Remember to add {@code limit} condition if big result will be returned by the query.
// *
// * @param conn
// * @param sql
// * @param statementSetter
// * @param parameters
// * @return
// */
// public Map queryForMap(final Connection conn, final String sql, StatementSetter statementSetter, Object... parameters) {
// return query(conn, sql, statementSetter, MAP_RESULT_SET_EXTRACTOR, null, parameters);
// }
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final String sql, final Object... parameters) {
return queryForEntity(targetClass, sql, null, null, parameters);
}
public Optional queryForEntity(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return queryForEntity(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return queryForEntity(targetClass, conn, sql, null, null, parameters);
}
/**
* Just fetch the result in the 1st row. {@code null} is returned if no result is found. This method will try to
* convert the column value to the type of mapping entity property if the mapping entity property is not assignable
* from column value.
*
* Remember to add {@code limit} condition if big result will be returned by the query.
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SuppressWarnings("unchecked")
public Optional queryForEntity(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
final T result = (T) query(targetClass, conn, sql, statementSetter, ENTITY_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
return result == null ? (Optional) Optional.empty() : Optional.of(result);
}
@SafeVarargs
public final DataSet query(final String sql, final Object... parameters) {
return query(sql, null, parameters);
}
@SafeVarargs
public final DataSet query(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return query(sql, statementSetter, null, parameters);
}
//
// public T query(String sql, ResultSetExtractor resultSetExtractor,
// Object... parameters) {
// return query(null, sql, null, resultSetExtractor, null, parameters);
// }
//
@SafeVarargs
public final T query(final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final Object... parameters) {
return query(sql, statementSetter, resultSetExtractor, null, parameters);
}
/**
* Remember to close the ResultSet
, Statement
and Connection
if the return type T
is ResultSet
or RowIterator
.
*
* If T
is RowIterator
, call rowIterator.close()
to close ResultSet
, Statement
and Connection
.
*
* If T
is ResultSet
, call below codes to close ResultSet
, Statement
and Connection
.
*
*
*
* Connection conn = null;
* Statement stmt = null;
*
* try {
* stmt = rs.getStatement();
* conn = stmt.getConnection();
* } catch (SQLException e) {
* // TODO.
* } finally {
* JdbcUtil.closeQuietly(rs, stmt, conn);
* }
*
*
*
* @param sql
* @param statementSetter
* @param resultSetExtractor
* @param jdbcSettings
* @param parameters
* @return
*/
public T query(final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor, final JdbcSettings jdbcSettings,
final Object... parameters) {
return query(null, sql, statementSetter, resultSetExtractor, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet query(final Connection conn, final String sql, final Object... parameters) {
return query(conn, sql, null, parameters);
}
@SafeVarargs
public final DataSet query(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return query(conn, sql, statementSetter, null, parameters);
}
public T query(final Connection conn, final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final Object... parameters) {
return query(conn, sql, statementSetter, resultSetExtractor, null, parameters);
}
/**
* Remember to close the ResultSet
, Statement
and Connection
if the return type T
is ResultSet
or RowIterator
.
*
* If T
is RowIterator
, call rowIterator.close()
to close ResultSet
, Statement
and Connection
.
*
* If T
is ResultSet
, call below codes to close ResultSet
, Statement
and Connection
.
*
*
*
* Connection conn = null;
* Statement stmt = null;
*
* try {
* stmt = rs.getStatement();
* conn = stmt.getConnection();
* } catch (SQLException e) {
* // TODO.
* } finally {
* JdbcUtil.closeQuietly(rs, stmt, conn);
* }
*
*
*
* @param conn
* @param sql
* @param statementSetter
* @param resultSetExtractor
* @param jdbcSettings
* @param parameters
* @return
*/
public T query(final Connection conn, final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final JdbcSettings jdbcSettings, final Object... parameters) {
return query(null, conn, sql, statementSetter, resultSetExtractor, jdbcSettings, parameters);
}
protected T query(final Class targetClass, final Connection conn, final String sql, StatementSetter statementSetter,
ResultSetExtractor resultSetExtractor, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
resultSetExtractor = checkResultSetExtractor(namedSQL, resultSetExtractor);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
T result = null;
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, false, parameters);
rs = stmt.executeQuery();
result = resultSetExtractor.extractData(targetClass, namedSQL, rs, jdbcSettings);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if (result instanceof ResultSet || result instanceof RowIterator) {
// delay.
} else {
closeQuietly(rs, stmt, localConn, conn);
}
}
return result;
}
@SafeVarargs
public final DataSet queryAll(final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(sql, null, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet queryAll(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(null, sql, statementSetter, jdbcSettings, parameters);
}
DataSet queryAll(final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
DataSet queryAll(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List iterators = this.iterateAll(conn, sql, statementSetter, newJdbcSettings, parameters);
try (final Stream stream = (jdbcSettings.isQueryInParallel() ? Stream.parallelConcat2(iterators, iterators.size())
: Stream.concat2(iterators)).skip(jdbcSettings.getOffset()).limit(jdbcSettings.getCount())) {
final NamedSQL namedSQL = getNamedSQL(sql);
final ResultSet rs = iterators.get(0).resultSet();
final List columnLabelList = getColumnLabelList(namedSQL.getPureSQL(), rs);
final int columnCount = columnLabelList.size();
final List columnNameList = new ArrayList<>(columnCount);
final List> columnList = new ArrayList<>(columnCount);
for (int i = 0; i < columnCount; i++) {
columnNameList.add(columnLabelList.get(i));
columnList.add(new ArrayList<>());
}
stream.forEach(new Consumer() {
@Override
public void accept(Object[] a) {
for (int i = 0; i < columnCount; i++) {
columnList.get(i).add(a[i]);
}
}
});
return new RowDataSet(columnNameList, columnList);
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
IOUtil.closeQuietly(iterators);
}
}
@SafeVarargs
public final DataSet queryAll(final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(sqls, null, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet queryAll(final List sqls, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(null, sqls, statementSetter, jdbcSettings, parameters);
}
DataSet queryAll(final Connection conn, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
DataSet queryAll(final Connection conn, final List sqls, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List iterators = this.iterateAll(conn, sqls, statementSetter, newJdbcSettings, parameters);
try (final Stream stream = (jdbcSettings.isQueryInParallel() ? Stream.parallelConcat2(iterators, iterators.size())
: Stream.concat2(iterators)).skip(jdbcSettings.getOffset()).limit(jdbcSettings.getCount())) {
final NamedSQL namedSQL = getNamedSQL(sqls.get(0));
final ResultSet rs = iterators.get(0).resultSet();
final List columnLabelList = getColumnLabelList(namedSQL.getPureSQL(), rs);
final int columnCount = columnLabelList.size();
final List columnNameList = new ArrayList<>(columnCount);
final List> columnList = new ArrayList<>(columnCount);
for (int i = 0; i < columnCount; i++) {
columnNameList.add(columnLabelList.get(i));
columnList.add(new ArrayList<>());
}
stream.forEach(new Consumer() {
@Override
public void accept(Object[] a) {
for (int i = 0; i < columnCount; i++) {
columnList.get(i).add(a[i]);
}
}
});
return new RowDataSet(columnNameList, columnList);
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
IOUtil.closeQuietly(iterators);
}
}
//
// public Map queryForMap(String sql, Object... parameters) {
// return queryForMap(sql, null, parameters);
// }
//
// public Map queryForMap(String sql, StatementSetter statementSetter, Object... parameters) {
// return queryForMap(null, sql, statementSetter, parameters);
// }
//
// public Map queryForMap(final Connection conn, final String sql, Object... parameters) {
// return queryForMap(conn, sql, null, parameters);
// }
//
// /**
// * Just fetch the result in the 1st row. {@code null} is returned if no result is found.
// *
// * Remember to add {@code limit} condition if big result will be returned by the query.
// *
// * @param conn
// * @param sql
// * @param statementSetter
// * @param parameters
// * @return
// */
// public Map queryForMap(final Connection conn, final String sql, StatementSetter statementSetter, Object... parameters) {
// return query(conn, sql, statementSetter, MAP_RESULT_SET_EXTRACTOR, null, parameters);
// }
RowIterator iterate(final String sql, final Object... parameters) {
return iterate(sql, null, parameters);
}
RowIterator iterate(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return iterate(sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned RowIterator
to close the underlying ResultSet
.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
RowIterator iterate(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterate(null, sql, statementSetter, jdbcSettings, parameters);
}
RowIterator iterate(final Connection conn, final String sql, final Object... parameters) {
return iterate(conn, sql, null, parameters);
}
RowIterator iterate(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return iterate(conn, sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned RowIterator
to close the underlying ResultSet
.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
RowIterator iterate(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if RowIterator is closed. that means the specified connection can't be held independently.
return query(conn, sql, statementSetter, ROW_ITERATOR_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
}
List iterateAll(final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(sql, null, jdbcSettings, parameters);
}
/**
* Remember to close the returned RowIterator
list to close the underlying ResultSet
list.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
List iterateAll(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(null, sql, statementSetter, jdbcSettings, parameters);
}
List iterateAll(final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List iterateAll(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
if (jdbcSettings != null && (jdbcSettings.getOffset() != 0 || jdbcSettings.getCount() != Long.MAX_VALUE)) {
throw new IllegalArgumentException("Can't specify 'offset' or 'count' for iterateAll method");
}
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings;
}
if (jdbcSettings == null || N.isNullOrEmpty(jdbcSettings.getQueryWithDataSources())) {
return N.asList(iterate(conn, sql, statementSetter, jdbcSettings, parameters));
} else {
final List iterators = new ArrayList<>();
final Holder errorHolder = new Holder<>();
final AtomicInteger activeThreadNum = new AtomicInteger(0);
for (String dataSource : jdbcSettings.getQueryWithDataSources()) {
final JdbcSettings newJdbcSettings = jdbcSettings == null ? _jdbcSettings.copy() : jdbcSettings.copy();
newJdbcSettings.setOffset(0).setCount(Long.MAX_VALUE);
newJdbcSettings.setQueryWithDataSource(dataSource);
final Runnable cmd = new Runnable() {
@Override
public void run() {
try {
if (errorHolder.value() != null) {
return;
}
final RowIterator tmp = iterate(conn, sql, statementSetter, newJdbcSettings, parameters);
synchronized (iterators) {
iterators.add(tmp);
}
} catch (Throwable e) {
if (JdbcUtil.isTableNotExistsException(e)) {
// ignore;
} else {
setException(errorHolder, e);
}
} finally {
activeThreadNum.decrementAndGet();
}
}
};
activeThreadNum.incrementAndGet();
if (newJdbcSettings.isQueryInParallel()) {
_asyncExecutor.execute(cmd);
} else {
cmd.run();
}
}
while (activeThreadNum.get() > 0) {
N.sleep(1);
}
if (errorHolder.value() != null) {
try {
throw N.toRuntimeException(errorHolder.value());
} finally {
IOUtil.closeQuietly(iterators);
}
}
return iterators;
}
}
List iterateAll(final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(sqls, null, jdbcSettings, parameters);
}
/**
* Remember to close the returned RowIterator
list to close the underlying ResultSet
list.
*
* @param sqls
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
List iterateAll(final List sqls, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(null, sqls, statementSetter, jdbcSettings, parameters);
}
List iterateAll(final Connection conn, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return iterateAll(conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List iterateAll(final Connection conn, final List sqls, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if RowIterator is closed. that means the specified connection can't be held independently.
N.checkNullOrEmpty(sqls, "sqls");
if (jdbcSettings != null && (jdbcSettings.getOffset() != 0 || jdbcSettings.getCount() != Long.MAX_VALUE)) {
throw new IllegalArgumentException("Can't specify 'offset' or 'count' for iterateAll method");
}
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings;
}
final List iterators = new ArrayList<>();
final Holder errorHolder = new Holder<>();
final AtomicInteger activeThreadNum = new AtomicInteger(0);
for (String e : sqls) {
final String sql = e;
final JdbcSettings newJdbcSettings = jdbcSettings == null ? _jdbcSettings.copy() : jdbcSettings.copy();
newJdbcSettings.setOffset(0).setCount(Long.MAX_VALUE);
final Runnable cmd = new Runnable() {
@Override
public void run() {
try {
if (errorHolder.value() != null) {
return;
}
final List tmp = iterateAll(conn, sql, statementSetter, newJdbcSettings, parameters);
synchronized (iterators) {
iterators.addAll(tmp);
}
} catch (Throwable e) {
if (JdbcUtil.isTableNotExistsException(e)) {
// ignore;
} else {
setException(errorHolder, e);
}
} finally {
activeThreadNum.decrementAndGet();
}
}
};
activeThreadNum.incrementAndGet();
if (newJdbcSettings.isQueryInParallel()) {
_asyncExecutor.execute(cmd);
} else {
cmd.run();
}
}
while (activeThreadNum.get() > 0) {
N.sleep(1);
}
if (errorHolder.value() != null) {
try {
throw N.toRuntimeException(errorHolder.value());
} finally {
IOUtil.closeQuietly(iterators);
}
}
return iterators;
}
@SafeVarargs
public final Try> stream(final String sql, final Object... parameters) {
return stream(sql, null, parameters);
}
@SafeVarargs
public final Try> stream(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return stream(sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned Stream
to close the underlying ResultSet
.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final Try> stream(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return stream((Connection) null, sql, statementSetter, jdbcSettings, parameters);
}
Try> stream(final Connection conn, final String sql, final Object... parameters) {
return stream(conn, sql, null, parameters);
}
Try> stream(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return stream(conn, sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned Stream
to close the underlying ResultSet
.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
Try> stream(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
final RowIterator iterator = this.iterate(conn, sql, statementSetter, jdbcSettings, parameters);
return Stream.of(iterator).onClose(new Runnable() {
private volatile boolean isClosed = false;
@Override
public void run() {
if (isClosed) {
return;
}
isClosed = true;
IOUtil.closeQuietly(iterator);
}
}).tried();
}
@SafeVarargs
public final Try> streamAll(final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return streamAll(sql, null, jdbcSettings, parameters);
}
/**
* Remember to close the returned Stream
list to close the underlying ResultSet
list.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
public Try> streamAll(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return streamAll((Connection) null, sql, statementSetter, jdbcSettings, parameters);
}
Try> streamAll(final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return streamAll(conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
Try> streamAll(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List iterators = this.iterateAll(conn, sql, statementSetter, newJdbcSettings, parameters);
return (jdbcSettings.isQueryInParallel() ? Stream.parallelConcat2(iterators, iterators.size()) : Stream.concat2(iterators))
.skip(jdbcSettings.getOffset()).limit(jdbcSettings.getCount()).onClose(new Runnable() {
private volatile boolean isClosed = false;
@Override
public void run() {
if (isClosed) {
return;
}
isClosed = true;
IOUtil.closeQuietly(iterators);
}
}).tried();
}
@SafeVarargs
public final Try> streamAll(final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return streamAll(sqls, null, jdbcSettings, parameters);
}
/**
* Remember to close the returned Stream
list to close the underlying ResultSet
list.
*
* @param sqls
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
public Try> streamAll(final List sqls, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return streamAll((Connection) null, sqls, statementSetter, jdbcSettings, parameters);
}
Try> streamAll(final Connection conn, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return streamAll(conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
Try> streamAll(final Connection conn, final List sqls, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List