001/* 002 * Copyright 2002-2016 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.hibernate5; 018 019import org.hibernate.FlushMode; 020import org.hibernate.Session; 021import org.hibernate.SessionFactory; 022 023import org.springframework.core.Ordered; 024import org.springframework.dao.DataAccessException; 025import org.springframework.transaction.support.TransactionSynchronization; 026import org.springframework.transaction.support.TransactionSynchronizationManager; 027 028/** 029 * Callback for resource cleanup at the end of a Spring-managed transaction 030 * for a pre-bound Hibernate Session. 031 * 032 * @author Juergen Hoeller 033 * @since 4.2 034 */ 035public class SpringSessionSynchronization implements TransactionSynchronization, Ordered { 036 037 private final SessionHolder sessionHolder; 038 039 private final SessionFactory sessionFactory; 040 041 private final boolean newSession; 042 043 private boolean holderActive = true; 044 045 046 public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) { 047 this(sessionHolder, sessionFactory, false); 048 } 049 050 public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) { 051 this.sessionHolder = sessionHolder; 052 this.sessionFactory = sessionFactory; 053 this.newSession = newSession; 054 } 055 056 057 private Session getCurrentSession() { 058 return this.sessionHolder.getSession(); 059 } 060 061 062 @Override 063 public int getOrder() { 064 return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER; 065 } 066 067 @Override 068 public void suspend() { 069 if (this.holderActive) { 070 TransactionSynchronizationManager.unbindResource(this.sessionFactory); 071 // Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss. 072 getCurrentSession().disconnect(); 073 } 074 } 075 076 @Override 077 public void resume() { 078 if (this.holderActive) { 079 TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder); 080 } 081 } 082 083 @Override 084 public void flush() { 085 SessionFactoryUtils.flush(getCurrentSession(), false); 086 } 087 088 @Override 089 public void beforeCommit(boolean readOnly) throws DataAccessException { 090 if (!readOnly) { 091 Session session = getCurrentSession(); 092 // Read-write transaction -> flush the Hibernate Session. 093 // Further check: only flush when not FlushMode.MANUAL. 094 if (!FlushMode.MANUAL.equals(SessionFactoryUtils.getFlushMode(session))) { 095 SessionFactoryUtils.flush(getCurrentSession(), true); 096 } 097 } 098 } 099 100 @Override 101 @SuppressWarnings("deprecation") 102 public void beforeCompletion() { 103 try { 104 Session session = this.sessionHolder.getSession(); 105 if (this.sessionHolder.getPreviousFlushMode() != null) { 106 // In case of pre-bound Session, restore previous flush mode. 107 session.setFlushMode(this.sessionHolder.getPreviousFlushMode()); 108 } 109 // Eagerly disconnect the Session here, to make release mode "on_close" work nicely. 110 session.disconnect(); 111 } 112 finally { 113 // Unbind at this point if it's a new Session... 114 if (this.newSession) { 115 TransactionSynchronizationManager.unbindResource(this.sessionFactory); 116 this.holderActive = false; 117 } 118 } 119 } 120 121 @Override 122 public void afterCommit() { 123 } 124 125 @Override 126 public void afterCompletion(int status) { 127 try { 128 if (status != STATUS_COMMITTED) { 129 // Clear all pending inserts/updates/deletes in the Session. 130 // Necessary for pre-bound Sessions, to avoid inconsistent state. 131 this.sessionHolder.getSession().clear(); 132 } 133 } 134 finally { 135 this.sessionHolder.setSynchronizedWithTransaction(false); 136 // Call close() at this point if it's a new Session... 137 if (this.newSession) { 138 SessionFactoryUtils.closeSession(this.sessionHolder.getSession()); 139 } 140 } 141 } 142 143}