Skip to content

Wrong SessionFactory is used when tenant service is calling a non-tenant service. Behavior changed between 6.1.4 and 6.1.5. #14602

@andersb

Description

@andersb

In 6.1.4, it was possible to let a service working with multi-tenant domain call a second service working with non-multi-tenant domains.

This doesn't work since 6.1.5.
Now I can't say for sure that this was suppose to work in 6.1.4 like it does.
I see problems with having a transaction span over multiple data sources but this is a single data source with multi tenant mode SCHEMA.

I've included a test project which minimal external dependencies.
For the life of me I could not get multi tenancy working with with H2 memory database but starting H2 as network server will show the actual problem with transactions.

Running the test will work in 6.1.4.

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. Start H2 (downloaded from http://www.h2database.com/h2-2017-06-10.zip)
  2. Run gradlew check

Expected Behaviour

Test should pass

Actual Behaviour

Exception is thrown.

org.springframework.jdbc.BadSqlGrammarException: Hibernate operation: could not prepare statement; bad SQL grammar [insert into main_parent (version, name, id) values (?, ?, ?)]; nested exception is org.h2.jdbc.JdbcSQLException: Table "MAIN_PARENT" not found; SQL statement:
insert into main_parent (version, name, id) values (?, ?, ?) [42102-196]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.command.Parser.readTableOrView(Parser.java:5552)
	at org.h2.command.Parser.readTableOrView(Parser.java:5529)
	at org.h2.command.Parser.parseInsert(Parser.java:1062)
	at org.h2.command.Parser.parsePrepared(Parser.java:417)
	at org.h2.command.Parser.parse(Parser.java:321)
	at org.h2.command.Parser.parse(Parser.java:293)
	at org.h2.command.Parser.prepareCommand(Parser.java:258)
	at org.h2.engine.Session.prepareLocal(Session.java:578)
	at org.h2.server.TcpServerThread.process(TcpServerThread.java:264)
	at org.h2.server.TcpServerThread.run(TcpServerThread.java:158)
	at java.lang.Thread.run(Unknown Source)


	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.convertJdbcAccessException(GrailsHibernateTemplate.java:731)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.convertHibernateAccessException(GrailsHibernateTemplate.java:719)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:303)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:243)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:117)
	at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.performSave(AbstractHibernateGormInstanceApi.groovy:242)
	at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.save(AbstractHibernateGormInstanceApi.groovy:159)
	at org.grails.datastore.gorm.GormEntity$Trait$Helper.save(GormEntity.groovy:151)
	at se.demo.plugin.maindb.MainParentService.$tt__save(MainParentService.groovy:9)
	at se.demo.plugin.maindb.MainParentService.save_closure1(MainParentService.groovy)
	at groovy.lang.Closure.call(Closure.java:414)
	at groovy.lang.Closure.call(Closure.java:430)
	at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
	at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
	at se.demo.plugin.clientdb.TenantParentService.$tt__saveAndCallMainDbMethod(TenantParentService.groovy:22)
	at se.demo.plugin.clientdb.TenantParentService._mt__saveAndCallMainDbMethod_closure4(TenantParentService.groovy)
	at groovy.lang.Closure.call(Closure.java:414)
	at groovy.lang.Closure.call(Closure.java:430)
	at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
	at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
	at se.demo.plugin.clientdb.TenantParentService.saveAndCallMainDbMethod_closure2(TenantParentService.groovy)
	at groovy.lang.Closure.call(Closure.java:414)
	at groovy.lang.Closure.call(Closure.java:430)
	at grails.gorm.multitenancy.Tenants.withId_closure1$_closure3(Tenants.groovy:229)
	at org.grails.orm.hibernate.GrailsHibernateTemplate$1.doInHibernate(GrailsHibernateTemplate.java:153)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:299)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:243)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.executeWithNewSession(GrailsHibernateTemplate.java:150)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.executeWithExistingOrCreateNewSession(GrailsHibernateTemplate.java:209)
	at org.grails.orm.hibernate.AbstractHibernateDatastore.withNewSession(AbstractHibernateDatastore.java:362)
	at grails.gorm.multitenancy.Tenants.withId_closure1(Tenants.groovy:222)
	at grails.gorm.multitenancy.Tenants$CurrentTenant.withTenant(Tenants.groovy:322)
	at grails.gorm.multitenancy.Tenants.withId(Tenants.groovy:200)
	at org.grails.datastore.gorm.services.DefaultTenantService.withCurrent(DefaultTenantService.groovy:71)
	at se.demo.plugin.IntegrationSpec.$tt__$spock_feature_0_0(IntegrationSpec.groovy:54)
	at se.demo.plugin.IntegrationSpec.test of transactions across both main and tenant db_closure2(IntegrationSpec.groovy)
	at groovy.lang.Closure.call(Closure.java:414)
	at groovy.lang.Closure.call(Closure.java:430)
	at grails.gorm.transactions.GrailsTransactionTemplate$1.doInTransaction(GrailsTransactionTemplate.groovy:68)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
	at grails.gorm.transactions.GrailsTransactionTemplate.executeAndRollback(GrailsTransactionTemplate.groovy:65)
	at se.demo.plugin.IntegrationSpec.test of transactions across both main and tenant db(IntegrationSpec.groovy)
Caused by: org.h2.jdbc.JdbcSQLException: Table "MAIN_PARENT" not found; SQL statement:
insert into main_parent (version, name, id) values (?, ?, ?) [42102-196]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.command.Parser.readTableOrView(Parser.java:5552)
	at org.h2.command.Parser.readTableOrView(Parser.java:5529)
	at org.h2.command.Parser.parseInsert(Parser.java:1062)
	at org.h2.command.Parser.parsePrepared(Parser.java:417)
	at org.h2.command.Parser.parse(Parser.java:321)
	at org.h2.command.Parser.parse(Parser.java:293)
	at org.h2.command.Parser.prepareCommand(Parser.java:258)
	at org.h2.engine.Session.prepareLocal(Session.java:578)
	at org.h2.server.TcpServerThread.process(TcpServerThread.java:264)
	at org.h2.server.TcpServerThread.run(TcpServerThread.java:158)
	at java.lang.Thread.run(Unknown Source)

	at org.h2.engine.SessionRemote.done(SessionRemote.java:629)
	at org.h2.command.CommandRemote.prepare(CommandRemote.java:83)
	at org.h2.command.CommandRemote.<init>(CommandRemote.java:49)
	at org.h2.engine.SessionRemote.prepareCommand(SessionRemote.java:499)
	at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1204)
	at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:73)
	at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288)
	at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.invoke(LazyConnectionDataSourceProxy.java:376)
	at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
	at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:87)
	at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172)
	at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:78)
	at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.buildBatchStatement(AbstractBatchImpl.java:136)
	at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.getBatchStatement(AbstractBatchImpl.java:125)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2980)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3499)
	at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:589)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1295)
	at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.flushSession(AbstractHibernateGormInstanceApi.groovy:280)
	at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.performSave_closure3(AbstractHibernateGormInstanceApi.groovy:245)
	at groovy.lang.Closure.call(Closure.java:414)
	at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:299)
	... 41 more

Environment Information

  • Operating System: Windows 10
  • GORM Version: 6.1.7
  • Grails Version (if using Grails): 3.3.1
  • JDK Version: 1.8.0_111

Example Application

multi-tenancy-demo-plugin.zip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions