001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate4; 018 019import org.hibernate.FlushMode; 020import org.hibernate.HibernateException; 021import org.hibernate.Session; 022import org.hibernate.SessionFactory; 023 024import org.springframework.core.Ordered; 025import org.springframework.dao.DataAccessException; 026import org.springframework.transaction.support.TransactionSynchronization; 027import org.springframework.transaction.support.TransactionSynchronizationManager; 028 029/** 030 * Callback for resource cleanup at the end of a Spring-managed transaction 031 * for a pre-bound Hibernate Session. 032 * 033 * @author Juergen Hoeller 034 * @since 3.1 035 */ 036public class SpringSessionSynchronization implements TransactionSynchronization, Ordered { 037 038 private final SessionHolder sessionHolder; 039 040 private final SessionFactory sessionFactory; 041 042 private final boolean newSession; 043 044 private boolean holderActive = true; 045 046 047 public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) { 048 this(sessionHolder, sessionFactory, false); 049 } 050 051 public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) { 052 this.sessionHolder = sessionHolder; 053 this.sessionFactory = sessionFactory; 054 this.newSession = newSession; 055 } 056 057 058 private Session getCurrentSession() { 059 return this.sessionHolder.getSession(); 060 } 061 062 063 @Override 064 public int getOrder() { 065 return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER; 066 } 067 068 @Override 069 public void suspend() { 070 if (this.holderActive) { 071 TransactionSynchronizationManager.unbindResource(this.sessionFactory); 072 // Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss. 073 getCurrentSession().disconnect(); 074 } 075 } 076 077 @Override 078 public void resume() { 079 if (this.holderActive) { 080 TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder); 081 } 082 } 083 084 @Override 085 public void flush() { 086 try { 087 SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request"); 088 getCurrentSession().flush(); 089 } 090 catch (HibernateException ex) { 091 throw SessionFactoryUtils.convertHibernateAccessException(ex); 092 } 093 } 094 095 @Override 096 public void beforeCommit(boolean readOnly) throws DataAccessException { 097 if (!readOnly) { 098 Session session = getCurrentSession(); 099 // Read-write transaction -> flush the Hibernate Session. 100 // Further check: only flush when not FlushMode.MANUAL. 101 if (!session.getFlushMode().equals(FlushMode.MANUAL)) { 102 try { 103 SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization"); 104 session.flush(); 105 } 106 catch (HibernateException ex) { 107 throw SessionFactoryUtils.convertHibernateAccessException(ex); 108 } 109 } 110 } 111 } 112 113 @Override 114 public void beforeCompletion() { 115 try { 116 Session session = this.sessionHolder.getSession(); 117 if (this.sessionHolder.getPreviousFlushMode() != null) { 118 // In case of pre-bound Session, restore previous flush mode. 119 session.setFlushMode(this.sessionHolder.getPreviousFlushMode()); 120 } 121 // Eagerly disconnect the Session here, to make release mode "on_close" work nicely. 122 session.disconnect(); 123 } 124 finally { 125 // Unbind at this point if it's a new Session... 126 if (this.newSession) { 127 TransactionSynchronizationManager.unbindResource(this.sessionFactory); 128 this.holderActive = false; 129 } 130 } 131 } 132 133 @Override 134 public void afterCommit() { 135 } 136 137 @Override 138 public void afterCompletion(int status) { 139 try { 140 if (status != STATUS_COMMITTED) { 141 // Clear all pending inserts/updates/deletes in the Session. 142 // Necessary for pre-bound Sessions, to avoid inconsistent state. 143 this.sessionHolder.getSession().clear(); 144 } 145 } 146 finally { 147 this.sessionHolder.setSynchronizedWithTransaction(false); 148 // Call close() at this point if it's a new Session... 149 if (this.newSession) { 150 SessionFactoryUtils.closeSession(this.sessionHolder.getSession()); 151 } 152 } 153 } 154 155}