【问题标题】:Spring @ transactional, how to configure two different nodes of data basespring@transactional,如何配置数据库的两个不同节点
【发布时间】:2018-08-28 09:23:03
【问题描述】:

我想用两个不同的数据库节点配置@transactional 注解。

如果一个数据库节点出现故障,那么事务管理器应该与第二个节点一起工作而不会出现任何故障。

如果数据库节点在事务之间失败,那么它也应该与第二个节点一起工作。有什么方法可以在 spring 中配置它

【问题讨论】:

    标签: spring spring-boot transactions spring-transactions


    【解决方案1】:

    您可以根据自己的情况调整多租户方法

    https://dzone.com/articles/spring-boot-hibernate-multitenancy-implementation

    您需要重写 MultiTenantConnectionProviderImpl 方法

    public Connection getConnection(String tenantIdentifier)
    public Connection getAnyConnection()
    

    如果第一个失败,则检查并返回第二个 DataSource 连接。

    虽然不是一个简单的任务。

    【讨论】:

      【解决方案2】:

      虽然上面已经给出了答案,但我再次发布它并提供更多详细信息,

      我同意您可以将MultiTenantConnectionProviderImplCurrentTenantIdentifierResolver 一起使用,我早就实现了这两个功能,并且我正在发布我的代码以获得更多帮助。

      首先要了解两者的目的。

      CurrentTenantIdentifierResolver 用于识别要用于给定租户的连接,为此您需要租户标识。对于租户识别的逻辑,您可以覆盖它。在您的情况下,它将被修复,即您将始终指向您的第一个数据库。

      public class TenantIdentifierAndSchemaResolver implements CurrentTenantIdentifierResolver {
      
          private String tenantIdentifier = "FIRST_DATABASE";
      
          @Override
          public String resolveCurrentTenantIdentifier() {
              return this.tenantIdentifier;
          }
      
          /**
           * Reason why it retuns a false is because we don't want to validate the
           * tenant identifier in the current session.
           * 
           * Please read below.
           * {@link CurrentTenantIdentifierResolver#validateExistingCurrentSessions()}
           */
          @Override
          public boolean validateExistingCurrentSessions() {
              return false;
          }
      
          public void setTenantIdentifier(String tenantIdentifier) {
              this.tenantIdentifier = tenantIdentifier;
          }
      }
      

      在此之后,您需要实现MultiTenantConnectionProvider,使用它您将实际切换数据库以接收传入请求。

      public class CustomMultiTenantConnectionProvider implements MultiTenantConnectionProvider {
      
          private static final long serialVersionUID = 9033113494774715973L;
      
          private Logger LOG = LogManager.getLogger(CustomMultiTenantConnectionProvider.class);
      
          private BasicDataSource dataSource;
      
          public void setDataSource(BasicDataSource dataSource) {
              this.dataSource = dataSource;
          }
      
          @Override
          public Connection getAnyConnection() throws SQLException {
              if (LOG.isDebugEnabled()) {
                  LOG.debug("Fetching any connection >");
              }
              return dataSource.getConnection();
          }
      
          @Override
          public Connection getConnection(String tenantIdentifier) throws SQLException {
              Connection tenantSpecificConnection = dataSource.getConnection();
          if (!StringUtils.isEmpty(tenantIdentifier)) {
              Statement statement = tenantSpecificConnection.createStatement();
              statement.executeQuery("use " + tenantIdentifier);
              statement.close();
              tenantSpecificConnection.setSchema(tenantIdentifier);
          } else {
              tenantSpecificConnection.setSchema(Constants.SOMEOTHER_DB);
          }
          return tenantSpecificConnection;
          }
      
          @Override
          public void releaseAnyConnection(Connection connection) throws SQLException {
              if (LOG.isDebugEnabled()) {
                  LOG.debug("Releasing connection obtained by : getAnyConnection", connection);
              }
              connection.close();
          }
      
          @Override
          public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
              if (LOG.isDebugEnabled()) {
                  LOG.debug("Releasing connection for : {}", tenantIdentifier);
              }
              connection.close();
          }
      
          /**
           * does the connection provider has support for releasing connection and get
           * back the connection as and when needed ?
           * 
           * @return
           */
          @Override
          public boolean supportsAggressiveRelease() {
              return false;
          }
      
          @SuppressWarnings("rawtypes")
          @Override
          public boolean isUnwrappableAs(Class arg0) {
              return false;
          }
      
          @Override
          public <T> T unwrap(Class<T> arg0) {
              return null;
          }
      }
      

      您需要在 spring 配置中声明这些 bean,并在 hibernate 配置中指定。

      <bean id="sessionFactory"
              class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
              <property name="dataSource" ref="dataSource" />
              <property name="packagesToScan" value="org.opensource.example" />
              <property name="hibernateProperties">
                  <map>
                      <entry key="hibernate.hbm2ddl.auto" value="update"></entry>
                      <entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"></entry>
                      <entry key="hibernate.connection.charSet" value="UTF-8"></entry>
                      <entry key="hibernate.multiTenancy" value="SCHEMA"></entry>
                      <entry key="hibernate.tenant_identifier_resolver" value-ref="multitenantSchemaResolverAndTenantIdentifier"></entry>
                      <entry key="hibernate.multi_tenant_connection_provider"
                          value-ref="multitenantConnectionProvider"></entry>
                      <entry key="hibernate.show_sql" value="true"></entry>
                      <entry key="hibernate.use_sql_comments" value="true"></entry>
                      <entry key="hibernate.connection.charSet" value="UTF-8"></entry>
                  </map>
              </property>
          </bean>
      

      我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2018-08-07
        • 2011-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-16
        • 1970-01-01
        相关资源
        最近更新 更多