Spring @transactional,如何配置两个不同的数据库节点

时间:2018-08-28 09:23:03

标签: spring spring-boot transactions spring-transactions

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

如果一个数据库节点发生故障,那么事务管理器应与第二个节点一起正常工作。

如果数据库节点在事务之间失败,那么它也应与第二个节点一起使用。是否有任何方法可以在春季进行配置

2 个答案:

答案 0 :(得分:0)

您可以根据情况采用多租户方式

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

您需要重写MultiTenantConnectionProviderImpl方法

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

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

但这不是一个简单的任务。

答案 1 :(得分:0)

尽管上面已经提供了答案,但我将再次发布更多详细信息,

我同意您可以将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; } } 切换传入请求的数据库。

<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>

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

var a = " a @b c "
console.log(a.split(" "))
["", "a", "b", "c", ""]

我希望这会有所帮助。