HHH-11980 MultiTenantConnectionProvider is required for MultiTenancyStrategy.DISCRIMINATOR
Instead of checking that multiTenancyStrategy is NONE start using MultiTenancyStrategy.requiresMultiTenantConnectionProvider to distinguish whether MultiTenantConnectionProvider is to be used.
This commit is contained in:
parent
5be294506d
commit
e391d8577e
|
@ -42,7 +42,7 @@ public class MultiTenantConnectionProviderInitiator implements StandardServiceIn
|
|||
@SuppressWarnings( {"unchecked"})
|
||||
public MultiTenantConnectionProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
|
||||
final MultiTenancyStrategy strategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configurationValues );
|
||||
if ( strategy == MultiTenancyStrategy.NONE || strategy == MultiTenancyStrategy.DISCRIMINATOR ) {
|
||||
if ( !strategy.requiresMultiTenantConnectionProvider() ) {
|
||||
// nothing to do, but given the separate hierarchies have to handle this here.
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
|
|||
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy(
|
||||
configValues
|
||||
);
|
||||
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
|
||||
if ( !multiTenancyStrategy.requiresMultiTenantConnectionProvider() ) {
|
||||
ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class );
|
||||
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEn
|
|||
public static JdbcConnectionAccess buildBootstrapJdbcConnectionAccess(
|
||||
MultiTenancyStrategy multiTenancyStrategy,
|
||||
ServiceRegistryImplementor registry) {
|
||||
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
|
||||
if ( !multiTenancyStrategy.requiresMultiTenantConnectionProvider() ) {
|
||||
ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class );
|
||||
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
|
||||
}
|
||||
|
|
|
@ -445,7 +445,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
public JdbcConnectionAccess getJdbcConnectionAccess() {
|
||||
// See class-level JavaDocs for a discussion of the concurrent-access safety of this method
|
||||
if ( jdbcConnectionAccess == null ) {
|
||||
if ( MultiTenancyStrategy.NONE == factory.getSettings().getMultiTenancyStrategy() ) {
|
||||
if ( !factory.getSettings().getMultiTenancyStrategy().requiresMultiTenantConnectionProvider() ) {
|
||||
jdbcConnectionAccess = new NonContextualJdbcConnectionAccess(
|
||||
getEventListenerManager(),
|
||||
factory.getServiceRegistry().getService( ConnectionProvider.class )
|
||||
|
|
|
@ -424,14 +424,14 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
return new JdbcConnectionAccess() {
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
return settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE
|
||||
return !settings.getMultiTenancyStrategy().requiresMultiTenantConnectionProvider()
|
||||
? serviceRegistry.getService( ConnectionProvider.class ).getConnection()
|
||||
: serviceRegistry.getService( MultiTenantConnectionProvider.class ).getAnyConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
if ( settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE ) {
|
||||
if ( !settings.getMultiTenancyStrategy().requiresMultiTenantConnectionProvider() ) {
|
||||
serviceRegistry.getService( ConnectionProvider.class ).closeConnection( connection );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.test.multitenancy.discriminator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
|
||||
import org.hibernate.tool.schema.internal.SchemaCreatorImpl;
|
||||
import org.hibernate.tool.schema.internal.SchemaDropperImpl;
|
||||
import org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.cache.CachingRegionFactory;
|
||||
import org.hibernate.testing.env.ConnectionProviderBuilder;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.hibernate.test.multitenancy.schema.Customer;
|
||||
import org.hibernate.test.util.DdlTransactionIsolatorTestingImpl;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Mårten Svantesson
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-11980")
|
||||
public class DiscriminatorMultiTenancyTest extends BaseUnitTestCase {
|
||||
|
||||
private SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private DriverManagerConnectionProviderImpl connectionProvider;
|
||||
|
||||
private final TestCurrentTenantIdentifierResolver currentTenantResolver = new TestCurrentTenantIdentifierResolver();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Map settings = new HashMap();
|
||||
settings.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DISCRIMINATOR);
|
||||
settings.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantResolver);
|
||||
settings.put(Environment.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName());
|
||||
settings.put(Environment.GENERATE_STATISTICS, "true");
|
||||
|
||||
ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder()
|
||||
.applySettings(settings)
|
||||
.build();
|
||||
|
||||
MetadataSources ms = new MetadataSources(serviceRegistry);
|
||||
ms.addAnnotatedClass(Customer.class);
|
||||
|
||||
Metadata metadata = ms.buildMetadata();
|
||||
((RootClass) metadata.getEntityBinding(Customer.class.getName())).setCacheConcurrencyStrategy("read-write");
|
||||
|
||||
HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool();
|
||||
tool.injectServices(serviceRegistry);
|
||||
|
||||
connectionProvider = ConnectionProviderBuilder.buildConnectionProvider();
|
||||
|
||||
final GenerationTargetToDatabase target = new GenerationTargetToDatabase(
|
||||
new DdlTransactionIsolatorTestingImpl(
|
||||
serviceRegistry,
|
||||
connectionProvider
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
new SchemaDropperImpl(serviceRegistry).doDrop(
|
||||
metadata,
|
||||
serviceRegistry,
|
||||
settings,
|
||||
true,
|
||||
target
|
||||
);
|
||||
|
||||
new SchemaCreatorImpl(serviceRegistry).doCreation(
|
||||
metadata,
|
||||
serviceRegistry,
|
||||
settings,
|
||||
true,
|
||||
target
|
||||
);
|
||||
|
||||
target.release();
|
||||
|
||||
final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder();
|
||||
sessionFactory = (SessionFactoryImplementor) sfb.build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() {
|
||||
sessionFactory.close();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor sessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests for current tenant being used for second level cache, but not selecting connection provider.
|
||||
* Discrimination on connection level will for now need to be implemented in the supplied connection provider.
|
||||
*/
|
||||
@Test
|
||||
public void testDiscriminator() {
|
||||
|
||||
doInHibernate( "jboss", session -> {
|
||||
Customer steve = new Customer( 1L, "steve" );
|
||||
session.save( steve );
|
||||
} );
|
||||
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
// make sure we get the steve back, from cache if same tenant (jboss)
|
||||
doInHibernate( "jboss", session -> {
|
||||
Customer customer = session.load( Customer.class, 1L );
|
||||
Assert.assertEquals( "steve", customer.getName() );
|
||||
// also, make sure this came from second level
|
||||
Assert.assertEquals( 1, sessionFactory.getStatistics().getSecondLevelCacheHitCount() );
|
||||
} );
|
||||
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
// then make sure we get the steve back, from db if other tenant (acme)
|
||||
doInHibernate( "acme", session -> {
|
||||
Customer customer = session.load( Customer.class, 1L );
|
||||
Assert.assertEquals( "steve", customer.getName() );
|
||||
// also, make sure this doesn't came from second level
|
||||
Assert.assertEquals( 0, sessionFactory.getStatistics().getSecondLevelCacheHitCount() );
|
||||
} );
|
||||
|
||||
// make sure the same works from data store too
|
||||
sessionFactory.getStatistics().clear();
|
||||
sessionFactory.getCache().evictEntityRegions();
|
||||
|
||||
// first jboss
|
||||
doInHibernate( "jboss", session -> {
|
||||
Customer customer = session.load( Customer.class, 1L );
|
||||
Assert.assertEquals( "steve", customer.getName() );
|
||||
// also, make sure this doesn't came from second level
|
||||
Assert.assertEquals( 0, sessionFactory.getStatistics().getSecondLevelCacheHitCount() );
|
||||
} );
|
||||
|
||||
sessionFactory.getStatistics().clear();
|
||||
// then, acme
|
||||
doInHibernate( "acme", session -> {
|
||||
Customer customer = session.load( Customer.class, 1L );
|
||||
Assert.assertEquals( "steve", customer.getName() );
|
||||
// also, make sure this doesn't came from second level
|
||||
Assert.assertEquals( 0, sessionFactory.getStatistics().getSecondLevelCacheHitCount() );
|
||||
} );
|
||||
|
||||
doInHibernate( "jboss", session -> {
|
||||
Customer customer = session.load( Customer.class, 1L );
|
||||
session.delete( customer );
|
||||
} );
|
||||
}
|
||||
|
||||
private static class TestCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
|
||||
private String currentTenantIdentifier;
|
||||
|
||||
@Override
|
||||
public String resolveCurrentTenantIdentifier() {
|
||||
return currentTenantIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateExistingCurrentSessions() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void doInHibernate(String tenant,
|
||||
Consumer<Session> function) {
|
||||
currentTenantResolver.currentTenantIdentifier = tenant;
|
||||
TransactionUtil.doInHibernate( this::sessionFactory, tenant, function);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue