Unwrap JPA PersistenceException on flush failure (for Hibernate 5.2)

Issue: SPR-14457
This commit is contained in:
Juergen Hoeller 2016-07-15 15:40:38 +02:00
parent 1d39d762f0
commit 29f980ec72
5 changed files with 62 additions and 24 deletions

View File

@ -24,6 +24,7 @@ import java.lang.reflect.Proxy;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.persistence.PersistenceException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -357,6 +358,12 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
catch (HibernateException ex) { catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex); throw SessionFactoryUtils.convertHibernateAccessException(ex);
} }
catch (PersistenceException ex) {
if (ex.getCause() instanceof HibernateException) {
throw SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex.getCause());
}
throw ex;
}
catch (RuntimeException ex) { catch (RuntimeException ex) {
// Callback code threw application exception... // Callback code threw application exception...
throw ex; throw ex;

View File

@ -18,6 +18,7 @@ package org.springframework.orm.hibernate5;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
import javax.persistence.PersistenceException;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
@ -588,6 +589,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
// assumably failed to flush changes to database // assumably failed to flush changes to database
throw convertHibernateAccessException(ex); throw convertHibernateAccessException(ex);
} }
catch (PersistenceException ex) {
if (ex.getCause() instanceof HibernateException) {
throw convertHibernateAccessException((HibernateException) ex.getCause());
}
throw ex;
}
} }
@Override @Override
@ -607,6 +614,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
// Shouldn't really happen, as a rollback doesn't cause a flush. // Shouldn't really happen, as a rollback doesn't cause a flush.
throw convertHibernateAccessException(ex); throw convertHibernateAccessException(ex);
} }
catch (PersistenceException ex) {
if (ex.getCause() instanceof HibernateException) {
throw convertHibernateAccessException((HibernateException) ex.getCause());
}
throw ex;
}
finally { finally {
if (!txObject.isNewSession() && !this.hibernateManagedSession) { if (!txObject.isNewSession() && !this.hibernateManagedSession) {
// Clear all pending inserts/updates/deletes in the Session. // Clear all pending inserts/updates/deletes in the Session.
@ -825,6 +838,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
catch (HibernateException ex) { catch (HibernateException ex) {
throw convertHibernateAccessException(ex); throw convertHibernateAccessException(ex);
} }
catch (PersistenceException ex) {
if (ex.getCause() instanceof HibernateException) {
throw convertHibernateAccessException((HibernateException) ex.getCause());
}
throw ex;
}
} }
} }

View File

@ -18,6 +18,7 @@ package org.springframework.orm.hibernate5;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -123,6 +124,37 @@ public abstract class SessionFactoryUtils {
return (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session); return (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session);
} }
/**
* Trigger a flush on the given Hibernate Session, converting regular
* {@link HibernateException} instances as well as Hibernate 5.2's
* {@link PersistenceException} wrappers accordingly.
* @param session the Hibernate Session to flush
* @param synch whether this flush is triggered by transaction synchronization
* @throws DataAccessException
* @since 4.3.2
*/
static void flush(Session session, boolean synch) throws DataAccessException {
if (synch) {
logger.debug("Flushing Hibernate Session on transaction synchronization");
}
else {
logger.debug("Flushing Hibernate Session on explicit request");
}
try {
session.flush();
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (PersistenceException ex) {
if (ex.getCause() instanceof HibernateException) {
throw convertHibernateAccessException((HibernateException) ex.getCause());
}
throw ex;
}
}
/** /**
* Perform actual closing of the Hibernate Session, * Perform actual closing of the Hibernate Session,
* catching and logging any cleanup exceptions thrown. * catching and logging any cleanup exceptions thrown.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,6 @@
package org.springframework.orm.hibernate5; package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationAdapter; import org.springframework.transaction.support.TransactionSynchronizationAdapter;
@ -40,13 +39,7 @@ public class SpringFlushSynchronization extends TransactionSynchronizationAdapte
@Override @Override
public void flush() { public void flush() {
try { SessionFactoryUtils.flush(this.session, false);
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
this.session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
} }

View File

@ -17,7 +17,6 @@
package org.springframework.orm.hibernate5; package org.springframework.orm.hibernate5;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
@ -83,13 +82,7 @@ public class SpringSessionSynchronization implements TransactionSynchronization,
@Override @Override
public void flush() { public void flush() {
try { SessionFactoryUtils.flush(getCurrentSession(), false);
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
getCurrentSession().flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
} }
@Override @Override
@ -99,13 +92,7 @@ public class SpringSessionSynchronization implements TransactionSynchronization,
// Read-write transaction -> flush the Hibernate Session. // Read-write transaction -> flush the Hibernate Session.
// Further check: only flush when not FlushMode.MANUAL. // Further check: only flush when not FlushMode.MANUAL.
if (!FlushMode.MANUAL.equals(SessionFactoryUtils.getFlushMode(session))) { if (!FlushMode.MANUAL.equals(SessionFactoryUtils.getFlushMode(session))) {
try { SessionFactoryUtils.flush(getCurrentSession(), true);
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
} }
} }
} }