Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No value for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy] bound to thread #65

Closed
brischniz opened this issue Sep 26, 2018 · 20 comments

Comments

@brischniz
Copy link

I tried to integrate the grails-melody-plugin-1.73.2 into a Grails-3.3.8 application but with some GORM interactions I got the following stacktrace:

java.lang.IllegalStateException: No value for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy@64e3d4ab] bound to thread [pool-2-thread-1]
	at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:210)
	at org.springframework.orm.hibernate5.HibernateTransactionManager.doCleanupAfterCompletion(HibernateTransactionManager.java:654)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1021)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:815)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:150)
	at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
...
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
	at grails.melody.plugin.MelodyInterceptorEnhancer$_enhance_closure1$_closure2.doCall(MelodyInterceptorEnhancer.groovy:77)
	at sun.reflect.GeneratedMethodAccessor349.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
...

It seems that Graeme Rocher investigated on that issue a while ago: grails/grails-core#10675 (comment)

This is an issue with the melody plugin. It is replacing the data source with another proxy which interferes with the references GORM uses to bind and unbind the session.

@sergiomichels
Copy link
Collaborator

@brischniz Could you provide a sample application with the issue? Probably it's related to #61.

@bassmartin
Copy link
Contributor

I confirm this is happening.

I'll try to investigate.

@joemccall86
Copy link

This issue still occurs in our application running Grails 3.3.9. It would also appear that even disabling the plugin in application.yml still causes this issue. I'm still trying to reproduce this in a sample project but so far no luck.

@bassmartin
Copy link
Contributor

Disabling the plugin will not prevent the issue. The ´expando metaclass’ enabling is done in a static block in the plugin. We might need some help from Grails team since every time we find a fix, anither issue arise.

@joemccall86
Copy link

joemccall86 commented Dec 5, 2018

Were you by any chance successful in creating a sample application? It might be easier to lobby for some help if we can reproduce it reliably.

*Edit: never mind, I was able to reproduce it. Turns out I actually have to include the plugin in build.gradle :-)

@joemccall86
Copy link

Added sample here: https://github.com/joemccall86/melody-sample

@sergiomichels
Copy link
Collaborator

Thanks @joemccall86, I'll take a look at sample code.

@sergiomichels
Copy link
Collaborator

I've created branch 65_no_value_for_key, I see issue even without ExpandoMetaClass.enableGlobally(). In this branch I'm creating a new integration test app so we can improve our regression suite and avoid this issues in future.

@bassmartin
Copy link
Contributor

Thanks Sergio! I just had a new baby so I don’t have much time right now ;-)

@sergiomichels
Copy link
Collaborator

@bassmartin Congratulations on the birth of your baby! Enjoy this time :-)

@demon101
Copy link

@bassmartin , yes, agree with @sergiomichels , Enjoy this time :-) And sleep

@brischniz
Copy link
Author

Thanks @sergiomichels
Great work - I can confirm that your fix is working!

@bassmartin
Copy link
Contributor

bassmartin commented Dec 19, 2018

When I use the latest release, I don't have any SQL queries monitored.

sql Statistics sql - 1 day

None

Do you all still have SQL queries monitored?

I see this in the logs
GrailsErrorHandler : org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
when I call a withNewSession{} on a Domain Class

@sergiomichels
Copy link
Collaborator

@bassmartin Probably Grails version or data source different configuration, I added simple test in https://github.com/javamelody/grails-melody-plugin/blob/master/app-integration-tests/src/integration-test/groovy/grails.melody.plugin/GrailsTransactionSpec.groovy specially for sql monitoring...

We can start enhancing this integration test suite to cover this because is getting hard to handle all possibilities without tests.

@bassmartin
Copy link
Contributor

I installed a custom version with this code modified (removed the if if (dataSource instanceof TransactionAwareDataSourceProxy) { and it works for me on Grails 3.3.9 and GORM 6.1.11...

Why is that if required?

 // Attempt DataSources for Grails 3.3 and newer if no lazy proxy created
        if (!lazyProxied) {
            String hibernateBeanName = 'hibernateDatastore'
            if (applicationContext.containsBean(hibernateBeanName)) {
                def bean = applicationContext.getBean(hibernateBeanName)
                def transactionManager = bean.transactionManager
                def dataSource = transactionManager.dataSource
                LOG.debug "Wrapping Hibernate DataStore DataSource"
                dataSource.targetDataSource = JdbcWrapper.SINGLETON.createDataSourceProxy(dataSource.targetDataSource)
            }
        }

@sergiomichels
Copy link
Collaborator

Which class is this for you? I think my initial idea was to make sure that we're dealing with two levels of encapsulation to reach the datasource (store - targetds - targetds) but I guess we can check if property with this name exists instead of using instance of.

@bassmartin
Copy link
Contributor

screen shot 2019-01-02 at 10 54 49

@bassmartin
Copy link
Contributor

bassmartin commented Jan 2, 2019

This might have to do with my configuration.

Here are some extracts :

grails:
    spring:
        transactionManagement:
            proxies: false

hibernate:
    cache:
        queries: false
        use_second_level_cache: true
        use_query_cache: true
        region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
    flush:
        mode: AUTO
    jdbc:
        batch_versioned_data: false
        batch_size: 50
    connection:
        release_mode: ON_CLOSE
    hibernateDirtyChecking: true

I commented them and I still have a LazyConnectionDataSourceProxy

@bassmartin
Copy link
Contributor

Since the code in org.grails.datastore.gorm.jdbc.connections.DataSourceConnectionSourceFactory#proxy is

    protected DataSource proxy(DataSource dataSource, DataSourceSettings settings) {
        if(settings.isLazy()) {
            dataSource = new LazyConnectionDataSourceProxy(dataSource);
        }
        if(settings.isTransactionAware()) {
            dataSource = new TransactionAwareDataSourceProxy(dataSource);
        }
        return dataSource;
    }

I think we could replace if (dataSource instanceof TransactionAwareDataSourceProxy) by if (dataSource instanceof DelegatingDataSource) to support both types of proxy (since it's the superclass of both).

What do you think about that @sergiomichels ?

@sergiomichels
Copy link
Collaborator

Yep, looks good. I think that probably there's an way to configure this for one specific integration test (instead of creating new project), can you take a look at Spring Security plug-in and see if it's using it? https://github.com/grails-plugins/grails-spring-security-core/tree/master/integration-test-app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants