Рецепты программирования на PHP или практические советы по программированию → Обмен данными в режиме он-лайн между базами MS SQL (под Windows/IIS) и MySQL (по /д UNIX/Appache) на двух удаленных веб-серверах
Иногда возникает необходимость обмена данными между двуми базами данных в режиме реального времени. Например, на базе MS SQL написаны многие офисные / складские / учетные и т.п. программы. На mySQL храняться обычно данные для сайтов.
Оперативный обмен может потребоваться, к примеру, если вы захотите транслировать какие-либо данные в интернет. Например, выписки по счетам клиентов, какие-либо отчеты и пр. Или наоборот, когда интернет-посетитель оставляет о себе на веб-сайте какую-то информацию, которая должна попасть в программы внутреннего учета. В этой заметке я не затрону немаловажные вопросы безопасности при обмене данными, а покажу на простом примере как делается такой обмен. Т.е. это не конкретная реализация, а общие принципы построения таких архитектурных решений. Авторизацию и прочие анти-хакерские штучки постараюсь затронуть в следующих публикациях.
Пусть перед нами стоит задача данные о сделанном заказе с сайта domain.ru перенести во внутреннюю программу учета, которая построена на базе MS SQL (например, в 1С). При этом, пусть данные переносятся не с каждым новым заказом, а раз в час. Т.е. у нас на сайте domain.ru возникает необходимость создать базу данных с заказами и время от времени ее переносить на другой сервер.
В связке будут участвовать базы данных MSSQL и MySQL.
Шаги 1-3 - на Windows хостинге.
Шаг 1.
Создаем на MS SQL простую таблицу заказов:
| 1 | CREATE TABLE orders ( |
| 2 | useremail varchar(50) |
| 3 | ,order varchar(50) |
| 4 | ,quantity int |
| 5 | ) |
Шаг 2.
Создаем на MS SQL хранимую процедуру, которая будет записывать данные о заказе. Для простоты, в этой процедуре нет никаких проверок на то, был ли заказ ранее, можно ли заказать этот товар, и пр.
| 1 | CREATE PROCEDURE dbo.orders_ins_sp ( |
| 2 | @useremail varchar(50) |
| 3 | ,@order varchar(50) |
| 4 | ,@quantity int |
| 5 | AS |
| 6 | BEGIN |
| 7 | SET NOCOUNT ON |
| 8 | INSERT INTO orders (useremail,order,quantity) VALUES (@useremail,@order,@quantity) |
| 9 | SELECT SCOPE_IDENTITY() as Result |
| 10 | END |
| 11 | GO |
Шаг 3.
Создаем файл на Visual Basic (на IIS сервере) - /xchange/x.asp, который будет принимать данные и вызывать хранимую процедуру orders\_ins\_sp на сервере:
| 1 | <% |
| 2 | Server.ScriptTimeout = 100 |
| 3 | Set Conn = Server.CreateObject("ADODB.Connection") |
| 4 | Conn.ConnectionTimeout = 100 |
| 5 | Conn.CommandTimeout = 100 |
| 6 | Conn.Open "DATABASE", "DBUSER", "DBPASSWORD" |
| 7 | Conn.DefaultDatabase="DATABASE" |
| 8 | |
| 9 | useremail = Request("useremail") |
| 10 | order = Request("order") |
| 11 | quantity = Request("order") |
| 12 | |
| 13 | q = "orders\_ins\_sp '@useremail='"+useremail+"',@order='"+order+"',@quantity="+quantity |
| 14 | Set rs = Conn.Execute(q) |
| 15 | if(Not rs.EOF) then |
| 16 | response.write rs("Result") |
| 17 | end if |
| 18 | rs.Close |
| 19 | %> |
Шаг 4.
Создаем на UNIX хостинге файл sender.php, который забирает данные из таблицы mySQL и передает их удаленному серверу IIS.
Пусть табличка с заказами на mySQL будет аналогичного вида, только туда добавим поле id INT - идентифицируйщий столбец и поле status EMUN('new','sent','error'), которое по умолчанию будет равно new, а при передаче заказов другому серверу статус изменится на 'sent'. Если возникнет ошибка при передаче, то в это поле запишем статус 'error'.
| 1 | <?php |
| 2 | //определяем адрес ASP скрипта удаленного сервера |
| 3 | DEFINE("REMOTE\_URL","http://domain1.ru/xchange/x.asp"); |
| 4 | //соединяемся с БД |
| 5 | $conn = new mysqli(DBHOST,DBUSER,DBPASSWORD,DATABASE); |
| 6 | //запрашиваем все новые заказы |
| 7 | $q = "SELECT * FROM orders WHERE status='new'"; |
| 8 | $res = FALSE; |
| 9 | $result = $conn->query($q) or trigger_error("[SQL] ".$q." ".$conn->error,E_USER_ERROR); |
| 10 | //считываем полученные данные в ассоциативный массив в $res |
| 11 | while ($r = $result->fetch_array(MYSQLI_ASSOC)) $res[] = $r; |
| 12 | $result->close(); |
| 13 | |
| 14 | //теперь каждый заказ отсылаем на удаленный сервер и меняем его статус на 'sent' |
| 15 | $sent = $error = 0; |
| 16 | foreach($res as $k=>$v) { |
| 17 | if($response = file_get_contents(REMOTE_URL,$v)) { |
| 18 | $conn->query("UPDATE orders SET status='done' WHERE id=".$v["id"]); |
| 19 | $sent++; |
| 20 | } else { |
| 21 | $conn->query("UPDATE orders SET status='error' WHERE id=".$v["id"]); |
| 22 | $error++; |
| 23 | } |
| 24 | } |
| 25 | unset($res); |
| 26 | |
| 27 | //и выводим результат: |
| 28 | echo "Всего новых заказов: ".count($res).", успешно передано:".$sent.", ошбики при передаче:".$error; |
| 29 | ?> |
Вот и все. Теперь включаем файл sender.php в расписание cron, чтобы он вызывался раз в час/день/неделю и т.п. и получаем автоматические обновления в БД MS SQL.
Обратная связь организуется аналогично. В этом случае asp скрипт забирает данные из MS SQL и передает их скрипту php. А скрипт php пишет полученные данные в базу MySQL.
В реальной жизни, я разрабатывал более сложные архитектуры, которые позволяли обмениваться информацией в двустороннем режиме, с поддержкой авторизации и многим другим функционалом. Один из примеров совместной работы двух разных серверов, построенных по вышеуказанному принципу, можно увидеть в нашем проекте sbtrader.ru. Здесь, данные по экономической статистике транслируются в режиме реального времени прямо с торговых терминалов Рейтер и Блумберг.
Дмитрий Трость

20.07.2010 → Валек написал:
Здравствуйте. Не могли бы вы более подробно описать третий шаг? Спасибо.