I am running into an odd problem with my application. The app was developed and tested with HSQLDB, and worked fine. When I built a WAR file & deployed it on a server, one particular bit of code (crucial to the app, of course) failed.
The code
def assessment = Assessment.findByPostingAndAssessor(posting, judge)
The error:
Caused by: java.sql.SQLException: No value specified for parameter 2
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2214)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2138)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1853)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2228)
I looked around on Google, and found this rather old blog post
http://blog.flurdy.com/2008/09/no-value-specified-for-parameter-when.html
which alludes to this problem and says it was caused by a bad version of hibernate. But that's three years old; I am now using grails 1.3.7 with hibernate plugin 1.3.7. Furthermore, I couldn't figure out where to find the maven specifications that the blog post describes so that I could edit them.
And none of my other apps is exhibiting this problem. I tried using the finder as above, and tried manually to create a criteria query, but both produced the same error. Neither value passed to the method is null.
I really really really need this to work ASAP, so I am wondering if anyone has any ideas of what to try next.
For the record, you can see the full stack trace here: http://grails.1312388.n4.nabble.com/file/n3787337/hibernate-exception.txt
Thanks,
Gene
EDITED 9/2/2011:
Here is the hibernate/SQL log that lead up to the error:
11/09/02 17:56:15 DEBUG hibernate.SQL: select this_.id as id22_0_, this_.version as version22_0_, this_.assessor_id as assessor3_22_0_, this_.comment as comment22_0_, this_.date_created as date5_22_0_, this_.last_updated as last6_22_0_, this_.value as value22_0_ from assessment this_ where this_.id=? and this_.assessor_id=?
11/09/02 17:56:15 TRACE type.LongType: binding '2' to parameter: 1
11/09/02 17:56:15 ERROR util.JDBCExceptionReporter: No value specified for parameter 2
11/09/02 17:56:15 ERROR docusearch.UiController: Could not save assessment
org.hibernate.exception.SQLGrammarException: could not execute query
The stack trace follows.
EDITED 9/3/2011:
Here are the classes involved:
package com.fxpal.docusearch
import com.sun.org.apache.xalan.internal.xsltc.cmdline.getopt.IllegalArgumentException;
class Assessment {
Posting posting
AssessmentValue value
Searcher assessor
static belongsTo = [posting: Posting, assessor: Searcher]
static indexes = {
posting()
assessor()
}
static constraints = {
posting(nullable: false)
value()
assessor(nullable: true)
}
static judge(Posting posting, Searcher judge, String value) {
if (judge == null)
throw new IllegalArgumentException("missing judge value");
// error occurs here
def assessment = Assessment.findByPostingAndAssessor(posting, judge)
def judgment = AssessmentValue.fromString(value)
if (judgment && !assessment)
assessment = new Assessment( posting: posting, assessor: judge )
if (!judgment && assessment) {
assessment.delete(flush:true)
assessment = null
}
else {
assessment.value = judgment
assessment.save(flush:true)
}
return assessment
}
}
package com.fxpal.docusearch
class Posting {
Document document
int rank
double score
Assessment assessment
static mapping = {
cache true
}
static belongsTo = [document: Document, query: Query]
static constraints = {
document(nullable: false)
rank()
score()
assessment(nullable: true)
}
}
package com.fxpal.docusearch
import com.fxpal.authentication.User
class Searcher Extends User {
String name
String email
String color
static constraints = {
name(blank:false, unique: true, maxSize:255)
email(nullable: true)
color(blank: false)
}
static mapping = {
tablePerHierarchy true
}
public String displayName() {
return name ?: username
}
}
package com.fxpal.authentication
// This is the generic class generated by the Spring Security plugin
class User {
String username
String password = 'n/a'
boolean enabled = true
boolean accountExpired = false
boolean accountLocked = false
boolean passwordExpired = false
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
}
Do you suppose the hierarchical relationship between Searcher
and User
is part of the problem?
Again, I should emphasize that this code works when I run it as a run-app with an in-memory database.
EDITED 9/3/2011:
Here is a test case that illustrates the problem. Runs fine as grails run-app
(in memory) but fails when you use 'grails prod run-app` (with a MySQL db).
http://grails.1312388.n4.nabble.com/file/n3788449/test.zip
EDITED 9/4/2011: I had asked this question on the Grails Nabble group as well, and Daniel Henrique Alves Lima identified a potential problem with the schema of my code. (See his post on Nabble). The problem seems to be that I had coded:
开发者_StackOverflow中文版static belongsTo = [posting: Posting, assessor: Searcher]
in my Assessment
class, which resulted in the behavior described above. When I changed the declaration to
static belongsTo = [assessor: Searcher]
the findBy..()
code worked correctly. I still think there is a hibernate bug lurking in the code (as leaving out parameters is not a good way to report errors :-) ), but at least my program now saves data!
Thanks to everyone who contributed to the solution!
I assume it's because one of posting
or judge
is null. If that's not the case, you could try turning on SQL logging, although I'm not sure if that happens before or after the code that throws the exception.
Adding this to the log4j section in Config.groovy will log the SQL:
debug 'org.hibernate.SQL'
and this will log the bind parameters:
trace 'org.hibernate.type'
Edit 9/4: I spent some time in the debugger with your test code and it's due to the one-to-one mapping between Posting
and Assessment
. A one-to-one uses the same value for the primary key as the foreign key of the owner, so there's logic in the PreparedStatement population code that skips the call to set the value of the 1st arg and doesn't increment the position counter, so the one value that's set is the 2nd arg's value in the 1st slot and nothing in the 2nd. You can see from the log4j output that HSQLDB does the same thing, but it's apparently less strict. Note that HSQLDB only coincidentally works since you only create one instance of each, so they share the same value of the id - if you create some dummy instances of one type first to force a mismatch you'll get the wrong results (but not an exception). My suggestion is to rework it as a one-to-many and if you need to you can add a constraint that limits the size of the collection to at most one, e.g. children(size:0..1)
- see http://grails.org/doc/latest/ref/Constraints/size.html
Have the same error with grails 2.3.11 while trying to find object by another object, that is mandatory field (belongsTO is in place).
精彩评论