Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Multitenancy sessions manually

I need to create a multitenanacy application with ability to switch between schemas inside my java-code (not based on a user request).

I've read articles: https://fizzylogic.nl/2016/01/24/make-your-spring-boot-application-multi-tenant-aware-in-2-steps/ http://www.greggbolinger.com/tenant-per-schema-with-spring-boot/ Solution works fine, when the schema is passed in Rest-request.

However I need to implement the following logic:

public void compare(String originalSchema, String secondSchema){
    TenantContext.setCurrentTenant(originalSchema);
    List<MyObject> originalData = myRepository.findData();

    TenantContext.setCurrentTenant(secondSchema);
    List<MyObject> migratedData = myRepository.findData();
}

The point is, that connection is not switched, when I manually set up TenenantContext. MultiTenantConnectionProviderImpl.getConnection is invoked only on the first call to my repository.

 @Component
 public class MultiTenantConnectionProviderImpl implements  MultiTenantConnectionProvider {

     @Override
     public Connection getConnection(String tenantIdentifier) throws SQLException {
          final Connection connection = getAnyConnection();
          try {
               connection.createStatement().execute( "ALTER SESSION SET CURRENT_SCHEMA = " + tenantIdentifier );
          }
          catch ( SQLException e ) {
              throw new HibernateException(
      "Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]",e);
          }
          return connection;
    }
 }

Is it possible to force switching sessions?

like image 870
Ermintar Avatar asked Oct 20 '17 10:10

Ermintar


People also ask

How multi tenancy is implemented?

We can implement multi-tenancy using any of the following approaches: Database per Tenant: Each Tenant has its own database and is isolated from other tenants. Shared Database, Shared Schema: All Tenants share a database and tables. Every table has a Column with the Tenant Identifier, that shows the owner of the row.

What is spring boot Multitenancy?

Multitenancy allows multiple clients or tenants use a single resource or, in the context of this article, a single database instance. The purpose is to isolate the information each tenant needs from the shared database.


2 Answers

Found a hard-coded solution.

@Service
public class DatabaseSessionManager {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    public void bindSession() {
        if (!TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
        }
    }

    public void unbindSession() {
        EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
            .unbindResource(entityManagerFactory);
        EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
    }
}

Each block, loading data in a new tenantContext should execute the following:

    databaseSessionManager.unbindSession();
    TenantContext.setCurrentTenant(schema);
    databaseSessionManager.bindSession();
    //execute selects
like image 60
Ermintar Avatar answered Oct 17 '22 16:10

Ermintar


Well, you need it

public interface Service {
    List<MyObject> myObjects();
}

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class ServiceImpl implements Service {
     @Autowired
     private MyRepository myRepository;

     @Override
     public List<MyObject> myObjects() {
         return myRepository.findData();
     }
}

@Service
public class AnotherService() {
    @Autowired
    private Service service;

    public void compare(String originalSchema, String secondSchema){
        TenantContext.setCurrentTenant(originalSchema);
        List<MyObject> originalData = service.myObjects();

        TenantContext.setCurrentTenant(secondSchema);
        List<MyObject> migratedData = service.myObjects();
    }
}
like image 1
Andriy Slobodyanyk Avatar answered Oct 17 '22 17:10

Andriy Slobodyanyk