|
|
|
|
@@ -197,9 +197,16 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|
|
|
|
* manager needs to work on the underlying target DataSource. If there's
|
|
|
|
|
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
|
|
|
|
|
* unwrapped to extract its target DataSource.
|
|
|
|
|
* <p><b>NOTE: For scenarios with many transactions that just read data from
|
|
|
|
|
* Hibernate's cache (and do not actually access the database), consider using
|
|
|
|
|
* a {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}
|
|
|
|
|
* for the actual target DataSource. Alternatively, consider switching
|
|
|
|
|
* {@link #setPrepareConnection "prepareConnection"} to {@code false}.</b>
|
|
|
|
|
* In both cases, this transaction manager will not eagerly acquire a
|
|
|
|
|
* JDBC Connection for each Hibernate Session anymore (as of Spring 5.1).
|
|
|
|
|
* @see #setAutodetectDataSource
|
|
|
|
|
* @see TransactionAwareDataSourceProxy
|
|
|
|
|
* @see DataSourceUtils
|
|
|
|
|
* @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
|
|
|
|
|
* @see org.springframework.jdbc.core.JdbcTemplate
|
|
|
|
|
*/
|
|
|
|
|
public void setDataSource(@Nullable DataSource dataSource) {
|
|
|
|
|
@@ -462,33 +469,37 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|
|
|
|
|
|
|
|
|
session = txObject.getSessionHolder().getSession();
|
|
|
|
|
|
|
|
|
|
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
|
|
|
|
// We're allowed to change the transaction settings of the JDBC Connection.
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
|
|
|
|
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
|
|
|
}
|
|
|
|
|
Connection con = ((SessionImplementor) session).connection();
|
|
|
|
|
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
|
|
|
|
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
|
|
|
|
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
|
|
|
|
|
int currentHoldability = con.getHoldability();
|
|
|
|
|
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
|
|
|
|
txObject.setPreviousHoldability(currentHoldability);
|
|
|
|
|
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
|
|
|
|
|
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
|
|
|
|
|
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
|
|
|
|
|
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
|
|
|
|
|
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
|
|
|
|
// We're allowed to change the transaction settings of the JDBC Connection.
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
|
|
|
|
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
|
|
|
}
|
|
|
|
|
Connection con = ((SessionImplementor) session).connection();
|
|
|
|
|
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
|
|
|
|
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
|
|
|
|
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
|
|
|
|
|
int currentHoldability = con.getHoldability();
|
|
|
|
|
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
|
|
|
|
txObject.setPreviousHoldability(currentHoldability);
|
|
|
|
|
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Not allowed to change the transaction settings of the JDBC Connection.
|
|
|
|
|
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
|
|
|
|
|
// We should set a specific isolation level but are not allowed to...
|
|
|
|
|
throw new InvalidIsolationLevelException(
|
|
|
|
|
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
|
|
|
|
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
|
|
|
|
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
|
|
|
|
|
}
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
|
|
|
|
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
|
|
|
else {
|
|
|
|
|
// Not allowed to change the transaction settings of the JDBC Connection.
|
|
|
|
|
if (isolationLevelNeeded) {
|
|
|
|
|
// We should set a specific isolation level but are not allowed to...
|
|
|
|
|
throw new InvalidIsolationLevelException(
|
|
|
|
|
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
|
|
|
|
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
|
|
|
|
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
|
|
|
|
|
}
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
|
|
|
|
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -529,13 +540,13 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|
|
|
|
|
|
|
|
|
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
|
|
|
|
|
if (getDataSource() != null) {
|
|
|
|
|
Connection con = ((SessionImplementor) session).connection();
|
|
|
|
|
ConnectionHolder conHolder = new ConnectionHolder(con);
|
|
|
|
|
SessionImplementor sessionImpl = (SessionImplementor) session;
|
|
|
|
|
ConnectionHolder conHolder = new ConnectionHolder(sessionImpl::connection);
|
|
|
|
|
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
|
|
|
|
conHolder.setTimeoutInSeconds(timeout);
|
|
|
|
|
}
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
|
|
|
|
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
|
|
|
|
|
logger.debug("Exposing Hibernate transaction as JDBC [" + conHolder.getConnectionHandle() + "]");
|
|
|
|
|
}
|
|
|
|
|
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
|
|
|
|
|
txObject.setConnectionHolder(conHolder);
|
|
|
|
|
|