2017-10-20 80 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