Spring @ транзакционный, как настроить два разных узла базы данных - PullRequest
0 голосов
/ 28 августа 2018

Я хочу настроить аннотации @transactional для двух разных узлов базы данных.

Если происходит сбой на одном узле базы данных, диспетчер транзакций должен работать со вторым узлом без сбоев.

Если между узлами базы данных происходит сбой между транзакциями, то также он должен работать со вторым узлом. Есть ли способ настроить это весной

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

Хотя ответ уже предоставлен выше, я публикую его снова с более подробной информацией,

Я согласен с тем, что Вы можете использовать MultiTenantConnectionProviderImpl вместе с CurrentTenantIdentifierResolver, я реализовал обе версии и я публикую свой код для получения дополнительной помощи.

Цель того и другого должна быть понята первой.

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-компоненты в весенней конфигурации, а также указать это в конфигурации 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>

Надеюсь, это поможет.

0 голосов
/ 28 августа 2018

Вы можете адаптировать многопользовательский подход в вашем случае

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

Вам необходимо переопределить методы MultiTenantConnectionProviderImpl

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

Чтобы проверить и вернуть второе соединение с источником данных, если первое не удалось.

Хотя это не простая задача.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...