Sommario Un genitore può avere molti figli. Come si scrive un servizio tale che, se dopo aver aggiunto un genitore si verifica un errore durante l'aggiunta di un figlio, viene eseguito il rollback dell'intera transazione. Ad esempio, aggiungi genitore p1, aggiungi con successo child c1, quindi quando si aggiunge child c2 si verifica un errore, entrambi i p1 e c1 dovrebbero essere ripristinati.Come eseguire le transazioni in Grails
problema dettagliato
Nel codice seguente, v'è un vincolo univoco sulla proprietà nome del bambino. Pertanto, se si tenta di aggiungere lo stesso nome due volte con un genitore diverso, il record figlio non deve essere aggiunto e il record padre deve essere ripristinato.
Il mio problema è che il record padre non viene ripristinato.
Sto usando MySQL con InnoDB con Grails 1.2-M2 e Tomcat 6.018.
Data Source
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
dataSource {
configClass = GrailsAnnotationConfiguration.class
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
dialect = org.hibernate.dialect.MySQLInnoDBDialect
zeroDateTimeBehavior="convertToNull" //Java can't convert ''0000-00-00 00:00:00' to TIMESTAMP
username = "root"
password = "12345"
loggingSql=false
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/transtest?zeroDateTimeBehavior=convertToNull"
}
}
}
Ho le seguenti classi di dominio semplice:
Parent:
class Parent {
static hasMany = [ children : Child ]
String name
static constraints = {
name(blank:false,unique:true)
}
}
Bambino
class Child {
static belongsTo = Parent
String name
Parent parent
static constraints = {
name(blank:false,unique:true)
}
}
semplice inserimento dati GSP
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sample title</title>
</head>
<body>
<h1>Add A Record</h1>
<g:form action="add" name="doAdd">
<table>
<tr>
<td>
Parent Name
</td>
<td>
Child Name
</td>
</tr>
<tr>
<td>
<g:textField name="parentName" />
</td>
<td>
<g:textField name="childName" />
</td>
</tr>
<tr><td><g:submitButton name="update" value="Update" /></td></tr>
</table>
</g:form>
</body>
</html>
controller
class AddrecordController {
def addRecordsService
def index = {
redirect action:"show", params:params
}
def add = {
println "do add"
addRecordsService.addAll(params)
redirect action:"show", params:params
}
def show = {}
}
Servizio
class AddRecordsService {
// boolean transactional = true //shouldn't this be all I need?
static transactional = true // this should work but still doesn't nor does it work if the line is left out completely
def addAll(params) {
println "add all"
println params
def Parent theParent = addParent(params.parentName)
def Child theChild = addChild(params.childName,theParent)
println theParent
println theChild
}
def addParent(pName) {
println "add parent: ${pName}"
def theParent = new Parent(name:pName)
theParent.save()
return theParent
}
def addChild(cName,Parent theParent) {
println "add child: ${cName}"
def theChild = new Child(name:cName,parent:theParent)
theChild.save()
return theChild
}
}
Grazie per aver aggiunto quei dettagli importanti. –
> È inoltre necessario assicurarsi che venga generata una RuntimeException all'interno del servizio > affinché la transazione venga automaticamente ripristinata > indietro. Questo era il mio problema! Sembra che i graal dovrebbero farlo per convenzione. –
Penso che ci sia un'opzione di configurazione in arrivo la versione 1.2 per fare save() lanciare eccezioni invece di restituire null se la validazione fallisce – leebutts