Skip to content

Commit a6b1777

Browse files
committed
Merged fix for GRAILS-5277 "Grails still flushes the session after an action
completes when an exception is caught and not rethrown" Also fixes GRAILS-4776
1 parent 9735222 commit a6b1777

File tree

3 files changed

+133
-9
lines changed

3 files changed

+133
-9
lines changed

src/groovy/org/codehaus/groovy/grails/plugins/orm/hibernate/HibernatePluginSupport.groovy

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ import org.hibernate.proxy.LazyInitializer
5555
import org.apache.commons.beanutils.PropertyUtils
5656
import org.hibernate.Hibernate
5757
import org.springframework.validation.Validator
58+
import org.springframework.dao.DataAccessException
59+
import org.hibernate.FlushMode
60+
import org.codehaus.groovy.grails.commons.ConfigurationHolder
5861

5962

6063
/**
@@ -694,15 +697,29 @@ Try using Grails' default cache provider: 'org.hibernate.cache.OSCacheProvider'"
694697

695698
metaClass.delete = {->
696699
def obj = delegate
697-
template.execute({Session session ->
698-
session.delete obj
699-
} as HibernateCallback)
700+
try {
701+
template.execute({Session session ->
702+
session.delete obj
703+
if(this.shouldFlush()) {
704+
session.flush()
705+
}
706+
} as HibernateCallback)
707+
}
708+
catch (DataAccessException e) {
709+
handleDataAccessException(template, e)
710+
}
700711
}
701712
metaClass.delete = { Map args ->
702713
def obj = delegate
703714
template.delete obj
704-
if(args?.flush)
705-
template.flush()
715+
if(shouldFlush(args)) {
716+
try {
717+
template.flush()
718+
}
719+
catch (DataAccessException e) {
720+
handleDataAccessException(template, e)
721+
}
722+
}
706723
}
707724
metaClass.refresh = {-> template.refresh(delegate); delegate }
708725
metaClass.discard = {->template.evict(delegate); delegate }
@@ -743,6 +760,32 @@ Try using Grails' default cache provider: 'org.hibernate.cache.OSCacheProvider'"
743760
}
744761
}
745762

763+
static shouldFlush(Map map = [:]) {
764+
def shouldFlush
765+
766+
if(map?.containsKey('flush')) {
767+
shouldFlush = Boolean.TRUE == map.flush
768+
} else {
769+
def config = ConfigurationHolder.flatConfig
770+
shouldFlush = Boolean.TRUE == config?.get('grails.gorm.autoFlush')
771+
}
772+
return shouldFlush
773+
}
774+
/**
775+
* Session should no longer be flushed after a data access exception occurs (such a constriant violation)
776+
*/
777+
static void handleDataAccessException(HibernateTemplate template, DataAccessException e) {
778+
try {
779+
template.execute({Session session ->
780+
session.setFlushMode(FlushMode.MANUAL)
781+
} as HibernateCallback)
782+
}
783+
finally {
784+
throw e
785+
}
786+
}
787+
788+
746789
private static convertToType(value, targetType) {
747790
SimpleTypeConverter typeConverter = new SimpleTypeConverter()
748791

src/persistence/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hibernate.HibernateException;
2020
import org.hibernate.Session;
2121
import org.hibernate.SessionFactory;
22+
import org.springframework.dao.DataAccessException;
2223
import org.springframework.orm.hibernate3.HibernateCallback;
2324
import org.springframework.orm.hibernate3.HibernateTemplate;
2425

@@ -52,8 +53,16 @@ protected Object performSave(final Object target, final boolean flush) {
5253
return ht.execute(new HibernateCallback() {
5354
public Object doInHibernate(Session session) throws HibernateException, SQLException {
5455
session.saveOrUpdate(target);
55-
if(flush)
56-
getHibernateTemplate().flush();
56+
if(flush) {
57+
try {
58+
getHibernateTemplate().flush();
59+
}
60+
catch (DataAccessException e) {
61+
// session should not be flushed again after a data acccess exception!
62+
getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_NEVER);
63+
throw e;
64+
}
65+
}
5766
return target;
5867
}
5968
});
@@ -64,8 +73,17 @@ protected Object performInsert(final Object target, final boolean shouldFlush) {
6473
return ht.execute(new HibernateCallback() {
6574
public Object doInHibernate(Session session) throws HibernateException, SQLException {
6675
session.save(target);
67-
if(shouldFlush)
68-
getHibernateTemplate().flush();
76+
if(shouldFlush) {
77+
78+
try {
79+
getHibernateTemplate().flush();
80+
}
81+
catch (DataAccessException e) {
82+
// session should not be flushed again after a data acccess exception!
83+
getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_NEVER);
84+
throw e;
85+
}
86+
}
6987
return target;
7088
}
7189
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.codehaus.groovy.grails.orm.hibernate
2+
3+
import org.hibernate.FlushMode
4+
import org.springframework.dao.DataAccessException
5+
6+
/**
7+
* @author Graeme Rocher
8+
* @since 1.1
9+
*/
10+
11+
public class DontFlushAfterDataAccessExceptionTests extends AbstractGrailsHibernateTests{
12+
13+
protected void onSetUp() {
14+
gcl.parseClass('''
15+
import grails.persistence.*
16+
17+
@Entity
18+
class DontFlushAfterDataAccessExceptionAuthor {
19+
20+
static hasMany = [books: DontFlushAfterDataAccessExceptionBook]
21+
22+
String name
23+
24+
static mapping = {
25+
columns {
26+
books cascade: 'save-update'
27+
}
28+
}
29+
}
30+
31+
@Entity
32+
class DontFlushAfterDataAccessExceptionBook {
33+
34+
static belongsTo = [author: DontFlushAfterDataAccessExceptionAuthor]
35+
36+
String name
37+
}
38+
''')
39+
}
40+
41+
42+
void testDontFlushAfterDataAccessException() {
43+
def Author = ga.getDomainClass("DontFlushAfterDataAccessExceptionAuthor").clazz
44+
45+
session.setFlushMode(FlushMode.AUTO)
46+
assert Author.newInstance(name:"bob")
47+
.addToBooks(name:"my story")
48+
.save(flush:true)
49+
50+
assert session.getFlushMode() == FlushMode.AUTO : "should be a flush mode of auto"
51+
52+
session.clear()
53+
54+
def author = Author.get(1)
55+
56+
shouldFail(DataAccessException) {
57+
author.delete(flush:true)
58+
}
59+
60+
assert session.getFlushMode() == FlushMode.MANUAL : "should be a flush mode of manual after exception!"
61+
62+
}
63+
}

0 commit comments

Comments
 (0)