use of org.apache.cayenne.tx.Transaction in project cayenne by apache.
the class DataNode method performQueries.
/**
* Runs queries using Connection obtained from internal DataSource.
*
* @since 1.1
*/
@Override
public void performQueries(Collection<? extends Query> queries, OperationObserver callback) {
int listSize = queries.size();
if (listSize == 0) {
return;
}
if (callback.isIteratedResult() && listSize > 1) {
throw new CayenneRuntimeException("Iterated queries are not allowed in a batch. Batch size: %d", listSize);
}
// do this meaningless inexpensive operation to trigger AutoAdapter lazy
// initialization before opening a connection. Otherwise we may end up
// with two
// connections open simultaneously, possibly hitting connection pool
// upper limit.
getAdapter().getExtendedTypes();
Connection connection = null;
try {
connection = this.getDataSource().getConnection();
} catch (Exception globalEx) {
getJdbcEventLogger().logQueryError(globalEx);
Transaction transaction = BaseTransaction.getThreadTransaction();
if (transaction != null) {
transaction.setRollbackOnly();
}
callback.nextGlobalException(globalEx);
return;
}
try {
DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, callback);
for (Query nextQuery : queries) {
// catch exceptions for each individual query
try {
queryRunner.runQuery(connection, nextQuery);
} catch (Exception queryEx) {
getJdbcEventLogger().logQueryError(queryEx);
// notify consumer of the exception,
// stop running further queries
callback.nextQueryException(nextQuery, queryEx);
Transaction transaction = BaseTransaction.getThreadTransaction();
if (transaction != null) {
transaction.setRollbackOnly();
}
break;
}
}
} finally {
try {
connection.close();
} catch (SQLException e) {
// ignore closing exceptions...
}
}
}
use of org.apache.cayenne.tx.Transaction in project cayenne by apache.
the class DataContextPerformQueryAPIIT method testProcedureQueryStringMapBoolean.
@Test
public void testProcedureQueryStringMapBoolean() throws Exception {
if (!accessStackAdapter.supportsStoredProcedures()) {
return;
}
if (!accessStackAdapter.canMakeObjectsOutOfProcedures()) {
return;
}
createTwoArtistsAndTwoPaintingsDataSet();
// fetch artist
Map<String, String> parameters = Collections.singletonMap("aName", "artist2");
List<?> artists;
// Sybase blows whenever a transaction wraps a SP, so turn of
// transactions
Transaction t = new ExternalTransaction(jdbcEventLogger);
BaseTransaction.bindThreadTransaction(t);
try {
artists = context.performQuery("ProcedureQuery", parameters, true);
} finally {
BaseTransaction.bindThreadTransaction(null);
t.commit();
}
assertNotNull(artists);
assertEquals(1, artists.size());
Artist artist = (Artist) artists.get(0);
assertEquals(11, ((Number) artist.getObjectId().getIdSnapshot().get(Artist.ARTIST_ID_PK_COLUMN)).intValue());
}
use of org.apache.cayenne.tx.Transaction in project cayenne by apache.
the class SybasePkGenerator method longPkFromDatabase.
/**
* @since 3.0
*/
@Override
protected long longPkFromDatabase(DataNode node, DbEntity entity) throws Exception {
// handle CAY-588 - get connection that is separate from the connection
// in the current transaction.
// TODO (andrus, 7/6/2006) Note that this will still work in a pool with
// a single connection, as PK generator is invoked early in the transaction,
// before the connection is grabbed for commit...
// So maybe promote this to other adapters in 3.0?
Transaction transaction = BaseTransaction.getThreadTransaction();
BaseTransaction.bindThreadTransaction(null);
try (Connection connection = node.getDataSource().getConnection()) {
try (CallableStatement statement = connection.prepareCall("{call auto_pk_for_table(?, ?)}")) {
statement.setString(1, entity.getName());
statement.setInt(2, super.getPkCacheSize());
// can't use "executeQuery" per http://jtds.sourceforge.net/faq.html#expectingResultSet
statement.execute();
if (statement.getMoreResults()) {
try (ResultSet rs = statement.getResultSet()) {
if (rs.next()) {
return rs.getLong(1);
} else {
throw new CayenneRuntimeException("Error generating pk for DbEntity %s", entity.getName());
}
}
} else {
throw new CayenneRuntimeException("Error generating pk for DbEntity %s" + ", no result set from stored procedure.", entity.getName());
}
}
} finally {
BaseTransaction.bindThreadTransaction(transaction);
}
}
use of org.apache.cayenne.tx.Transaction in project cayenne by apache.
the class MySQLPkGenerator method longPkFromDatabase.
/**
* Overrides superclass's implementation to perform locking of the primary
* key lookup table.
*
* @since 3.0
*/
@Override
protected long longPkFromDatabase(DataNode node, DbEntity entity) throws Exception {
// must work directly with JDBC connection, since we
// must unlock the AUTO_PK_SUPPORT table in case of
// failures.... ah..JDBC is fun...
// chained SQL exception
SQLException exception = null;
long pk = -1L;
// Start new transaction if needed, can any way lead to problems when
// using external transaction manager. We can only warn about it.
// See https://issues.apache.org/jira/browse/CAY-2186 for details.
Transaction transaction = BaseTransaction.getThreadTransaction();
if (transaction != null && transaction.isExternal()) {
logger.warn("Using MysqlPkGenerator with external transaction manager may lead to inconsistent state.");
}
BaseTransaction.bindThreadTransaction(null);
try (Connection con = node.getDataSource().getConnection()) {
if (con.getAutoCommit()) {
con.setAutoCommit(false);
}
try (Statement st = con.createStatement()) {
try {
pk = getLongPrimaryKey(st, entity.getName());
con.commit();
} catch (SQLException pkEx) {
try {
con.rollback();
} catch (SQLException ignored) {
}
exception = processSQLException(pkEx, null);
} finally {
// THIS MUST BE EXECUTED NO MATTER WHAT, OR WE WILL LOCK THE PRIMARY KEY TABLE!!
try {
String unlockString = "UNLOCK TABLES";
adapter.getJdbcEventLogger().log(unlockString);
st.execute(unlockString);
} catch (SQLException unlockEx) {
exception = processSQLException(unlockEx, exception);
}
}
}
} catch (SQLException otherEx) {
exception = processSQLException(otherEx, null);
} finally {
BaseTransaction.bindThreadTransaction(transaction);
}
// check errors
if (exception != null) {
throw exception;
}
return pk;
}
use of org.apache.cayenne.tx.Transaction in project cayenne by apache.
the class DataContext method performIteratedQuery.
/**
* Performs a single database select query returning result as a
* ResultIterator. It is caller's responsibility to explicitly close the
* ResultIterator. A failure to do so will result in a database connection
* not being released. Another side effect of an open ResultIterator is that
* an internal Cayenne transaction that originated in this method stays open
* until the iterator is closed. So users should normally close the iterator
* within the same thread that opened it.
* <p>
* Note that 'performIteratedQuery' always returns ResultIterator over
* DataRows. Use
* {@link #iterate(Select, org.apache.cayenne.ResultIteratorCallback)} to
* get access to objects.
*/
// TODO: deprecate once all selecting queries start implementing Select<T>
// interface
@SuppressWarnings({ "rawtypes" })
public ResultIterator performIteratedQuery(Query query) {
if (BaseTransaction.getThreadTransaction() != null) {
return internalPerformIteratedQuery(query);
} else {
// can't use TransactionManger here as it would attempt to commit the transaction at the end...
// manually manage a transaction, so that a ResultIterator wrapper
// could close it when it is done.
Transaction tx = getTransactionFactory().createTransaction();
BaseTransaction.bindThreadTransaction(tx);
ResultIterator<?> result;
try {
result = internalPerformIteratedQuery(query);
} catch (Exception e) {
tx.setRollbackOnly();
throw new CayenneRuntimeException(e);
} finally {
// unbind thread tx before returning to the caller. Transaction will be managed internally by the
// ResultIterator and should not get in the way of other DB operations that may be performed
// within the iterator....
// TODO: there was an older comment about Ingres breaking when we unbind thread transaction
// before closing the iterator. As we have no test environment for ingres, we can't
// confirm this here...
BaseTransaction.bindThreadTransaction(null);
if (tx.isRollbackOnly()) {
try {
tx.rollback();
} catch (Exception rollbackEx) {
}
}
}
return new TransactionResultIteratorDecorator<>(result, tx);
}
}
Aggregations