Блог Александра Башкирова

ИТ и бизнес, компьютеры и ПО, фото, программирование и просто мысли…

Этот сайт в основном посвящен тому, что мне интересно вне работы. Ведется в порядке хобби.
Все изложенное на сайте - мое частное оценочное мнение и не может быть истолковано иначе.
Со всеми вытекающими из этого последствиями.

Метки: mysql

Немного про mysql и совсем мало про postgre

Рубрика: Linux

Писал я тут проект на mysql... Причем, не просто набор таблиц и связей - а "все по-взрослому", то есть: триггеры, хранимые, функции. То есть логика на стороне сервера.

Приступая к сему действу - тешил себя надеждой, что получится написать код, который может мигрировать на postgre вообще без правок. И - обломался. Нет такой радости. Более того, от версии к версии mysql в хранимых что-то добавляется (и, видимо, исчезет). А попытка перенести на postgre наталкивается на много ошибок, которые в основном относятся к специфике СУБД. Так что оставил эту идею и принялся ковырять mysql.

Из того, что заметил:

  • динамический SQL в триггерах mysql нельзя. Совсем никак. Даже если вызывать процедуру, в которой есть динамический SQL - будет ошибка. Версия mysql 5.5.
  • Если пишем триггер на таблицу в mysql, суть которого - изменение поля в той же таблице, на которой триггер, то синтаксис будет такой, например:
  • SET new.field = CONCAT (old.field, 'test')

    где new и old - старое и новое состояние полей соответственно

    А если так не написать - то ошибка вылезет.

  • вообще динамический SQL себя ведет странно. Его как бы можно, но через prepare - execute.
  • курсоры ведут себя странно. Есть таблица, из которой выбираю курсором, InnoDB. Пока она была предварительно заполнена - все хорошо. Как только начал в нее писать/удалять - так всё, ша. Задвоение данных. Об это плясал с бубном много... Но ничего лучше не придумал, как проверять в цикле на совпадение с предыдущим значением (костылииина, честно говоря). Но добиться от мускула адекватного поведения не смог. (Рестарт, сброс кешей, чистка кармы и прочее - не помогли).
  • версию mysql можно посмотреть через SQL запрос SHOW version();
Пока что полет продолжается... Ждем новых вестей с полей "разработки для души".

Сугубо технический пост.

Рубрика: Linux

На Хабре. Про то, как перенести пользователей с их привилегиями на новую базу в mysql. Интересен и пост, и комментарии, где также предлагают интересные варианты решений.

https://habrahabr.ru/post/328604/

FluentPDO - библиотека для работы с PDO в PHP

Рубрика: Alib.spb.ru

Слйчайно наткнулся на FluentPDO - библиотеку для работы с PDO в PHP. Смысл в том, что библиотека является слоем абстракции между приложением, PDO-расширением PHP и SQL. Потестировав, понял, что удобно. А значит, есть смысл рассказать.

Для начала - ссылки.

  1. FluentPDO на github: https://github.com/envms/fluentpdo
  2. Подробная статья о том, как её использовать: https://www.sitepoint.com/getting-started-fluentpdo/
Ну и - чем "зацепило".

Смысл в том, что от программиста при использовании библиотеки требуется создать PDO-объект для работы с БД, передать его в fluentpdo, и дальше, используя встроенные методы - работать с SQL.

Например:

$pdo = new PDO("mysql:dbname=testdb", "testuser", "testpassword");
$fpdo = new FluentPDO($pdo);

Дальше "всё просто", например, простой select * from mytable where id=$userid будет выглядеть так:

$query = $fpdo->from('mytable')->where('id', $userid);

И чтобы обработать результат:

foreach($query as $row){
    
print $row['field1'] . ' -- ' . $row['field2'] . '<br>';
 }

Если нужны конкретные столбцы, то:

$query = $fpdo->from('mytable')
   ->select(array('field1', 'field3'))->where('id', $userid);

Ну и чисто для иллюстрации - insert:

$values = array('field1' => 'testval1', 
     'field2' => 'testval2', 
     'field3' => 'testval3'); 
     
$query = $fpdo->insertInto('mytable')->values(values); 
  
$insert = $query->execute();

Также поддерживаются все основные операции, включая разнообразные update, join, delete и т.д.

Кстати, по приведенной выше ссылке примеров сильно больше. Скажу, что я попробовал на тесте FluentPDO - мне понравилось. Как-то упрощает жизнь, с точки зрения того, что не надо писать километровый код и запросы выглядят пологичнее. Ну и вся мощь PDO - типа единого синтаксиса работы с разными БД, безопасности (использование placeholder), получается как бы на нашей стороне :)

Про блокировки таблиц в mysql

Рубрика: Alib.spb.ru

Натолкнулся на любопытную особенность работы блокировки в mysql. Итак дано:

таблица table-1 и table-2. Из второй мы читаем, результат записываем в первую. Но читаем не просто - а достаточно хитро, примерно так

TRUNCATE TABLE table-1;
INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 WHERE fld3='value');

Если таблицы не заблокировать (что мне понятнее) или не использовать транзаккцию (что для случая mysql я пока не использовал), то при одновременном выполнении запроса получится ... да всё, что угодно. Имитация (запуск скрипта с вызовом указанного кода в несколько потоков) приводил к тому, например, что для ряда ситуаций число строк в table-1 превышало ожиждаемое в 1,5-2 раза.

Соответственно, требуется обернуть вызовы блокировкой. Которая по идее должна выглядеть так:

LOCK TABLES table-1 WRITE, table-2 READ;
TRUNCATE TABLE table-1;
INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 WHERE fld3='value');
UNLOCK TABLES;

Но вот фигушки. В такой конструкции mysql упорно выдает ошибку ERROR #1100: Table 'table-2' was not locked with LOCK TABLES

Как оказалось, это не бага, это фича. Как написано в документации https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html - для каждого упоминения таблицы table-2 в SELECT требуется свой блокировочный алиас в LOCK'е. Вот так примерно:

LOCK TABLES table-1 WRITE, table-2 READ, table-2 AS t2 READ;
TRUNCATE TABLE table-1;
INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 AS t2 WHERE fld3='value');
UNLOCK TABLES;

В такой конструкции - всё будет работать.

И еще момент: когда используем LOCK TABLES, то в нем надо перечислить (заблокировать) все таблицы, к которым будет доступ на чтение / запись. В противном случае mysql выдаст Error #1100. Ту самую, что какая-то таблица не блокирована, ага.

mysql: Как бороться с #2014 - Commands out of sync; you can't run this command now

Рубрика: Alib.spb.ru

Писал тут хранимую процедуру под mysql (что важно: с параметром типа string). Написал, запустил (из-под phpmyadmin)... получаю ошибку: #2014 - Commands out of sync; you can't run this command now. Я понимаю, когда ловлю такое из-под phpmyadmin - это еще куда ни шло... А вот когда запускаю из консоли, под рутом - получил ошибку "ERROR 1253 (42000): COLLATION 'utf8_bin' is not valid for CHARACTER SET 'latin1'". Ага, подумал я. И поменля кодировку всей базы на utf8. Не поверите: заработало! И из консоли, и из под pma.

Подозреваю, что для процедур, у которых на входе нетекстовый параметр - такой проблемы может не существовать. Но для текстового параметра - вот так вот.

Для памяти:

Изменяем кодировку для базы данных:

ALTER DATABASE `имя базы` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Изменяем кодировку для таблицы:

ALTER TABLE `tablename` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE `tablename` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Все естественно из-под рута.

Случайная фотография

Орфография

Система Orphus
Дизайн от: Templates Next | Адаптация d51x