📄 sessionfactoryutils.java
字号:
/**
* Process Sessions that have been registered for deferred close
* for the given SessionFactory.
* @param sessionFactory Hibernate SessionFactory
* @see #initDeferredClose
* @see #closeSessionIfNecessary
*/
public static void processDeferredClose(SessionFactory sessionFactory) {
Assert.notNull(sessionFactory, "No SessionFactory specified");
Map holderMap = (Map) deferredCloseHolder.get();
if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
}
logger.debug("Processing deferred close of Hibernate sessions");
Set sessions = (Set) holderMap.remove(sessionFactory);
for (Iterator it = sessions.iterator(); it.hasNext();) {
doClose((Session) it.next());
}
if (holderMap.isEmpty()) {
deferredCloseHolder.set(null);
}
}
/**
* Close the given Session, created via the given factory,
* if it isn't bound to the thread.
* @param session Session to close
* @param sessionFactory Hibernate SessionFactory that the Session was created with
*/
public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory) {
if (session == null) {
return;
}
// Only close non-transactional Sessions.
if (!isSessionTransactional(session, sessionFactory)) {
closeSessionOrRegisterDeferredClose(session, sessionFactory);
}
}
/**
* Close the given Session or register it for deferred close.
* @param session Session to close
* @param sessionFactory Hibernate SessionFactory that the Session was created with
* @see #initDeferredClose
* @see #processDeferredClose
*/
private static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
Map holderMap = (Map) deferredCloseHolder.get();
if (holderMap != null && holderMap.containsKey(sessionFactory)) {
logger.debug("Registering Hibernate session for deferred close");
Set sessions = (Set) holderMap.get(sessionFactory);
sessions.add(session);
}
else {
doClose(session);
}
}
/**
* Perform the actual closing of the Hibernate Session.
* @param session Session to close
*/
private static void doClose(Session session) {
logger.debug("Closing Hibernate session");
try {
session.close();
}
catch (JDBCException ex) {
// SQLException underneath
logger.error("Could not close Hibernate session", ex.getSQLException());
}
catch (HibernateException ex) {
logger.error("Could not close Hibernate session", ex);
}
}
/**
* Callback for resource cleanup at the end of a Spring-managed JTA transaction,
* i.e. when participating in a JtaTransactionManager transaction.
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
private static class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
private final SessionHolder sessionHolder;
private final SessionFactory sessionFactory;
private final SQLExceptionTranslator jdbcExceptionTranslator;
private final boolean newSession;
/**
* Whether Hibernate has a looked-up JTA TransactionManager that it will
* automatically register CacheSynchronizations with on Session connect.
*/
private boolean hibernateTransactionCompletion = false;
private Transaction jtaTransaction;
private SpringSessionSynchronization(
SessionHolder sessionHolder, SessionFactory sessionFactory,
SQLExceptionTranslator jdbcExceptionTranslator, boolean newSession) {
this.sessionHolder = sessionHolder;
this.sessionFactory = sessionFactory;
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
this.newSession = newSession;
// check whether the SessionFactory has a JTA TransactionManager
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
if (jtaTm != null) {
this.hibernateTransactionCompletion = true;
// fetch current JTA Transaction object
// (just necessary for JTA transaction suspension, with an individual
// Hibernate Session per currently active/suspended transaction)
try {
int jtaStatus = jtaTm.getStatus();
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
this.jtaTransaction = jtaTm.getTransaction();
}
}
catch (SystemException ex) {
throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
}
}
}
public int getOrder() {
return SESSION_SYNCHRONIZATION_ORDER;
}
public void suspend() {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
public void resume() {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
public void beforeCommit(boolean readOnly) throws DataAccessException {
if (!readOnly) {
// read-write transaction -> flush the Hibernate Session
logger.debug("Flushing Hibernate session on transaction synchronization");
Session session = null;
// Check whether there is a Hibernate Session for the current JTA
// transaction. Else, fall back to the default thread-bound Session.
if (this.jtaTransaction != null) {
session = this.sessionHolder.getSession(this.jtaTransaction);
}
if (session == null) {
session = this.sessionHolder.getSession();
}
// further check: only flush when not FlushMode.NEVER
if (!session.getFlushMode().equals(FlushMode.NEVER)) {
try {
session.flush();
}
catch (JDBCException ex) {
if (this.jdbcExceptionTranslator != null) {
throw this.jdbcExceptionTranslator.translate("SessionSynchronization", null, ex.getSQLException());
}
else {
throw new HibernateJdbcException(ex);
}
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}
}
public void beforeCompletion() {
if (this.jtaTransaction != null) {
// Typically in case of a suspended JTA transaction:
// Remove the Session for the current JTA transaction, but keep the holder.
Session session = this.sessionHolder.removeSession(this.jtaTransaction);
if (session != null) {
if (this.sessionHolder.isEmpty()) {
// No Sessions for JTA transactions bound anymore -> could remove it.
if (TransactionSynchronizationManager.hasResource(this.sessionFactory)) {
// Explicit check necessary because of remote transaction propagation:
// The synchronization callbacks will execute in a different thread
// in such a scenario, as they're triggered by a remote server.
// The best we can do is to leave the SessionHolder bound to the
// thread that originally performed the data access. It will be
// reused when a new data access operation starts on that thread.
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
}
// Do not close a pre-bound Session. In that case, we'll find the
// transaction-specific Session the same as the default Session.
if (session != this.sessionHolder.getSession()) {
closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
}
else if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
return;
}
}
// We'll only get here if there was no specific JTA transaction to handle.
if (this.newSession) {
// Default behavior: unbind and close the thread-bound Hibernate Session.
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
if (this.hibernateTransactionCompletion) {
// Close the Hibernate Session here in case of a Hibernate TransactionManagerLookup:
// Hibernate will automatically defer the actual closing to JTA transaction completion.
// Else, the Session will be closed in the afterCompletion method, to provide the
// correct transaction status for releasing the Session's cache locks.
closeSessionOrRegisterDeferredClose(this.sessionHolder.getSession(), this.sessionFactory);
}
}
else if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
this.sessionHolder.getSession().setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
}
public void afterCompletion(int status) {
if (!this.hibernateTransactionCompletion || !this.newSession) {
// No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback.
// Always perform explicit afterTransactionCompletion callback for pre-bound Session,
// even with Hibernate TransactionManagerLookup (which only applies to new Sessions).
Session session = this.sessionHolder.getSession();
// Provide correct transaction status for releasing the Session's cache locks,
// if possible. Else, closing will release all cache locks assuming a rollback.
if (session instanceof SessionImplementor) {
((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED);
}
// Close the Hibernate Session here if necessary
// (closed in beforeCompletion in case of TransactionManagerLookup).
if (this.newSession) {
closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
}
}
if (!this.newSession && status != STATUS_COMMITTED) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
this.sessionHolder.getSession().clear();
}
if (this.sessionHolder.doesNotHoldNonDefaultSession()) {
this.sessionHolder.setSynchronizedWithTransaction(false);
}
}
}
/**
* Callback for resource cleanup at the end of a non-Spring JTA transaction,
* i.e. when plain JTA or EJB CMT is used without Spring's JtaTransactionManager.
*/
private static class JtaSessionSynchronization implements Synchronization {
private final SpringSessionSynchronization springSessionSynchronization;
private final TransactionManager jtaTransactionManager;
private boolean beforeCompletionCalled = false;
private JtaSessionSynchronization(
SpringSessionSynchronization springSessionSynchronization, TransactionManager jtaTransactionManager) {
this.springSessionSynchronization = springSessionSynchronization;
this.jtaTransactionManager = jtaTransactionManager;
}
/**
* JTA beforeCompletion callback: just invoked on commit.
* <p>In case of an exception, the JTA transaction gets set to rollback-only.
* (Synchronization.beforeCompletion is not supposed to throw an exception.)
* @see SpringSessionSynchronization#beforeCommit
*/
public void beforeCompletion() {
try {
this.springSessionSynchronization.beforeCommit(false);
}
catch (Throwable ex) {
logger.error("beforeCommit callback threw exception", ex);
try {
this.jtaTransactionManager.setRollbackOnly();
}
catch (SystemException ex2) {
logger.error("Could not set JTA transaction rollback-only", ex2);
}
}
// Unbind the SessionHolder from the thread early, to avoid issues
// with strict JTA implementations that issue warnings when doing JDBC
// operations after transaction completion (e.g. Connection.getWarnings).
this.beforeCompletionCalled = true;
this.springSessionSynchronization.beforeCompletion();
}
/**
* JTA afterCompletion callback: invoked after commit/rollback.
* <p>Needs to invoke SpringSessionSynchronization's beforeCompletion
* at this late stage, as there's no corresponding callback with JTA.
* @see SpringSessionSynchronization#beforeCompletion
* @see SpringSessionSynchronization#afterCompletion
*/
public void afterCompletion(int status) {
if (!this.beforeCompletionCalled) {
// beforeCompletion not called before (probably because of JTA rollback).
// Unbind the SessionHolder from the thread here.
this.springSessionSynchronization.beforeCompletion();
}
// Reset the synchronizedWithTransaction flag,
// and clear the Hibernate Session after a rollback (if necessary).
switch (status) {
case Status.STATUS_COMMITTED:
this.springSessionSynchronization.afterCompletion(TransactionSynchronization.STATUS_COMMITTED);
break;
case Status.STATUS_ROLLEDBACK:
this.springSessionSynchronization.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
break;
default:
this.springSessionSynchronization.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -