I try to execute raw SQL in Grails with this code:
class PlainSqlService {
def dataSource // the Spring-Bean "dataSource" is auto-injected
def newNum = {
def sql = new Sql(dataSource) // Create a new instance of groovy.sql.Sql with the DB of the Grails app
def q = "SELECT a.xaction_id, a.xdin FROM actions a WHERE a.is_approved = 0"
def result = sql.rows(q) // Perform the query
return result
}
}
But I get this exception at runtime.
sql object is not null!
How can I debug it?
2011-02-13 15:55:27,507 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /moderator/login/index
Stacktrace follows:
java.lang.NullPointerException
at moderator.PlainSqlService$_closure1.doCall(PlainSqlService.groovy:17)
at moderator.PlainSqlService$_closure1.doCall(PlainSqlService.groovy)
at moderator.LoginController$_closure1.doCall(LoginController.groovy:29)
at moderator.LoginController$_closure1.doCall(LoginController.groovy)
at java.lang.Thread.run(Thread.java:662)
It's hard to tell what's going on from the limited code you're providing, but there are some things to check. Is the service injected into the controller with a class-scope field "def plainSqlService" like you have here for the dataSource, or are you calling new PlainSqlService()? If you're creating a new instance then the dataSource bean won't be injected and the groovy.sql.Sql constructor won't fail, but queries will.
One thing to try is grails clean - whenever something like this that should work doesn't, a full recompile often helps.
One important but unrelated point - you should never use Closures in services. Controllers and taglibs require that actions and tags be implemented with a Closure, but a Service is just a Spring bean defined in Groovy. Spring knows nothing about Closures and since they're just a field that Groovy executes as if it were a method, any proxying that you're expecting from Spring (in particular transactional behavior, but also security and other features) will not happen since Spring only looks for methods.
So newNum should be declared as:
def newNum() {
...
}
Related
What is proper way to get DB connection in Grails 3?
For grails 2 following code has works:
((SessionImpl) sessionFactory.getCurrentSession()).connection() // sessionFactory initialized in bootstrap
But after migration to Grails 3 sometimes I see exceptions in the log:
java.sql.SQLException: Operation not allowed after ResultSet closed at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) at
com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:743) at
com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1037) at
com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2757) at
com.mchange.v2.c3p0.impl.NewProxyResultSet.getLong(NewProxyResultSet.java:424)
at java_sql_ResultSet$getLong$3.call(Unknown Source)
It happens for 0,01% of requests
Grails 3.2.11
Gorm 6.0.12
I guess it depends on where you need it, but you can inject a DataSource into a service.
javax.sql.DataSource dataSource
Then you can just use
dataSource.getConnection()
Also be aware of the changes to flush mode in GORM 6 (http://gorm.grails.org/6.0.x/hibernate/manual/ section 1.2.1). If an upstream save/commit is failing, your result set could be incidentally closed and trigger an error that looks like this while not really have anything to do with this particular line of code at all. I'd (very temporarily) set back to the old flush mode and see if the problem goes away, before tracking much more down!
From grails docs, you can get the actual dataSource bean. From that you can access the connection or use it to query your db
import groovy.sql.Sql
def dataSource
println "connection: ${dataSource.connection}"
Sql sql = new Sql(dataSource)
sql.eachRow("SELECT * FROM note") { row ->
println "row: ${row}"
}
Use 'dataSourceUnproxied' to avoid Hibernate transaction and session issues:
def dataSourceUnproxied
For executing queries inside current hibernate transactions following construction can be used:
sessionFactory.currentSession.doWork {connection ->
new Sql(connection).execute(query, params)
}
I am using Grails 2.2.1, and I have a custom dataSource injected into the service so that I can execute some SQL queries.
Upon first execution, there is a dataSource, but on each subsequent call, the reference to the dataSource has become null.
class ReportService {
def dataSource_myds
Object[] reportRecords(int a) {
String query = "SELECT ..."
Object[] resultSet;
Sql sql = new Sql(dataSource_myds)
// ^ Here the NullPointerException is thrown
// But it always works at the first execution
sql.eachRow(query, [a]) {
...
resultSet += result
}
return resultSet
}
}
class ReportController {
ReportService reportService
def report = {
...
Object[] resultSet1 = reportService.reportRecords(1)
...
Object[] resultSet2 = reportService.reportRecords(2)
// ^ java.lang.NullPointerException : Must specify a non-null Connection
...
}
}
Has anyone ever seen this before, and if so, how can I avoid this?
Here is my DataSource.groovy
environments {
development {
dataSource_myds {
url = "jdbc:oracle:thin:#..."
driverClassName = "oracle.jdbc.driver.OracleDriver"
username = "..."
password = "..."
}
}
}
Try, to use resources.groovy way as well. This will also give you option for environment basis datasource.
Explained well on the link given below:
Grails 2 multiple dynamic datasources in services
Thanks
Solved avoiding 2 subsequent calls to the service. It seems the framework nulls the service connection after the first call from the controller.
James Kleeh's comment solved it for me - grails clean and then restart the app.
I had a similar issue and I got it fixed. Firstly, make sure your Service class is in the grails-app/services folder. Secondly, you need to make sure you get the object of the service class using the injection mechanism and not by using the constructor. I had my service class in the right folder but I was trying to create the instance of the service class as MyService.instance in my controller and having the issue of null dataSource/connection. Then I tried def myService in my controller instead of MyService.instance and it worked. Hope this helps. Thanks
Updated post:
In a Controller if I do this:
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
//a singleton service with nothing to do with obj
testService.dostuff()
/*
"obj" gets persisted to the database right here
even before the next println
*/
println "done"
Can anyone please explain me why is this happening with Grails 1.3.7 and not with Grails 2? What is the reason?
I know I could use discard() and basically restructure the code but I am interested in what and why is happening behind the scenes. Thanks!
Old post:
I have a test Grails application. I have one domain class test.Test:
package test
class Test {
String name
static constraints = {}
}
Also I have a service test.TestService:
package test
class TestService {
static scope = "singleton"
static transactional = true
def dostuff() {
println "test service was called"
}
}
And one controller test.TestController:
package test
class TestController {
def testService
def index = {
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
testService.dostuff()
println "done"
}
}
So what I do:
Create a domain object
Change one of it's properties
Call a singleton service method
What I would expect:
Nothing gets persisted to the db unless I call obj.save()
What happens instead:
Right after the service call Grails will do an update query to the database.
I have tried the following configuration from this url: http://grails.1312388.n4.nabble.com/Turn-off-autosave-in-gorm-td1378113.html
hibernate.flush.mode="manual"
But it didn't help.
I have tested it with Grails 1.3.7, Grails 2.0.3 does not have this issue.
Could anyone please give me a bit more information on what is exactly going on? It seems like the current session has to be terminated because of the service call and because the object is dirty it is getting automatically persisted to the database after the service call. What I don't understand that even with the manual flush mode configuration in Hibernate does not help.
Thanks in advance!
I'm not sure what about that thread you linked to made you think it would work. They all said it wouldn't work, the ticket created has been closed as won't fix. The solution here is to use discard() as the thread stated.
I'm trying to call a method on a grails service from a controller, but it looks like execution is just skipping the method call.
I've tried debugging the application with a breakpoint inside the method but it is never hit.
My service (generated with grails create-service) is:
class FormatterService {
static transactional = false
def formatList (List<Host>, String fmt) {
OutputObject somePOGO = new OutputObject();
(snip)
return somePOGO
}
}
Then on my controller I have:
class HostController {
def formatterService
def getHostsByLabels = {
(snip)
OutputObject o = formatterService.formatList(someHosts,params.format)
(snip)
}
}
When the formatterService.formatList method should be called in the controller, execution simply skips to the next line, no output is printed to the console and breakpoints within the method are not hit. The OutputObject o reference is null afterward.
What is wrong here? It could be a really basic mistake from my part, but I just can't put my finger on it...
To Me it seems a MetaProgramming Disaster..
Well there are 3 Tests to Debug:
_1) first try to do
println formatterService
println formatterService.getClass()
just to check if its injected bean is the desired one, some plugins sometimes inject beans which overrides the default.
_2) Make sure that the method with a name "formatList" is not injected in your services through metaprogramming by any plugin or core code.
How to test this is simple: Just change the name of the method to some Unrealistic One, ex: "formatListabcdewdw" and then call that one. If it works then its method overriden issue.
and if you are more enthusiastic you can see the metaMethods by
println formatterService.metaClass.methods
_3) just try to do "params.format as String" as the last argument in the method call.\
.
Hope any of these helps, please Do let me know of the findings, i am curious to know.. :)
I found the issue. It has to do with the method signature.
Printing out the thrown exception's message, it says:
No signature of method: hms.FormatterService.formatList() is applicable for argument types: (java.util.TreeSet, java.lang.String) values: (...)
Possible solutions: formatList(java.util.List, java.lang.String)
So, a rookie mistake (wanting to pass a TreeSet for a List) aided by weak typing in Groovy... :P
I've changed the method signature to
def formatList ( items, String fmt) {
and call it as
def activeHosts = ...
OutputObject o = formatterService.formatList(activeHosts, params.format as String)
and now it works.
I am trying to do a safe insert using GORM for Mongo's low-level API.
I have reproduced the problem in a clean Grails project like follows:
Create a new Grails project
Uninstall the Hibernate plugin
Install the GORM for Mongo plugin
Create a controller with the following action
import com.mongodb.*
class TestController {
def mongo
def index = {
def database = mongo.getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
}
When firing the action, the following exception is thrown:
2011-07-27 12:53:03,161 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /WriteConcern.SAFE-test/test/index
Stacktrace follows:
groovy.lang.MissingPropertyException: No such property: value for class: com.mongodb.WriteConcern
at com.gmongo.internal.Patcher$__converAllCharSeqToString_closure2.doCall(Patcher.groovy:81)
at com.gmongo.internal.Patcher._converAllCharSeqToString(Patcher.groovy:80)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher._convert(Patcher.groovy:69)
at com.gmongo.internal.Patcher$_convert.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$__patchInternal_closure1.doCall(Patcher.groovy:31)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy:17)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy)
at java.lang.Thread.run(Thread.java:680)
If I change the action to use the Mongo Java API as follows:
def index = {
def database = new Mongo().getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
Now it works and the document is persisted to the Mongo database as expected.
My question is this: Is this a bug with the GMongo wrapper, or then how should safe writes be done using the low level API?
This appears due to the GMongo library and how it patches the DBCollection object to handle passing of Map objects to the insert method and converts them. It assumes that all of the arguments of the insert method are Map objects and will then try to get the value property from the Map.Entry.
Looking at the source of Patcher.groovy from GMongo library you'll see the function _convert() that attempts to do this. It looks like a fork of the Github project with type check on the argument (either to see if it's a WriteConcern or to check if it's actually a Map before passing to the _converAllCharSeqToString) is necessary.
EDIT:
I created a pull request on Github for the appropriate code change, but as with all things Groovy, patching the class can also help. You can "patch" the WriteConcern class in your BootStrap.groovy to have a getValue method and that will allow you to pass the parameter in:
def init = { servletContext ->
com.mongodb.WriteConcern.metaClass.getValue = { null }
}