Как хранить изображения в MySQL с помощью BLOB

BLOB (или Binary Large Object, большой двоичный объект) – это тип данных MySQL, который позволяет хранить двоичные данные: изображения, мультимедиа и файлы PDF.
Хранить изображения (такие как фотографии и подписи) в базе данных MySQL вместе с другой информацией удобно в том случае, если вы разрабатываете приложения с сильной привязкой к БД (например, портал поиска работы, база данных студентов или финансовое приложение), и в этой БД изображения должны быть синхронизированы с другими данными.
И тогда на помощь приходит тип данных BLOB. Этот подход устраняет необходимость в создании отдельной файловой системы для хранения изображений, а также централизует базу данных, делая ее более портативной и надежной, поскольку данные изолированы от файловой системы. А еще это упрощает создание резервных копий, поскольку вы можете создать один дамп MySQL, содержащий все ваши данные.
Извлечение данных обрабатывается быстрее, а при создании новых записей вы можете быть уверены, что правила проверки данных и ссылочная целостность четко соблюдены (особенно при использовании транзакций MySQL).
В этом мануале мы расскажем о том, как использовать тип данных BLOB для хранения изображений с помощью PHP.
Требования
- Сервер Ubuntu 18.04, предварительно настроенный согласно этим инструкциям.
- Стек LAMP, установленный на вашем сервере. С установкой вам поможет этот мануал (раздел о виртуальных хостах можно пропустить, здесь мы не будем их использовать).
1: Создание базы данных
Давайте начнем с создания тестовой базы данных для этого проекта. Подключитесь к серверу по SSH, а затем выполните следующую команду, чтобы войти на сервер MySQL как пользователь root:
sudo mysql -u root -p
Введите root-пароль базы данных MySQL и нажмите Enter, чтобы продолжить.
После этого выполните следующую команду, чтобы создать базу данных. В этом руководстве мы назовем ее test_company:
CREATE DATABASE test_company;
После создания БД вы увидите следующее:
Query OK, 1 row affected (0.01 sec)
Теперь нам нужно создать на сервере MySQL учетную запись test_user; не забудьте заменить PASSWORD сложным паролем:
CREATE USER ‘test_user’@’localhost’ IDENTIFIED BY ‘PASSWORD’;
Вы получите следующий результат:
Query OK, 0 rows affected (0.01 sec)
Чтобы предоставить пользователю test_user полные права доступа к базе данных test_company, запустите команду:
GRANT ALL PRIVILEGES ON test_company.* TO ‘test_user’@’localhost’;
Вы должны получить следующий результат:
Query OK, 0 rows affected (0.01 sec)
В завершение нужно сбросить таблицы привилегий, чтобы MySQL перезагрузил права:
На экране должно появиться:
Query OK, 0 rows affected (0.01 sec)
Теперь, когда база данных test_company и пользователь test_user готовы, мы можем перейти к созданию таблицы. Предположим, нам нужна таблица products для хранения списка товаров. Позже мы попробуем вставить и извлечь данные из этой таблицы, чтобы понять, как работает BLOB в MySQL.
Выйдите из оболочки MySQL:
Затем снова войдите в систему, на этот раз – как пользователь test_user:
mysql -u test_user -p
При появлении запроса введите пароль test_user и нажмите Enter, чтобы продолжить. Затем откройте базу данных test_company, набрав команду:
Перейдя в базу данных test_company, MySQL отобразит такой результат:
Затем создайте таблицу products:
CREATE TABLE `products` (product_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(50), price DOUBLE, product_image BLOB) ENGINE = InnoDB;
Эта команда создаст таблицу по имени products. В таблице будет четыре столбца:
- product_id: в этом столбце используется тип данных BIGINT, он позволяет вместить большой список продуктов, содержащий 2⁶³-1 элементов. Мы пометили столбец как PRIMARY KEY, чтобы присвоить товарам уникальные идентификаторы. Чтобы MySQL мог обрабатывать создание новых идентификаторов, мы использовали ключевое слово AUTO_INCREMENT.
- product_name: этот столбец содержит названия товаров. Здесь мы использовали тип данных VARCHAR, так как это поле обычно обрабатывает буквенно-цифровые значения длиной до 50 символов; ограничение в 50 символов – это всего лишь гипотетическое значение, используемое для целей этого руководства.
- price: этот столбец содержит розничные цены наших товаров. Поскольку цена на некоторые товары может выражаться числом с плавающей точкой (например, 23.69, 45.36, 102.99), мы указали здесь тип данных DOUBLE.
- product_image: в этом столбце мы указали тип данных BLOB, поскольку он предназначен для хранения двоичных данных – изображений товаров.
Для поддержки широкого спектра функций, включая транзакции MySQL, мы использовали механизм InnoDB. Выполнив вышеприведенную команду для создания таблицы, вы увидите следующий результат:
Query OK, 0 rows affected (0.03 sec)
Выйдите из сервера MySQL:
Вы получите сообщение:
Таблица products готова. Вы можете использовать ее для хранения некоторых записей, включая изображения продуктов. Скоро мы заполним ее данными.
2: Создание PHP-скрипта для заполнения базы данных
На этом этапе мы создадим сценарий PHP, который будет подключаться к базе данных MySQL, созданной в первом разделе руководства. Сценарий подготовит три записи о товарах и вставит их в таблицу products.
Чтобы создать PHP-скрипт, откройте новый файл в текстовом редакторе:
sudo nano /var/www/html/config.php
Затем вставьте в него следующую информацию (замените PASSWORD паролем test_user, который вы создали в разделе 1):
$pdo = new PDO(«mysql:host=» . DB_HOST . «; dbname https://i.imgur.com/VEIKbp0.png»)
‘product_name’ => ‘MANAGED KUBERNETES’,
‘product_name’ => ‘MySQL DATABASES’,
$sql = «INSERT INTO products(product_name, price, product_image) VALUES (:product_name, :price, :product_image)»;
foreach ($products as $product)
echo «Records inserted successfully»;
Сохраните и закройте файл.
Этот файл нужен для определения переменных базы данных и подключения к ней. Файл также инициирует объект PDO и сохраняет его в переменной $pdo. Мы ссылаемся на файл config.php вверху.
Затем мы создали массив данных о товарах, которые нужно вставить в БД. Помимо product_name и price, которые заданы в виде строк и числовых значений соответственно, сценарий использует встроенную функцию PHP file_get_contents для чтения изображений из внешнего источника и передачи их в виде строк в столбец product_image.
После этого мы подготовили оператор SQL и использовали оператор PHP foreach для вставки каждого продукта в базу данных.
Запустите /var/www/html/insert_products.php в окне браузера, используя следующий URL-адрес (не забудьте заменить your-server-IP внешним IP-адресом сервера):
На экране вы увидите сообщение об успешном выполнении файла – следовательно, записи были вставлены в базу данных.
Records inserted successfully
Итак, мы успешно вставили три записи, содержащие изображения товаров, в таблицу. На следующем этапе мы напишем сценарий PHP для извлечения этих записей и отображения их в браузере.
3: Извлечение и визуализация данных из БД MySQL
Имея в базе данных информацию и изображения товаров, вы можете написать второй сценарий PHP, который будет запрашивать и отображать данные в таблице HTML в браузере.
Чтобы создать файл, введите:
sudo nano /var/www/html/display_products.php
Затем вставьте в файл следующее:
$sql = «SELECT * FROM products»;
Руководство. Использование хранилища BLOB-объектов Azure с SQL Server
В этом руководстве показано, как использовать хранилище BLOB-объектов Azure для файлов данных и резервных копий в SQL Server 2016 и более поздних версиях.
Поддержка интеграции SQL Server для хранилища BLOB-объектов Azure началась в качестве усовершенствования с пакетом обновления 1 (SP1) с пакетом обновления 1 (SP2) SQL Server 2014 и SQL Server 2016. Обзор возможностей и преимуществ использования этих функций см. в статье Файлы данных SQL Server в Microsoft Azure.
В этом руководстве в нескольких разделах показано, как работать с файлами данных SQL Server в Хранилище BLOB-объектов Azure. В каждом разделе рассматривается определенная задача, и их следует выполнять по порядку. Сначала вы узнаете, как создать контейнер в Хранилище BLOB-объектов с помощью хранимой политики доступа и подписанного URL-адреса. Затем вы узнаете, как создать учетные данные SQL Server, чтобы интегрировать SQL Server с Хранилищем BLOB-объектов Azure. Далее вы выполните резервное копирование базы данных в Хранилище BLOB-объектов и восстановите ее в виртуальной машине Azure. Затем вы будете использовать резервную копию журнала транзакций моментального снимка файлов SQL Server для восстановления до точки во времени и в новую базу данных. Наконец, в учебнике будет продемонстрировано использование хранимых процедур и функций системы метаданных, что позволит вам понять, как работать с резервными копиями моментальных снимков файлов.
Предварительные условия
Для работы с этим руководством необходимо ознакомиться с понятиями резервного копирования и восстановления SQL Server и синтаксисом T-SQL.
Чтобы использовать это руководство, вам потребуется учетная запись хранения Azure, СРЕДА SQL Server Management Studio (SSMS), доступ к экземпляру локальной среды SQL Server, доступ к виртуальной машине Azure под управлением экземпляра SQL Server 2016 или более поздней версии и AdventureWorks2022 базы данных. Кроме того, учетная запись, используемая для выдачи команд резервного копирования и восстановления, должна находиться в роли базы данных db_backupoperator с разрешениями изменение любых учетных данных.
- Получите бесплатную учетную запись Azure.
- Создайте учетную запись хранения Azure.
- Установите выпуск SQL Server 2017 Developer Edition.
- Подготовка виртуальной машины Azure под управлением SQL Server
- Установите SQL Server Management Studio.
- Скачайте примеры баз данных AdventureWorks.
- Назначьте учетной записи пользователя роль db_backupoperator и предоставьте разрешения на изменение любых учетных данных.
SQL Server не поддерживает Azure Data Lake Storage, убедитесь, что иерархическое пространство имен не включено в учетной записи хранения, используемой для этого руководства.
1. Создание хранимой политики доступа и хранилища с общим доступом
В этом разделе описан сценарий Azure PowerShell для создания подписанного URL-адреса в контейнере хранилища BLOB-объектов Azure с помощью хранимой политики доступа.
Этот скрипт написан с помощью Azure PowerShell 5.0.10586.
Подписанный URL-адрес — это универсальный код ресурса (URI), который предоставляет ограниченные права доступа к контейнерам, большим двоичным объектам, очередям и таблицам. Хранимая политика доступа предоставляет дополнительный уровень контроля над сервером, включая отзыв, истечение срока действия и продление доступа. При использовании этого расширения необходимо создать политику в контейнере как минимум с правами на чтение, запись и перечисление.
Хранимую политику доступа и подписанный URL-адрес можно создать с помощью Azure PowerShell, пакета SDK службы хранилища Azure, REST API Azure или служебной программы стороннего разработчика. В этом учебнике демонстрируется применение скрипта Azure PowerShell для выполнения данной задачи. В скрипте используется модель развертывания диспетчера ресурсов и создаются следующие ресурсы:
- Группа ресурсов
- Учетная запись хранения
- Контейнер хранилища BLOB-объектов Azure
- Политика SAS
Выполнение скрипта начинается с объявления ряда переменных для указания имен перечисленных выше ресурсов и имен следующих обязательных входных значений:
- имя префикса, используемое для именования других объектов ресурсов;
- Имя подписки
- расположение центра обработки данных.
В результате выполнения скрипта создается соответствующая инструкция CREATE CREDENTIAL, которая будет использоваться в разделе 2. Создание учетных данных SQL Server с помощью подписанного URL-адреса. Эта инструкция копируется в буфер обмена и выводится в консоль.
Чтобы создать политику в контейнере и создать подписанный URL-адрес (SAS), выполните следующие действия.
- Откройте интегрированную среду сценариев Window PowerShell или Windows PowerShell (см. требования к версии выше).
- Измените, а затем выполните приведенный ниже скрипт:
# Define global variables for the script $prefixName = '' # used as the prefix for the name for various objects $subscriptionID = '' # the ID of subscription name you will use $locationName = '' # the data center region you will use $storageAccountName= $prefixName + 'storage' # the storage account name you will create or use $containerName= $prefixName + 'container' # the storage container name to which you will attach the SAS policy with its SAS token $policyName = $prefixName + 'policy' # the name of the SAS policy # Set a variable for the name of the resource group you will create or use $resourceGroupName=$prefixName + 'rg' # Add an authenticated Azure account for use in the session Connect-AzAccount # Set the tenant, subscription and environment for use in the rest of Set-AzContext -SubscriptionId $subscriptionID # Create a new resource group - comment out this line to use an existing resource group New-AzResourceGroup -Name $resourceGroupName -Location $locationName # Create a new Azure Resource Manager storage account - comment out this line to use an existing Azure Resource Manager storage account New-AzStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName -Type Standard_RAGRS -Location $locationName # Get the access keys for the Azure Resource Manager storage account $accountKeys = Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName # Create a new storage account context using an Azure Resource Manager storage account $storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $accountKeys[0].Value # Creates a new container in Blob Storage $container = New-AzStorageContainer -Context $storageContext -Name $containerName # Sets up a Stored Access Policy and a Shared Access Signature for the new container $policy = New-AzStorageContainerStoredAccessPolicy -Container $containerName -Policy $policyName -Context $storageContext -StartTime $(Get-Date).ToUniversalTime().AddMinutes(-5) -ExpiryTime $(Get-Date).ToUniversalTime().AddYears(10) -Permission rwld # Gets the Shared Access Signature for the policy $sas = New-AzStorageContainerSASToken -name $containerName -Policy $policyName -Context $storageContext Write-Host 'Shared Access Signature= '$($sas.Substring(1))'' # Sets the variables for the new container you just created $container = Get-AzStorageContainer -Context $storageContext -Name $containerName $cbc = $container.CloudBlobContainer # Outputs the Transact SQL to the clipboard and to the screen to create the credential using the Shared Access Signature Write-Host 'Credential T-SQL' $tSql = "CREATE CREDENTIAL [] WITH IDENTITY='Shared Access Signature', SECRET=''" -f $cbc.Uri,$sas.Substring(1) $tSql | clip Write-Host $tSql # Once you're done with the tutorial, remove the resource group to clean up the resources. # Remove-AzResourceGroup -Name $resourceGroupName
2. Создание учетных данных SQL Server с помощью подписанного URL-адреса
В этом разделе вы создадите учетные данные для хранения сведений о безопасности, которые будут использоваться SQL Server для записи и чтения из контейнера хранилища BLOB-объектов Azure, созданного на предыдущем шаге.
Учетные данные SQL Server — это объект, который используется для хранения сведений, необходимых для проверки подлинности при подключении к ресурсу вне SQL Server. Учетные данные хранят URI-путь контейнера хранилища BLOB-объектов Azure и подписанный URL-адрес для этого контейнера.
Чтобы создать учетные данные SQL Server, выполните указанные ниже действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру SQL Server ядра СУБД в локальной среде.
- В новое окно запроса вставьте инструкцию CREATE CREDENTIAL с подписанным URL-адресом из раздела 1, а затем выполните этот скрипт. Код скрипта будет выглядеть следующим образом.
/* Example: USE master CREATE CREDENTIAL [https://msfttutorial.blob.core.windows.net/containername] WITH IDENTITY='SHARED ACCESS SIGNATURE' , SECRET = 'sharedaccesssignature' GO */ USE master CREATE CREDENTIAL [https://.blob.core.windows.net/] -- this name must match the container path, start with https and must not contain a forward slash at the end WITH IDENTITY='SHARED ACCESS SIGNATURE' -- this is a mandatory string and should not be changed , SECRET = 'sharedaccesssignature' -- this is the shared access signature key that you obtained in section 1. GO
SELECT * from sys.credentials
3. Резервное копирование базы данных по URL-адресу
В этом разделе описано, как создать AdventureWorks2022 резервную копию базы данных в экземпляре SQL Server, в контейнер, созданный в разделе 1.
Если вы хотите создать резервную копию базы данных SQL Server 2012 (11.x) с пакетом обновления 1 (SP1) или базы данных SQL Server 2014 (12.x) в этом контейнере, можно использовать устаревший синтаксис, описанный здесь , для резервного копирования по URL-адресу с помощью синтаксиса WITH CREDENTIAL .
Чтобы создать резервную копию базы данных в хранилище BLOB-объектов, выполните следующие действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру SQL Server в виртуальной машине Azure.
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окне запроса. Измените в URL-адресе имя учетной записи хранения и контейнер, которые вы указали ранее в разделе 1, а затем выполните этот скрипт.
-- To permit log backups, before the full database backup, modify the database to use the full recovery model. USE master; ALTER DATABASE AdventureWorks2022 SET RECOVERY FULL; -- Back up the full AdventureWorks2022 database to the container that you created in section 1 BACKUP DATABASE AdventureWorks2022 TO URL = 'https://.blob.core.windows.net//AdventureWorks2022_onprem.bak'
- Разверните контейнеры, разверните контейнер, созданный в разделе 1, и убедитесь, что резервная копия из шага 3 выше отображается в этом контейнере.

4. Восстановление базы данных на виртуальной машине по URL-адресу
В этом разделе вы восстановите AdventureWorks2022 базу данных в экземпляре SQL Server на виртуальной машине Azure.
В целях упрощения в этом учебнике для файлов данных и журналов применяется тот же контейнер, который использовался для резервной копии базы данных. В рабочей среде обычно используется несколько контейнеров, а также несколько файлов данных. Вы также можете рассмотреть возможность чередовать резервную копию по нескольким blob-объектам, чтобы повысить производительность резервного копирования при резервном копировании большой базы данных.
Чтобы восстановить AdventureWorks2022 базу данных из хранилища BLOB-объектов Azure в экземпляр SQL Server на виртуальной машине Azure, выполните следующие действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру SQL Server ядра СУБД на виртуальной машине Azure.
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окне запроса. Измените в URL-адресе имя учетной записи хранения и контейнер, которые вы указали ранее в разделе 1, а затем выполните этот скрипт.
-- Restore AdventureWorks2022 from URL to SQL Server instance using Azure Blob Storage for database files RESTORE DATABASE AdventureWorks2022 FROM URL = 'https://.blob.core.windows.net//AdventureWorks2022_onprem.bak' WITH MOVE 'AdventureWorks2022_data' to 'https://.blob.core.windows.net//AdventureWorks2022_Data.mdf' ,MOVE 'AdventureWorks2022_log' to 'https://.blob.core.windows.net//AdventureWorks2022_Log.ldf' --, REPLACE
- Щелкните правой кнопкой мыши AdventureWorks2022 и выберите «Свойства«.
- Выберите файлы и убедитесь, что пути для двух файлов базы данных являются URL-адресами, указывающими на большие двоичные объекты в контейнере хранилища BLOB-объектов Azure (нажмите кнопку «Отмена » при завершении).
] database on the Azure VM.](https://learn.microsoft.com/ru-ru/sql/relational-databases/media/tutorial-use-azure-blob-storage-service-with-sql-server-2016/adventureworks-on-azure-vm.png?view=sql-server-ver16)
- Разверните контейнеры, разверните контейнер, созданный в разделе 1, и убедитесь, что AdventureWorks2022_Data.mdf в этом контейнере отображается и AdventureWorks2022_Log.ldf из шага 3 выше, а также файл резервной копии из раздела 3 (при необходимости обновите узел).

5. Резервное копирование базы данных с помощью резервного копирования моментальных снимков файлов
В этом разделе описано, как создать AdventureWorks2022 резервную копию базы данных в виртуальной машине Azure с помощью резервного копирования моментальных снимков файлов для выполнения почти мгновенной резервной копии с помощью моментальных снимков Azure. Дополнительные сведения о резервных копиях моментальных снимков файлов см. в разделе Резервные копии моментальных снимков файлов для файлов базы данных в Azure.
Чтобы создать резервную копию базы данных с помощью резервного AdventureWorks2022 копирования моментальных снимков файлов, выполните следующие действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру SQL Server ядра СУБД на виртуальной машине Azure.
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окно запроса, а затем выполните его (не закрывайте окно запроса — этот скрипт необходимо будет выполнить еще раз на шаге 5). Эта системная хранимая процедура позволяет просмотреть существующие резервные копии моментальных снимков файлов для каждого файла, входящего в состав указанной базы данных. Обратите внимание на то, что для данной базы данных резервных копий моментальных снимков файлов нет.
-- Verify that no file snapshot backups exist SELECT * FROM sys.fn_db_backup_file_snapshots ('AdventureWorks2022');
-- Backup the AdventureWorks2022 database with FILE_SNAPSHOT BACKUP DATABASE AdventureWorks2022 TO URL = 'https://.blob.core.windows.net//AdventureWorks2022_Azure.bak' WITH FILE_SNAPSHOT;
-- Verify that two file-snapshot backups exist SELECT * FROM sys.fn_db_backup_file_snapshots ('AdventureWorks2022');

6. Создание действия и журнала резервного копирования с помощью резервного копирования моментальных снимков файлов
В этом разделе описано, как создать действия в AdventureWorks2022 базе данных и периодически создавать резервные копии журналов транзакций с помощью резервных копий моментальных снимков файлов. Дополнительные сведения об использовании резервных копий моментальных снимков файлов см. в разделе Резервные копии моментальных снимков файлов для файлов базы данных в Azure.
Чтобы создать действия в AdventureWorks2022 базе данных и периодически создавать резервные копии журналов транзакций с помощью резервных копий моментальных снимков файлов, выполните следующие действия.
- Запустите среду SSMS.
- Откройте два новых окна запросов и подключите каждый экземпляр SQL Server ядра СУБД в виртуальной машине Azure.
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в одно из окон запросов, а затем выполните этот скрипт. Обратите внимание, что в Production.Location таблице есть 14 строк, прежде чем добавлять новые строки на шаге 4.
-- Verify row count at start SELECT COUNT (*) from AdventureWorks2022.Production.Location;
-- Insert 30,000 new rows into the Production.Location table in the AdventureWorks2022 database in batches of 75 DECLARE @count INT=1, @inner INT; WHILE @count < 400 BEGIN BEGIN TRAN; SET @inner =1; WHILE @inner
--take 7 transaction log backups with FILE_SNAPSHOT, one per minute, and include the row count and the execution time in the backup file name DECLARE @count INT=1, @device NVARCHAR(120), @numrows INT; WHILE @count .blob.core.windows.net//tutorial-' + CONVERT (varchar(10),@numrows) + '-' + FORMAT(GETDATE(), 'yyyyMMddHHmmss') + '.bak'; BACKUP LOG AdventureWorks2022 TO URL = @device WITH FILE_SNAPSHOT; SELECT * from sys.fn_db_backup_file_snapshots ('AdventureWorks2022'); WAITFOR DELAY '00:1:00'; SET @count = @count + 1; END;



7. Восстановление базы данных на момент времени
В этом разделе вы восстановите AdventureWorks2022 базу данных до точки во времени между двумя резервными копиями журнала транзакций.
Чтобы выполнить восстановление на определенный момент времени из традиционных резервных копий, потребуется полная резервная копия базы данных, возможно, разностная резервная копия и все файлы журналов транзакций вплоть до того момента, на который необходимо выполнить восстановление, и сразу после него. При использовании резервных копий моментальных снимков файлов требуются только два ближайших файла резервных копий журнала с обеих сторон от целевой точки восстановления. Требуются только два резервных набора моментальных снимков файлов, так как каждая операция резервного копирования журнала создает моментальный снимок каждого файла базы данных (то есть файла данных и файла журнала).
Чтобы восстановить базу данных на определенный момент времени из резервных наборов моментальных снимков файлов, выполните указанные ниже действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру SQL Server ядра СУБД на виртуальной машине Azure.
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окно запроса, а затем выполните его. Убедитесь, что Production.Location таблица содержит 29 939 строк, прежде чем восстановить ее до точки во времени, когда на шаге 4 меньше строк.
-- Verify row count at start SELECT COUNT (*) from AdventureWorks2022.Production.Location

Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окне запроса. Выберите два смежных файла резервных копий журнала и укажите вместо их имен дату и время, требуемые для этого скрипта. В URL-адресе измените имя учетной записи хранения и контейнер, которые вы указали в разделе 1, укажите имена файлов для первой и второй резервных копий, укажите время STOPAT в формате "June 26, 2018 01:48 PM" (26 июня, 2018 13:48), а затем выполните этот скрипт. Выполнение скрипта займет несколько минут.
-- restore and recover to a point in time between the times of two transaction log backups, and then verify the row count ALTER DATABASE AdventureWorks2022 SET SINGLE_USER WITH ROLLBACK IMMEDIATE; RESTORE DATABASE AdventureWorks2022 FROM URL = 'https://.blob.core.windows.net//.bak' WITH NORECOVERY,REPLACE; RESTORE LOG AdventureWorks2022 FROM URL = 'https://.blob.core.windows.net//.bak' WITH RECOVERY, STOPAT = 'June 26, 2018 01:48 PM'; ALTER DATABASE AdventureWorks2022 set multi_user; -- get new count SELECT COUNT (*) FROM AdventureWorks2022.Production.Location ;

8. Восстановление новой базы данных из резервной копии журнала
В этом разделе вы восстановите AdventureWorks2022 базу данных в качестве новой базы данных из резервной копии журнала транзакций моментального снимка файлов.
В этом сценарии вы восстановите базу данных в экземпляре SQL Server на другой виртуальной машине, предназначенной для бизнес-анализа и создания отчетов. Восстановление в другом экземпляре, размещенном в другой виртуальной машине, позволяет перенести нагрузку на выделенную виртуальную машину, специально предназначенную для этой цели, и снизить требования к ресурсам, предъявляемые к системе обработки транзакций.
Восстановление из резервной копии журнала транзакций, созданной посредством резервного копирования моментальных снимков файлов, выполняется очень быстро — существенно быстрее, чем при использовании традиционных потоковых резервных копий. В случае с традиционными потоковыми резервными копиями вам потребовалось бы использовать полную резервную копию базы данных, а также, возможно, разностную резервную копию и все или часть резервных копий журнала транзакций (либо новую полную резервную копию базы данных). При использовании же резервных копий журнала на основе моментальных снимков файлов требуется только самая последняя резервная копия журнала (либо любая другая резервная копия журнала, либо две смежные резервные копии журнала для восстановления на определенный момент времени). Если точнее, требуется только один резервный набор моментальных снимков файлов, так как каждая операция резервного копирования журнала с помощью моментальных снимков файлов создает моментальный снимок каждого файла базы данных (то есть файла данных и файла журнала).
Чтобы выполнить восстановление в новую базу данных из резервной копии журнала транзакций, созданной посредством резервного копирования моментальных снимков файлов, выполните указанные ниже действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру ЯДРА СУБД SQL Server в виртуальной машине Azure.
Заметка Если это не та виртуальная машина Azure, которую вы использовали в предыдущих разделах, выполните инструкции из раздела 2. Создание учетных данных SQL Server с помощью подписанного URL-адреса. Если вы хотите восстановить данные в другой контейнер, выполните для нового контейнера действия из раздела 1. Создание хранимой политики доступа и хранилища с общим доступом.
-- restore as a new database from a transaction log backup file RESTORE DATABASE AdventureWorks2022_EOM FROM URL = 'https://.blob.core.windows.net//' WITH MOVE 'AdventureWorks2022_data' to 'https://.blob.core.windows.net//AdventureWorks2022_EOM_Data.mdf' , MOVE 'AdventureWorks2022_log' to 'https://.blob.core.windows.net//AdventureWorks2022_EOM_Log.ldf' , RECOVERY --, REPLACE

9. Управление резервными наборами данных и резервными копиями моментальных снимков файлов
В этом разделе описано, как удалить резервный набор с помощью хранимой процедуры sp_delete_backup (Transact-SQL ). Эта процедура удаляет файл резервной копии и моментальный снимок файла для каждого файла базы данных, связанного с резервным набором данных.
Если вы пытаетесь удалить резервный набор, просто удалив файл резервной копии из контейнера хранилища BLOB-объектов Azure, то будет удален только сам файл резервной копии. Связанные моментальные снимки файлов останутся. Если вы найдете себя в этом сценарии, используйте системную функцию sys.fn_db_backup_file_snapshots (Transact-SQL), чтобы определить URL-адрес моментальных снимков потерянных файлов и использовать хранимую процедуру sp_delete_backup_file_snapshot (Transact-SQL), чтобы удалить каждый потерянный моментальный снимок файла. Дополнительные сведения см. в разделе Резервные копии моментальных снимков файлов для файлов базы данных в Azure.
Чтобы удалить резервный набор моментальных снимков файлов, выполните указанные ниже действия.
- Запустите среду SSMS.
- Откройте новое окно запроса и подключитесь к экземпляру ядра СУБД SQL Server в виртуальной машине Azure (или к любому экземпляру SQL Server с разрешениями на чтение и запись в этом контейнере).
- Скопируйте и вставьте приведенный ниже скрипт Transact-SQL в окне запроса. Выберите резервную копию журнала, которую нужно удалить вместе со связанными моментальными снимками файлов. В URL-адресе измените имя учетной записи хранения и контейнер, которые вы указали в разделе 1, укажите имя файла резервной копии журнала, а затем выполните этот скрипт.
sys.sp_delete_backup 'https://.blob.core.windows.net//tutorial-21764-20181003205236.bak';

-- verify that two file snapshots have been removed SELECT * from sys.fn_db_backup_file_snapshots ('AdventureWorks2022');
10. Удаление ресурсов
Когда вы закончите работу с этим руководством, не забудьте в целях экономии ресурсов удалить группу ресурсов, созданную в этом руководстве.
Чтобы удалить группу ресурсов, выполните следующий код PowerShell:
# Define global variables for the script $prefixName = '' # should be the same as the beginning of the tutorial # Set a variable for the name of the resource group you will create or use $resourceGroupName=$prefixName + 'rg' # Adds an authenticated Azure account for use in the session Connect-AzAccount # Set the tenant, subscription and environment for use in the rest of Set-AzContext -SubscriptionId $subscriptionID # Remove the resource group Remove-AzResourceGroup -Name $resourceGroupName
Далее
- Файлы данных SQL Server в Microsoft Azure
- Резервные копии моментальных снимков файлов базы данных в Azure
- Резервное копирование SQL Server в указанное расположение.
- Использование подписанных URL-адресов (SAS)
- Create Container
- Set Container ACL
- Get Container ACL
- Учетные данные (ядро СУБД)
- CREATE CREDENTIAL (Transact-SQL)
- sys.credentials (Transact-SQL)
- sp_delete_backup (Transact-SQL)
- sys.fn_db_backup_file_snapshots (Transact-SQL)
- sp_delete_backup_file_snapshot (Transact-SQL)
- Резервные копии моментальных снимков файлов базы данных в Azure
Общие сведения о страничных BLOB-объектах Azure
Служба хранилища Azure предлагает три типа хранилища BLOB-объектов: блочные, добавочные и страничные BLOB-объекты. Блочные BLOB-объекты состоят из блоков и идеально подходят для хранения текстовых или двоичных файлов, а также для эффективной передачи больших файлов. Добавочные большие двоичные объекты также состоят из блоков, но они оптимизированы для операций добавления и поэтому полезны для сценариев ведения журнала. Страничные BLOB-объекты состоят из 512-байтовых страниц, общий размер которых не превышает 8 ТБ, и создаются для частых произвольных операций чтения и записи. Страничные BLOB-объекты являются основой дисков IaaS Azure. В этой статье рассматриваются возможности и преимущества страничных BLOB-объектов.
Страничные BLOB-объекты — это коллекция 512-байтовых страниц, которые предоставляют возможность чтения и записи произвольных диапазонов байтов. Таким образом, страничные BLOB-объекты идеально подходят для хранения структур данных на основе индексов и разреженных структур данных, таких как диски ОС и диски данных для виртуальных машин и баз данных. Например, в базе данных SQL Azure страничные BLOB-объекты используются в качестве базового постоянного хранилища для баз данных. Более того, страничные BLOB-объекты также часто используются для файлов с обновлениями на основе диапазонов.
Основные возможности страничных BLOB-объектов Azure: интерфейс REST, устойчивость базового хранилища и возможности эффективной миграции в Azure. Подробнее эти возможности рассматриваются в следующем разделе. Кроме того, страничные BLOB-объекты Azure сейчас поддерживаются в хранилищах двух типов: класса Premium и Standard. Хранилище класса Premium разработано специально для рабочих нагрузок, требующих постоянной высокой производительности и минимальных задержек, благодаря чему страничные BLOB-объекты класса Premium идеально подходят для сценариев с высокими требованиями к производительности хранилища. Хранилище класса Standard более выгодно использовать для рабочих нагрузок без особых требований к задержкам.
Ограничения
Страничные BLOB-объекты могут использовать только горячий уровень доступа, но не холодный или архивный. Дополнительные сведения об уровнях доступа см. в статье Горячий, холодный и архивный уровни доступа к данным BLOB-объектов.
Примеры вариантов использования
Рассмотрим несколько вариантов использования страничных BLOB-объектов, начиная с дисков IaaS Azure. Страничные BLOB-объекты Azure — это основа платформы виртуальных дисков IaaS Azure. Диски ОС и диски данных Azure реализуются как виртуальные диски, где данные надежно хранятся на платформе службы хранилища Azure, а затем доставляются на виртуальные машины для достижения максимальной производительности. Диски Azure хранятся в формате VHD Hyper-V и в виде страничного BLOB-объекта в службе хранилища Azure. Помимо использования виртуальных дисков для виртуальных машин IaaS Azure, страничные BLOB-объекты также поддерживают сценарии PaaS и DBaaS, например службу базы данных SQL Azure, в которой сейчас эти объекты используются для хранения данных SQL, обеспечивая выполнение произвольных операций чтения и записи для базы данных. Еще один пример: при использовании службы PaaS для общего доступа к мультимедиа для приложений совместного редактирования видео страничные BLOB-объекты обеспечивают быстрый доступ к произвольным расположениям в мультимедиа. Они также предоставляют возможность нескольким пользователям быстро и эффективно редактировать и объединять одно и то же мультимедиа.
Корпорация Майкрософт в своих основных службах, таких как Azure Site Recovery и Azure Backup, а также многие сторонние разработчики реализовали ведущие в отрасли инновационные возможности с помощью интерфейса REST страничного BLOB-объекта. Ниже приведены уникальные сценарии, реализованные в Azure.
- Управление добавочными моментальными снимками, направляемыми приложением. С помощью моментальных снимков страничного BLOB-объекта и интерфейсов REST API приложения могут сохранять контрольные точки приложения без дорогостоящего дублирования данных. Служба хранилища Azure поддерживает локальные моментальные снимки для страничных BLOB-объектов, для которых не требуется копирование всего BLOB-объекта. Общедоступные API-интерфейсы этих моментальных снимков также обеспечивают доступ к разностным данным между моментальными снимками и их копирование.
- Динамическая миграция приложения и данных из локального расположения в облако. Скопируйте локальные данные и запишите их в страничный BLOB-объект Azure через REST API, не прерывая работу виртуальной машины в локальной среде. После этого вы можете быстро выполнить отработку отказа на виртуальную машину Azure с использованием этих данных. Таким образом можно перенести виртуальные машины и виртуальные диски из локального расположения в облако с минимальным простоем, так как перенос данных происходит в фоновом режиме, а вы продолжаете использовать виртуальную машину. Простой при отработке отказа составит всего несколько минут.
- Общий доступ на основе SAS, который позволяет выполнять сценарии, такие как несколько читателей и один писатель с поддержкой управления параллелизмом.
Неуправляемые диски удаляются из эксплуатации. Дополнительные сведения см. в статье Перенос неуправляемых дисков Azure до 30 сентября 2025 г.
Цены
Два типа хранилища, предоставляемые для страничных BLOB-объектов, имеют разные модели ценообразования. Страничные BLOB-объекты уровня Premium оплачиваются так же, как управляемые диски, но страничные BLOB-объекты уровня Standard тарифицируются пропорционально используемому размеру и за каждую транзакцию. Дополнительные сведения см. на странице цен на страничные BLOB-объекты Azure.
Возможности страничных BLOB-объектов
REST API
Чтобы приступить к разработке с использованием страничных BLOB-объектов, см. статью Краткое руководство по передаче, скачиванию и составлению списка больших двоичных объектов с помощью .NET. Например, рассмотрим получение доступа к страничным BLOB-объектам с помощью клиентской библиотеки хранилища для .NET.
На следующей схеме изображены общие связи между учетной записью, контейнерами и страничными BLOB-объектами.

Создание пустого страничного BLOB-объекта указанного размера
Сначала получите ссылку на контейнер. Чтобы создать страничный BLOB-объект, вызовите метод GetPageBlobClient, а затем метод PageBlobClient.Create. Передайте в него максимальный размер создаваемого большого двоичного объекта. Этот размер должен быть кратен 512 байтам.
long OneGigabyteAsBytes = 1024 * 1024 * 1024; BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); var blobContainerClient = blobServiceClient.GetBlobContainerClient(Constants.containerName); var pageBlobClient = blobContainerClient.GetPageBlobClient("0s4.vhd"); pageBlobClient.Create(16 * OneGigabyteAsBytes);
Изменение размера страничного BLOB-объекта
Чтобы изменить размер страничного BLOB-объекта после его создания, используйте метод Resize. Запрошенный размер должен быть кратен 512 байтам.
pageBlobClient.Resize(32 * OneGigabyteAsBytes);
Запись страниц в страничный BLOB-объект
Чтобы сохранить страницы, используйте метод PageBlobClient.UploadPages.
pageBlobClient.UploadPages(dataStream, startingOffset);
Это позволит записать последовательный набор страниц размером до 4 МБ. Записываемое смещение должно начинаться на границе 512 байт (startingOffset % 512 == 0), а заканчиваться на границе 512 — 1.
Как только запрос на запись последовательного набора страниц успешно выполняется в службе BLOB-объектов и реплицируется для обеспечения устойчивости, запись фиксируется и клиенту отправляется уведомление о том, что запись завершена успешно.
На схеме ниже показано 2 отдельных операции записи:

- Операция записи, начинающаяся со смещения 0 длиной 1024 байт
- Операция записи, начинающаяся со смещения 4096 длиной 1024 байт
Чтение страниц из страничного BLOB-объекта
Чтобы считать страницы, используйте метод PageBlobClient.Download, который получает диапазон байтов из страничного BLOB-объекта.
var pageBlob = pageBlobClient.Download(new HttpRange(bufferOffset, rangeSize));
Это даст возможность загрузить весь большой двоичный объект или диапазон байтов, начиная со смещения в большом двоичном объекте. При чтении смещение не должно начинаться с величины, кратной 512. При чтении байтов со страницы NUL служба возвращает нулевые байты.
На следующем рисунке показана операция чтения со смещением 256 и размером диапазона 4352. Возвращенные данные выделены оранжевым цветом. Для страниц NUL возвращаются нули.

Если большой двоичный объект является фрагментарным, возможно, потребуется загружать только значимые области страницы. Это позволит не оплачивать передачу нулевых байтов и сократить задержку при загрузке.
Чтобы определить, для каких страниц присутствуют данные, используйте метод PageBlobClient.GetPageRanges. Вы можете перечислить возвращаемые диапазоны и загрузить данные в каждом диапазоне.
IEnumerable pageRanges = pageBlobClient.GetPageRanges().Value.PageRanges; foreach (var range in pageRanges)
Сдача страничного BLOB-объекта в аренду
Операция сдачи большого двоичного объекта в аренду устанавливает блокировку на большом двоичном объекте для операций записи и удаления, а также управляет ею. Эта операция полезна, если к страничному BLOB-объекту осуществляется доступ из нескольких клиентов. При ее применении запись в большой двоичный объект в текущий момент может осуществляться только одним клиентом. К примеру, в дисках Azure этот механизм сдачи в аренду используется, чтобы управление диском осуществлялось только с одной виртуальной машины. Длительность блокировки может составлять 15–60 секунд либо быть бесконечной. Дополнительные сведения см. в этой документации.
Помимо разнообразных интерфейсов REST API, страничные BLOB-объекты обеспечивают общий доступ, устойчивость и повышенную безопасность. Далее мы рассмотрим эти преимущества подробнее.
Одновременный доступ
REST API страничного BLOB-объекта и его механизм сдачи в аренду позволяет приложениям получать доступ к страничному BLOB-объекту из нескольких клиентов. Например, предположим, что нужно создать распределенную облачную службу, которая использует объекты хранилища совместно с несколькими пользователями. Это может быть веб-приложение, обслуживающее большую коллекцию изображений для нескольких пользователей. Один из вариантов для реализации — использование виртуальной машины с подключенными дисками. К недостаткам этого относится (а) ограничение подключения диска только к одной виртуальной машине, что уменьшает масштабируемость, гибкость и повышает риски. Если возникла проблема с виртуальной машиной или службой, запущенной на виртуальной машине, по истечении срока действия аренды или ее разрыва образ будет недоступен. Кроме того, требуются дополнительные затраты на виртуальную машину IaaS.
Альтернативным вариантом является использование страничных BLOB-объектов напрямую через интерфейсы REST API службы хранилища Azure. Этот вариант не требует использования дорогостоящих виртуальных машин IaaS, предоставляет гибкие возможности прямого доступа из нескольких клиентов, упрощает классическую модель развертывания (так как не нужно подключать и отключать диски) и исключает риски возникновения проблем на виртуальной машине. И обеспечивается тот же уровень производительности для произвольных операций чтения и записи, что и на диске.
Высокая доступность и устойчивость
Хранилище уровня "Стандартный" и "Премиум" — это надежное хранилище, в котором данные страничных BLOB-объектов всегда реплицируются для обеспечения устойчивости и высокой доступности. Azure постоянно обеспечивает устойчивость корпоративных уровней для дисков IaaS и страничных BLOB-объектов с ведущим в отрасли нулевым процентом ежегодных сбоев.
Дополнительные сведения об избыточности службы хранилища Azure для учетных записей хранения уровня "Стандартный" и "Премиум" см. в статье Избыточность службы хранилища Azure и в следующих двух разделах:
- Поддерживаемые службы хранилища Azure
- Поддерживаемые типы учетных записей хранения
Простая миграция в Azure
Для клиентов и разработчиков, заинтересованных в реализации своего собственного пользовательского решения резервного копирования, Azure также предлагает добавочные моментальные снимки, которые содержат только разностные данные. Эта возможность позволяет избежать затрат на начальную полную копию, что значительно снижает расходы на резервное копирование. Помимо возможности эффективно считывать и копировать разностные данные есть другая эффективная возможность, которая помогает внедрить еще больше инноваций от разработчиков, обеспечивая лучшие в своем классе резервное копирование и аварийное восстановление. Вы можете настроить свое собственное решение резервного копирования или аварийного восстановления для виртуальных машин в Azure, используя моментальные снимки больших двоичных объектов, интерфейс API Get Page Ranges и интерфейс API Incremental Copy Blob, с помощью которого можно легко копировать добавочные данные для аварийного восстановления.
Кроме того, во многих предприятиях важные рабочие нагрузки уже запущены в центрах обработки данных в локальной среде. При переносе рабочей нагрузки в облако одной из основных проблем является время простоя, необходимое для копирования данных, и риск возникновения других непредвиденных проблем после переключения. Во многих случаях простой может быть препятствием для миграции в облако. Используя REST API страничных BLOB-объектов, Azure устраняет эту проблему, обеспечивая перенос в облако с минимальными нарушениями работы важных рабочих нагрузок.
Примеры создания моментального снимка и восстановления страничного BLOB-объекта из моментального снимка см. в статье о настройке процесса резервного копирования с помощью добавочных моментальных снимков.
Операции над BLOB данными
Interbase поддерживает следующие операции над BLOB данными:
- Чтение из BLOB.
- Вставка новой строки включающей BLOB данные
- Замена данных ссылающихся на BLOB столбец.
- Обновление данных ссылающихся на BLOB столбец.
- Удаление BLOB.
API Функции динамического SQL (DSQL) и структура данных XSQLD A необходимы, чтобы выполнить SELECT, INSERT, и инструкции UPDATE, требующиеся, чтобы выбирать, вставлять, или модифицировать уместные данные Blob.
6.1.Чтение данных из BLOB.
Эти шесть шагов требуются для чтения данных из существующего BLOB:
1. Создается обычная инструкция SELECT для выбора строки содержащей BLOB столбец.
2. Подготавливается структура для вывода данных XSQLDA.
3. Подготавливается SELECT инструкция.
4. Выполняется инструкция.
5. Выбираем строки одну задругой
6. Читаем и обрабатываем BLOB данные для каждой строки.
Опишем все это подробнее, для непонимающих.
6.2.Создание SELECT инструкции
"SELECT PROJ_NAME, PROJ_DESC, PRODUCT FROM PROJECT WHERE \
PRODUCT IN ("software", "hardware","other") ORDER BY PROJ_NAME";
Подготовка структуры вывода XSQLDA
1. Объявляем переменную содержащую XSQLDA
2. Выделяем память
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(3));
3.Ставим версию и число выходных параметров
Подготовка SELECT инструкции для выполнения
После создания XSQLDA для содержания данных столбцов каждой выбранной строки,
Строку инструкции нужно подготовить к выполнению.
1. Объявляем и инициализируем дескриптор SQL инструкции,
с помощью известной нам функции isc_dsql_allocate_statement():
isc_stmt_handle stmt; /*Объявление дескриптора инструкции */
stmt = NULL; /* Установка дескриптора в NULL перед выполнением */
3. Подготавливаем строку для выполнения с помощью isc_dsql_prepare(),которая проверяет строку(str) на синтаксические ошибки, переводит строку в формат для эффективного выполнения, и устанавливает в дескриптор инструкции (stmt) ссылку на этот созданный формат (blr что ли). Дескриптор инструкции используется позднее в функции isc_dsql_execute().
Если isc_dsql_prepare()передан указатель на XSQLDA вывода, как в следующем примере, она будет заполнять большинство полей в XSQLDA и всех подструктур XSQLVAR информацией о типа данных, длине, и имени столбца в инструкции.
Пример вызова isc_dsql_prepare():
&trans, /* Устанавливается предварительным вызовом isc_start_transaction()*/
&stmt, /*Дескриптор инструкции устанавливается в вызове этой функции. */
0, /* Определяет что инструкция- строка заканчивается 0*/
str, /* Инструкция - строка */
SQLDA_VERSION1,/* Номер версии XSQLDA */
out_sqlda /* XSQLDA для хранения данных столбцов после выполнения инструкции */
3. Устанавливаем XSQLVAR структуру для каждого столбца:
- Определяем тип столбца ( если он не был установлен isc_dsql_prepare())
- Связываем указатель структуры XSQLVAR sqldata с соответствующей локальной переменной.
Для столбцов чьи типы неизвестных этому моменту:
Приводим элементы типа данных(необязательно), к примеру, из SQL_VARYING к SQL_TEXT.
Динамически выделяем место для хранения данных на которые указывает sqldata
- Определяем число байт данных передаваемых в sqldata
- Предоставляем значение NULL индикатора для параметров
Выбранные данные для Blob (и массивов)столбцов отличаются от других типов столбцов, так что поля XSQLVAR должны быть установлены по-другому. Для не -BLOB (и не массивов) столбцов, isc_dsql_prepare () устанавливают для каждый sqltype к соответствующему типу поля, и выбранные данные помещаются в область памяти на которую указывают соответствующие sqldata, при каждой операции fetch. Для столбцов Blob, тип должен быть установлен в SQL _Blob (или SQL _Blob + 1, если нужен индикатор NULL). InterBase сохраняет внутренний идентификатор Blob (BlobID), а не данные Blob, в памяти на которую кажет sqldata, когда строки данных выбраны, так что sqldata должна указывать на память с размером нужным для хранения BlobID.
Следующий пример кода иллюстрирует назначения для Blob и столбцов не-Blob, чей тип известен ко времени компиляции.
#define PROJLEN 20
#define TYPELEN 12
char proj_name[PROJLEN + 1];
char prod_type[TYPELEN + 1];
short flag0, flag1, flag2;
out_sqlda->sqlvar[0].sqltype = SQL_TEXT + 1;
out_sqlda->sqlvar[1].sqltype = SQL_Blob + 1;
out_sqlda->sqlvar[2].sqltype = SQL_TEXT + 1;
Выполнение инструкции
После того как инструкция подготовлена можно ее выполнить.
&trans, /* Устанавливается предварительным вызовом isc_start_transaction()*/
&stmt, /* выделяется isc_dsql_allocate_statement() */
1, /* XSQLDA version number */
NULL/* NULL так как нет входных параметров */
Эта инструкция создает список выбора, это строки возвращаемые после выполнения инструкции.
6.2.Извлечение выбранных строк
Конструкция цикла извлечения используется, чтобы извлечь(в XSQLDA вывода) данные столбцов для отдельной строки из списка выбора и обработать каждую строку прежде, чем следующая строка будет выбрана. Каждое выполнение isc_dsql_fetch () выбирает данные столбцов соответствующие подструктуры XSQLVAR структуры out_sqlda. Для столбца Blob, выбирается BlobID не являющийся фактическими данными, а просто указатель на них.
isc_dsql_fetch(status_vector, &stmt,1, out_sqlda))
printf("\nPROJECT: %–20s TYPE:%–15s\n\n",
/* Read and process the Blob data (seenext section) */
if (fetch_stat != 100L)
/* isc_dsql_fetch returns 100 if no morerows remain to be
Чтение и обработка BLOB данных
Для чтения и обработки BLOB данных
Объявите и инициализируйте BLOB дескриптор
isc_blob_handle blob_handle; /* Объявление BLOB дескриптора. */
blob_handle= NULL; /* Уставите его в NULL перед использованием*/
Создайте буфер для хранения каждого прочитанного BLOB сегмента. Его размер должен быть максимальным размером сегмента в вашей программе используемой для чтения BLOB.
3. Объявите беззнаковую short переменную в которую IB будет хранить фактическую длину каждого прочитанного сегмента:
unsigned short actual_seg_len;
4. Открываем BLOB c извлеченным ранее blob_id
&blob_handle,/*Устанавливается этой функцией для ссылки на BLOB */
&blob_id,/* Blob ID полученный из out_sqlda которую заполнил isc_dsql_fetch() */
0,/* BPB length = 0; фильтр не будем использовать */
NULL/* NULL BPB, фильтр не будем использовать */
5.Читаем все BLOB данные вызывая повторно isc_get_segment(), берущую каждый Blob сегмент и его длину. Обрабатываем каждый прочитаны сегмент.
&blob_handle, /* Устанавливается isc_open_blob2()*/
&actual_seg_len,/* Длина прочитанного сегмента */
sizeof(blob_segment),/* Длина буфера сегмента */
blob_segment/* буфер сегмента */
while (blob_stat == 0 ||status_vector[1] == isc_segment)
/*isc_get_segment возвращает 0 если сегмент был полностью прочитан.
/*status_vector[1] устанавливается в isc_segment только часть */
/*сегмента была прочитана из-за буфера (blob_segment) не являющегося */
/*достаточно большим. В этом случае придется делать дополнительные вызовы */
/*isc_get_segment() для дочитывания. */
printf("%*.*s",actual_seg_len, actual_seg_len, blob_segment);
blob_stat =isc_get_segment(status_vector, &blob_handle,
6. Закрываем BLOB
6.2.Запись данных в BLOB
Перед тем как создать новый BLOB и записать туда данные вы должны сделать следующее.
Включить BLOB данные в строку вставляемую в таблицу
Заменить данные ссылающиеся на BLOB столбец строки
Обновить данные ссылающиеся на BLOB столбец строки
Вносимый в столбец Blob фактически не содержит данных Blob. Он содержит BlobID ссылающийся на данные, которые сохранены в другом месте. Так, чтобы установить или изменить столбец Blob, Вы должны установить (или сбросить) BlobID, сохраненный в нем. Если столбец Blob содержит BlobID, и Вы изменяете столбцы относящиеся к различным Blob (или содержащим NULL), Blob на который ссылается предварительно сохраненный BlobID будет удален в течение следующей сборки "мусора".(. )
Все эти операции требуют следующих шагов:
1. Подготовьте соответствующую инструкцию DSQL. Это будет инструкция INSERT, если Вы вставляете новую строку в таблицу, или инструкция UPDATE для изменения строки. Каждая из этих инструкций будет нуждаться в соответствующей структуре ввода XSQLDA для передачи параметров инструкции во время выполнения. BlobID нового Blob будет одним переданных значений
2. Создайте новый BLOB, и запишите в него данные.
3. Свяжите BLOB ID нового BLOB со столбцом таблицы строк над которой вы будете выполнять INSERT и UPDATE.
Примечание: вы не можете непосредственно обновлять BLOB данные. Если вы желаете модифицировать BLOB данные, вы должны:
Создать новый BLOB
Прочитать данные из старого BLOBA в буфер где вы сможете отредактировать и модифицировать их.
Записать измененные данные в новый BLOB.
Подготовить и выполнить инструкцию UPDATE которая модифицирует BLOB столбец содержащий BLOBID нового BLOB, заменяющий старый BLOB ID.
Секция ниже описывает шаги требуемые для вставки, обновления, и замены BLOB данных.
Подготовка UPDATE или INSERT инструкции.
1. Создаем саму строку для обновления
"UPDATE PROJECT SET PROJ_DESC = ? WHERE PROJ_ID = ?";
или для вставки
char *in_str = "INSERT INTO PROJECT(PROJ_NAME, PROJ_DESC, PRODUCT,
2. Объявляем переменную содержащую структуру входных параметров
3. in_sqlda = (XSQLDA*)malloc(XSQLDA_LENGTH(2));
4. in_sqlda->version = SQLDA_VERSION1;
5.Установить XSQLVAR структуру в XSQLDA для каждого передаваемого параметра.
Определяем типы данных элементов
Для параметров типы которых известны во время компиляции: указатель sqldata связываем с локальной переменной содержащей передаваемый данные.
Для параметров типы которых неизвестны во время выполнения: выделяем память для хранения данных на которые указывает sqldata
Определяем число байт данных(размер)
Следующий код иллюстрирует все это для столбца BLOB и одного столбца тип данных которого известен во время компиляции.
#define PROJLEN 5
char proj_id[PROJLEN + 1];
in_sqlda->sqlvar[0].sqltype =SQL_Blob + 1;
Proj_id должна быть инициализирована во время выполнения (если значение не известно во времени компиляции). Blob_id должна быть установлена, чтобы обращаться к недавно созданному Blob, как описано в следующих секциях
Создание нового BLOB и хранения данных
1. Объявление и инициализация BLOB дескриптора:
isc_blob_handle blob_handle; /* Объявления BLOB дескриптора */
blob_handle= NULL; /* Устанавливаем дескриптор в NULL перед использованием*/
2. Объявление и инициализация BLOB ID:
ISC_QUAD blob_id; /* Объявление Blob ID. */
blob_id= NULL; /* Установка его в NULL перед использованием*/
3. Создание нового BLOB вызовомisc_create_blob2():
&blob_handle,/* устанавливается этой функцией ссылка на новый Blob */
&blob_id,/* Blob ID устанавливается этой функцией*/
0, /* Blob Parameter Buffer length = 0;no filter will be used*/
NULL /* NULL Blob Parameter Buffer, since no filter will be used*/
Эта функция создает новый BLOB открывает его для записи, и устанавливает blob_handle к указателю на новый BLOB
isc_create_blob2() также связывает BLOB с BLOBID, и устанавливает blob_id к указателю на BLOBID.
4. Записываем все данные, которые будут записаны в Blob, делая ряд вызовов isc_put_segment (). Следующий пример читает строки данных, и связывает каждый Blob с упомянутым blob_handle. (Get_line () читает следующую строку данных, которые будут написаны.)
unsigned short len;
&blob_handle,/* set by previousisc_create_blob2() */
len,/* длина буфера содержащего данные для записи */
line/* буфер содержащий данные для записи в BLOB*/
if (status_vector[0] == 1 &&status_vector[1])
5. Закрываем BLOB
Связывание нового BLOB с BLOB столбцом
Выполнение инструкции UPDATE связывает новый BLOB с BLOB столбцом в строке выбранной инструкции.
6.3.Удаление BLOB
существуют четыре способа удаления BLOB.
Удаляем строку содержащую BLOB. Вы можете использовать DSQL для выполнения DELETE инструкции.
Заменяем различные BLOB. Если Blob столбец содержит BlobID, и вы модифицируете столбец ссылающийся на разные BLOB, ранее сохраненный BLOB будет удален следующей сборкой “мусора”.
Сбрасываем в NULL столбец ссылающийся на BLOB, к примеру, используя DSQL инструкцию как следующую:
UPDATE PROJECT SET PROJ_DESC = NULLWHERE PROJ_ID = "VBASE"
Blob на который указывал удаленный blob_id будет удален следующей сборкой «мусора»
- Отказываемся от BLOB, после того как он был создан но, не был связан еще с определенным столбцом в таблице, используя isc_cancel_blob() функцию.
Запрос информации об открытом BLOB
После того, как приложение открывает Blob, оно может получить информацию о Blob.
Isc_blob_info () позволяет приложению сделать запрос для информации о Blob типа общего количества
числа сегментов в Blob, или о длине, в байтах, самого длинного сегмента. В дополнение к указателю на вектор состояния ошибки и дескриптор Blob, isc_blob_info () требует двух предоставляемых приложением буферов, буфера списков элементов, где приложение определяет информацию, которая требуется, и буфер результатов, куда InterBase возвращает требуемую информацию. Приложение заполняет буфер списков элементов с информационными запросами для isc_blob_info(), и передает ему указатель на буфер списков элементов, а также размер, в байтах, этого буфера.
Приложение должно также создать буфер результата, достаточно большой, чтобы хранить информацию, возвращенную InterBase. Оно передает указатель на буфер результата, и размер, в байтах, этого буфера в isc_blob_info(). Если InterBase пытается поместить, больше информации чем может вместить буфер результатов, она помещает значение, isc_info_truncated, определенное в ibase.h, в последний байт буфера результатов.
Буфер списка элементов запрашиваемой информации и буфер результатов.
Буфер списка элементов это char массив содержащий запрашиваемые байты значений. Каждый байт есть пункт определяющий тип желаемой информации.
Соответствующие константны определены в ibase.h
#define isc_info_blob_num_segments 4
#define isc_info_blob_max_segment 5
#define isc_info_blob_total_length 6
#define isc_info_blob_type 7
Буфер результатов содержит серию кластеров информации по каждому запрошенному элементу. Каждый кластер содержит три части.
Первый байт определяет тип возвращенной информации.
Второй байт – число определяющее число байт до конца кластера (длина инфо)
Значение хранимое в переменном числе байт, которое интерпретируется в зависимости от типа первого байта кластера
Следующая таблица показывает элементы информацию о которых можно получить
Элемент Возвращаемое значение
Запрашиваемый и возвращаемый элемент
Возвращаемое значение
Полное число сегментов
Длина самого длинного сегмента
Полный размер в байтах BLOB
Тип BLOB(0:сегментированный, 1:поток)
В дополнение к этой информации IB возвращенной ответ на запрос, IB может также возвратить один или несколько сообщений состояния в буфер результата. Каждое сообщение состояния есть беззнаковый байт в длине
Результирующий буфер слишком маленький для хранения запрашиваемой информации
Запрашиваемая информация неопеределена. Проверьте status_vector и сообщения.
6.4.Пример вызова isc_blob_info( )
Следующий код запрашивает число сегментов и максимальный размер сегмента для BLOB после открытия, получаемая информация помещается в буфер результатов
char res_buffer[20], *p, item;
SLONG max_size = 0L, num_segments = 0L;
&db_handle, /* database handle, setby isc_attach_database() */
&tr_handle, /* transaction handle, setby isc_start_transaction()
&blob_handle, /* set by thisfunction to refer to the Blob */
&blob_id, /* Blob ID of the Blob toopen */
0, /* BPB length = 0; no filter will beused */
NULL /* NULL BPB, since no filter willbe used */
if (status_vector[0] == 1 &&status_vector[1])
&blob_handle, /* Set inisc_open_blob2() call above. */
sizeof(blob_items),/* Length ofitem-list buffer. */
blob_items, /* Item-list buffer. */
sizeof(res_buffer),/* Length of resultbuffer. */
res_buffer /* Result buffer */
if (status_vector[0] == 1 &&status_vector[1])
/* An error occurred. */
/* Extract the values returned in theresult buffer. */
for (p = res_buffer; *p != isc_info_end;)
length = (short)isc_vax_integer(p, 2);
max_size = isc_vax_integer(p, length);
6.5.Blob дескрипторы
Blob дескриптор используется для предоставления динамического доступа к BLOB информации. К примеру, он может быть использован для хранения информации о BLOB данных для фильтрации, еще как кодовая страница для текстовых BLOB данных и информации о подтипе текстовых данных и не текстовых данных.
Два дескриптора Blob необходимы всякий раз, когда фильтр используется при записи или чтении Blob: один описывать данные источника фильтра, и другой цель.
BLOB дескриптор это структура определенная в заголовочном файле ibase.h как следующая:
short blob_desc_subtype; /* type of Blobdata */
short blob_desc_charset; /* characterset */
short blob_desc_segment_size; /* segmentsize */
unsigned char blob_desc_field_name [32];/* Blob column name */
unsigned char blob_desc_relation_name[32]; /* table name */
Размер сегмента BLOB есть максимальное число байт в приложении
Размер сегмента Blob -максимальное число байтов, которые приложение, как ожидается, запишет или будет читать из Blob. Вы можете использовать этот размер, чтобы выделить ваши собственные буфера. Blob_desc_relation_name и blob_desc_field_name поля содержащие строки с нулевым символом в конце.
Заполнение blob дескриптора
Есть четыре варианта для заполнения blob дескриптора
Вызываем isc_blob_default_desc(). И заполняем ей поля дескриптора значениями по умолчанию. Подтип по умолчанию есть 1 (TEXT), сегмент размером 80 байт, кодовая страница по умолчанию есть страница установленная для вашего процесса.
Вызываем isc_blob_lookup_desc(). Она обращается к системным таблицам и берет оттуда информацию о BLOB и заполняет ею поля дескриптора.
Вызываем isc_blob_set_desc(). Она инициализирует дескриптор из параметров вызова, быстрее нежели получать доступ к метаданным.
Устанавливаем поля дескриптора напрямую.
Следующий пример вызывает isc_blob_lookup_desc () чтобы узнать текущий подтип и информацию о наборе символов для столбца Blob по имени PROJ_DESC в таблице PROJECT. Функция сохраняет информацию в исходном описателе from_desс.
&db_handle; /* Set by previousisc_attach_database() call. */
&tr_handle, /* Set by previousisc_start_transaction() call. */
"PROJECT", /* имя таблицы */
"PROJ_DESC",/* название столбца */
&from_desc,/* Blob дескриптор заполняется этой функцией. */
&global/* глобальное название колонки возвращаемое этой функцией */
Фильтрация BLOB данных
Фильтр Blob это подпрограмма, которая транслирует данные Blob из одного подтипа в другой.
InterBase включает набор специальных внутренних фильтров Blob, которые преобразовывают подтип 0
( Неструктурные данные) в подтип1 (ТЕКСТ), и из подтипа 1 к подтипу 0.
В дополнение к использованию этих стандартных фильтров, Вы можете создавать ваши собственные внешние фильтры, чтобы обеспечивать специальное конвертирование данных. Например, Вы могли бы разрабатывать фильтр, чтобы преобразовывать один формат изображения к другому, например отображать то же самое изображение на мониторах с различными разрешающими способностями. Или Вы могли бы конвертировать двоичный Blob к простому тексту , чтобы легко файл переносить от одной системы к другой. Если Вы определяете фильтры, Вы можете назначать их идентификаторы подтипа от -32,768 до -1. Следующие разделы дают краткий обзор того, как писать фильтры Blob, и сопровождаются подробностями , как написать приложение, которое требует фильтрации.
Обратите внимание, что фильтры Blob доступны для баз данных, находящихся на всех платформах сервера InterBase кроме Системы Netware, где фильтры Blob не могут быть созданы.
6.6.Использование ваших собственных фильтров
В отличие от стандарта фильтров InterBase, которые конвертируют подтипом 0 в подтип 1 и наоборот, внешний фильтр Blob - вообще часть библиотеки подпрограмм, которые Вы создаете и связываете с приложением. Вы можете писать, Blob на C или Паскаль (или любой язык, который может называться из C).Чтобы использовать ваши собственные фильтры, следуйте по этим шагами:
1. Решите, какой фильтр Вы, должны написать.
2. Напишите фильтры в базовом языке.
3. Сформируйте общедоступную библиотеку фильтров.
4. Сделайте библиотеку фильтров доступной.
5. Определить фильтры для базы данных.
6. Напишите приложение, которое требует фильтрацию.
Шаги 2, 5 и 6 будут лучшеописаны в следующих разделах.
6.7.Объявление внешнего фильтра BLOB для БД
Для объявления внешнего фильтра для БД, используйте инструкции DECLARE FILTER. К примеру, следующая инструкция объявляет фильтр, SAMPLE:
DECLARE FILTER SAMPLE
INPUT TYPE –1 OUTPUT_TYPE –2
ENTRY POINT "FilterFunction"
В примере, входной подтип фильтра определен как -1 и его выходной подтип как -2. Если подтип -1определяет текст нижнего регистра, а подтип -2 текст верхнего регистра, то цель фильтра SAMPLE состояла бы в том, чтобы перевести данные Blob из текста нижнего регистра в текст верхнего регистра.
Параметры ENTRY_POINT И MODULE_NAME определяют внешнюю подпрограмму, которую вызывает, когда вызывается фильтр. Параметр MODULE_NAME определяет filter.dll, динамически загружаемую библиотеку, содержащую выполнимый код фильтра. Параметр ENTRY_POINT определяет точку входа в DLL. Хотя пример показывает только простое имя файла, это - хорошая практика для определения полного квалифицированного пути, начиная с пользователей вашего приложения желающих загрузить файл.
6.8.Создание внешних Blob фильтров
Если Вы хотите создавать ваши собственные фильтры, Вы должны иметь детальное понимание типов данных , которые Вы планируете конвертировать. InterBase не делает строгой проверки типа данных на данные Blob; это - ваша ответственность.
Определений функций фильтров
При написании фильтра, Вы должны включить точку входа, известной функции фильтра, в секции объявления программы. InterBase вызывает функцию фильтра, когда приложение выполняет операции на Blob, определенные для использования фильтра. Вся связь между InterBase и фильтром происходит через функцию фильтра. Функция самого фильтра может вызывать другие функции, которые включает исполняемая программу фильтра.
Вы объявляете имя функции фильтра и имя выполняемой программы - фильтра с параметрами ENTRY_POINT И MODULE_NAME в инструкции DECLAREFILTER.
Функция фильтрадолжна иметь следующее объявление, вызывающее последовательность:
filter_function_name(short action, isc_blob_ctl control);
Параметр, action, является одним из восьми возможных макроопределений действия, и параметр, control- элемент isc_blob_ctl, управляющей структуры Blob, определенной в файле заголовка InterBase, ibase.h. Эти параметры обсуждаются позже в этой главе.
Следующий листинг скелетного фильтра описывает функцию фильтра, jpeg_filter:
#define SUCCESS 0
#define FAILURE 1
ISC_STATUS jpeg_filter(short action, isc_blob_ctl control)
ISC_STATUS status = SUCCESS;
InterBase передает одно из восьми возможных действий к функции фильтра, jpeg_filter, посредством параметра action, и также передает экземпляр управляющей структуры Blob, isc_blob_ctl, посредством параметра, control. ellipses (…) в предыдущем листинге представляют код, который выполняет некоторые операции, для каждого действии, или случая, который перечислен в инструкции case.
6.9.Определение управляющей структуры BLOB
Управляющая структура BLOB предоставляет основные методы обмена данными между фильтром и Interbase.
Управляющая структура BLOB определена при помощи typedef, isc_blob_ctl. в ibase.h вот так:
typedef struct isc_blob_ctl
/* Указатель на внутреннюю InterBase Blob подпрограмму доступа.(функтор) */
struct isc_blob_ctl *ctl_source_handle;
/* Экземпляр ofisc_blob_ctl передаваемый во внутреннюю подпрограмму доступа IB*/
short ctl_to_sub_type;/* Целевой подтип */
short ctl_from_sub_type;/* Исходный подтип */
unsigned short ctl_buffer_length; /* Длина ctl_buffer. */
unsigned short ctl_segment_length; /* Длина текущего сегмента */
unsigned short ctl_bpb_length; /* Длина буфера параметров BLOB. */
char *ctl_bpb; /* Указатель на буфер параметров BLOB */
unsigned char*ctl_buffer; /* Указатель на сегментный буфер */
ISC_LONGctl_max_segment; /* Длина самого длинного BLOB сегмента */
ISC_LONGctl_number_segments; /* Полное число сегментов */
ISC_LONGctl_total_length; /* Полная длина BLOB*/
ISC_STATUS*ctl_status;/* Указатель на статус вектор */
long ctl_data[8];/* Данные определяемые приложением */
Семантика некоторых isc_blob_ctl полей зависит от выполняемого действия.
Например, когда приложение вызывает isc_put_segment () функцию API, InterBase передает isc_blob_filter_put_segment - действие функции фильтра. Буфер, указатель на буфер, ctl_buffer - поле управляющей структуры, передаваемый функции фильтра, содержит сегмент данных, которые будут записано, как определено приложением в его запросе к isc_put_segment (). Поскольку буфер содержит информацию, передаваемую в функцию фильтра, это называется полем IN. Функция фильтра должна включить инструкции в инструкцию case под isc_blob_filter_put_segment для выполнения фильтрации и затем передачи данных для записи в базу данных. Это может быть сделано, вызовом *ctl_source подпрограммы доступной внутри Interbase подпрограммы. Для подробной информации относительно ctl_source, см. Руководство Программиста.
С другой стороны, когда приложение вызывает isc_get_segment () функцию API, и буфер, на него указывает ctl_buffer в управляющей структуре переданной функции фильтра, пуст. В этом случае, InterBase передает isc_blob_filter_get_segment действие- функции фильтра. Обработка действия- функции isc_blob_filter_get_segment фильтра должна включить команды для заполнения ctl_buffer сегментом данных из базы данных, чтобы возвратить его приложению. Это может быть сделано, вызовом *ctl_source подпрограммы доступной внутри IB. В этом случае, буфер используется для вывода информации функцией фильтра, и называется полем OUT.
Следующая таблица описывает каждое из полей в isc_blob_ctl управляющей структуре Blob, используются ли они для ввода функции фильтра (IN), или вывода (OUT).