2017-10-20 66 views
0

我需要创建一个具有在我的java代码(不基于用户请求)内部架构之间切换的能力的多元应用程序。手动更改多租户会话

我读过的文章: 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/ 解决方案正常工作,当架构中休息,请求被通过。

但是我需要执行以下逻辑:

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

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

的一点是,该连接不被切换,当手动设置TenenantContext。 MultiTenantConnectionProviderImpl.getConnection仅在首次调用我的存储库时调用。

@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; 
    } 
} 

是否可以强制切换会话?

+0

是的,这是可能的,但需要在交易范围之外切换会话。 –

+0

@Andriy Slobodyanyk,我不会手动创建交易。我有一个服务,没有事务性注释,并使库存。交易债券来自哪里? – Ermintar

回答

0

发现一个硬编码解决方案。

@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()); 
    } 
} 

每个块,在一个新的tenantContext加载数据应执行以下命令:

databaseSessionManager.unbindSession(); 
    TenantContext.setCurrentTenant(schema); 
    databaseSessionManager.bindSession(); 
    //execute selects 
1

那么,你需要它

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(); 
    } 
} 
+0

不幸的是,它和自动装配仓库一样工作。连接未被切换 – Ermintar

+0

@Ermintar,您确定事务在任何SQL操作之前未启动吗?为了解决它,我建议在新事务中查找数据,我已经更新了我的答案。 –

+0

@ Andriy Slobodyanyk,要求新人不支持。而且我的服务没有任何事务上下文 - 它是我直接调用的唯一方法。 – Ermintar