Использование зеркального отображения базы данных (JDBC)

Скачать драйвер JDBC

Зеркальное отображение базы данных представляет решение по повышению доступности базы данных и резервированию данных, реализуемое в основном программными средствами. Драйвер Microsoft JDBC для SQL Server предоставляет неявную поддержку зеркального отображения базы данных, поэтому разработчику не нужно писать код или выполнять какие-либо другие действия при настройке базы данных.

Зеркалирование базы данных, которое выполняется отдельно для каждой базы данных, поддерживает копию производственной базы данных SQL Server на резервном сервере. Это или «горячий», или «теплый» резервный сервер, в зависимости от конфигурации и состояния сеанса зеркального отображения базы данных. Сервер горячего резерва обеспечивает быстрое переключение при сбое без потери зафиксированных транзакций. Сервер в режиме тёплого резерва поддерживает принудительное переключение с возможной потерей данных.

Рабочая база данных называется основной, а резервная копия — зеркальной базой данных. Основная база данных и зеркальная база данных должны находиться в отдельных экземплярах SQL Server (экземплярах сервера). По возможности они должны размещаться на разных компьютерах.

Экземпляр рабочего сервера (основной сервер) обменивается данными с экземпляром резервного сервера (зеркальный сервер). Основной и зеркальный серверы выступают в роли участников в сеансе зеркального отображения базы данных. Если основной сервер выходит из строя, зеркальный сервер может сделать свою базу данных основной посредством процесса, называемого переключением при отказе. Например, имеется два сервера-участника, Partner_A and Partner_B, при этом основная база данных изначально находится на сервере Partner_A (основной сервер), а зеркальная база данных — на сервере Partner_B (зеркальный сервер). Если сервер Partner_A переходит в режим вне сети, база данных на сервере Partner_B становится текущей основной базой данных. Когда Partner_A снова присоединяется к сеансу зеркального отображения, он становится зеркальным сервером, а его база данных — зеркальной базой данных.

Если сервер Partner_A выходит из строя без возможности восстановления, сервер Partner_C можно перевести в подключенный режим, чтобы использовать в качестве зеркального сервера для сервера Partner_B, который становится основным. Однако в этой ситуации клиентское приложение должно содержать логику программирования, обеспечивающую обновление свойств строк соединения с учетом новых имен серверов, используемых в конфигурации зеркального отображения базы данных. В противном случае соединение с серверами может не установиться.

Альтернативные конфигурации зеркального отображения баз данных обеспечивают различные уровни производительности и сохранности данных, а также поддерживают разные формы переключения при отказе. Дополнительные сведения см. в статье "Обзор зеркального отображения базы данных" в электронной документации по SQL Server.

Замечания по программированию

Если сервер, на котором размещается основная база данных, дает сбой, в ответ на вызовы API клиентское приложение получает ошибки, которые указывают на потерю соединения с базой данных. В этом случае утрачиваются все незафиксированные изменения в базе данных и выполняется откат текущей транзакции. В этом сценарии приложение должно закрыть подключение (или освободить объект источника данных), а затем снова открыть его. После подключения новое соединение автоматически направляется на зеркальную базу данных, которая теперь играет роль основного сервера, и клиенту не нужно изменять строку подключения или объект источника данных.

При первоначальном установлении соединения основной сервер отправляет клиенту сведения о своем партнере по аварийному переключению, который будет использоваться при возникновении отказа. Если приложение пытается установить первичное подключение с недоступным основным сервером, клиент не знает, кто является партнером по отработке отказа. Чтобы дать клиентам возможность справиться с таким сценарием, свойство строки подключения failoverPartner и, при необходимости, метод источника данных setFailoverPartner позволяют клиенту самостоятельно указать идентификатор партнёра для аварийного переключения. Свойство клиента используется только в этом сценарии и не используется, если доступен основной сервер.

Примечание.

Если свойство failoverPartner указывается в строке соединения или в объекте источника данных, то также необходимо установить свойство databaseName. В противном случае будет вызвано исключение. Если свойства failoverPartner и databaseName не заданы явно, то приложение не будет запускать отработку отказа в случае отказа основного сервера базы данных. Иначе говоря, прозрачное перенаправление работает только для подключений, в которых явно указаны failoverPartner и databaseName. Дополнительные сведения о свойстве failoverPartner и других свойствах строки соединения см. в статье о настройке свойств подключения.

Если указанный клиентом сервер-партнёр по переключению при отказе не является сервером, выступающим в качестве партнёра по переключению при отказе для указанной базы данных, и если указанные сервер и база данных участвуют в конфигурации зеркалирования, подключение отклоняется сервером. Класс SQLServerDataSource содержит метод getFailoverPartner, но этот метод возвращает только имя партнера по обеспечению отработки отказа, указанное в строке подключения или с помощью метода setFailoverPartner. Чтобы получить имя фактического партнёра по аварийному переключению, который используется в данный момент, используйте следующую инструкцию Transact-SQL:

SELECT m.mirroring_role_DESC, m.mirroring_state_DESC,
m.mirroring_partner_instance FROM sys.databases as db,
sys.database_mirroring AS m WHERE db.name = 'MirroringDBName'
AND db.database_id = m.database_id

Примечание.

Эту инструкцию нужно изменить в соответствии с именем зеркальной базы данных.

Рекомендуется кэшировать сведения об участниках для обновления строки подключения или разработать стратегию повторных попыток на случай, если первая попытка установить подключение завершается ошибкой.

Пример

В следующем примере сначала выполняется попытка подключения к основному серверу. Если это не удаётся и возникает исключение, предпринимается попытка подключения к зеркальному серверу, который мог стать новым основным сервером. Заметьте, что в строке соединения используется свойство failoverPartner.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class ClientFailover {
    public static void main(String[] args) {

        String connectionUrl = "jdbc:sqlserver://serverA:1433;"
                + "encrypt=true;databaseName=AdventureWorks;integratedSecurity=true;"
                + "failoverPartner=serverB";

        // Establish the connection to the principal server.
        try (Connection con = DriverManager.getConnection(connectionUrl);
                Statement stmt = con.createStatement();) {
            System.out.println("Connected to the principal server.");

            // Note that if a failover of serverA occurs here, then an
            // exception will be thrown and the failover partner will
            // be used in the first catch block below.

            // Execute a SQL statement that inserts some data.

            // Note that the following statement assumes that the
            // TestTable table has been created in the AdventureWorks
            // sample database.
            stmt.executeUpdate("INSERT INTO TestTable (Col2, Col3) VALUES ('a', 10)");
        }
        catch (SQLException se) {
            System.out.println("Connection to principal server failed, " + "trying the mirror server.");
            // The connection to the principal server failed,
            // try the mirror server which may now be the new
            // principal server.
            try (Connection con = DriverManager.getConnection(connectionUrl);
                    Statement stmt = con.createStatement();) {
                System.out.println("Connected to the new principal server.");
                stmt.executeUpdate("INSERT INTO TestTable (Col2, Col3) VALUES ('a', 10)");
            }
            // Handle any errors that may have occurred.
            catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}