Задать вопрос
  • Как объединить запросы в транзакцию?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Поскольку быстрым поиском готовый ответ на Тостере не находится, стоит написать канонический.

    Сначала общая информация:

    Транзакция служит для обеспечения принципа "всё или ничего", гарантируя, что либо все запросы выполнились без ошибок, либо, если в каком-то из запросов произошла ошибка, то все предыдущие будут отменены, как будто их и не было вовсе. Из чего можно сделать следующие выводы:
    • транзакция не нужна для любого количества запросов на выборку данных, поскольку там нечего откатывать
    • транзакция не нужна для одного запроса на изменение данных (вставка, обновление, удаление) - такой запрос представляет из себя мини-транзакцию, которая сама автоматом откатывается при ошибке
    • не следует путать транзакции с блокировками. Хотя при определённых параметрах транзакции могут выполнять и блокировку, в общем случае это два разных механизма, которые могут выполняться как вместе, так и по отдельности. По умолчанию транзакция НЕ обеспечивает блокировку таблиц, участвующих в запросе


    Самым простым вариантом будет заключить запросы между вызовами beginTransaction() и commit(), как показано например в документации к последнему.
    $db->beginTransaction();
    $db->prepare("UPDATE `tab1` SET `col` = ?")->execute($data1);
    $db->prepare("UPDATE `tab2` SET  `col` = ?")->execute($data2);
    $db->prepare("UPDATE `tab3` SET  `col` = ?")->execute($data3);
    $db->commit();

    Для современных версий РНР этого должно быть достаточно: начиная с РНР 8.0 ошибочный запрос по умолчанию выбрасывает исключение. Не пойманное исключение прерывает выполнение РНР скрипта. При прерывании выполнения скрипта РНР закрывает соединение с Mysql, а при закрытии соединения Mysql откатывает все открытые в нём транзакции.

    Соответственно, при ошибке в любом из запросов транзакция автоматически откатится. А при успешном выполнении всех запросов транзакция, соответственно, закоммитится.

    В редких случаях, когда после отката транзакции предполагается дальнейшее выполнение кода, можно заключить код транзакции в try-catch и откатить её вручную.

    Важно помнить некоторые особенности.
    • в mysql не все движки таблиц поддерживают транзакции. впрочем ,учитывая что innodb является движком по умолчанию уже лет 20, это вряд ли будет проблемой
    • запросы на изменение страктуры таблиц автоматически коммитят стартовавшую транзакцию, то есть их следует избегать. Кажется, в новых версиях какие-то уже не коммитят, но я предпочитаю избегать всё равно.


    Также желательно помнить, что в любом более-менее сложном коде очень быстро появляются вложенные транзакции, а PDO при попытке стартовать транзакцию при уже открытой, выбросит исключение, что, соответственно, приведёт к откату родительской (и это гораздо лучше поведения MySQL по умолчанию, которая автоматически коммитит старую). И имеет смысл накидать простой кодик, который считает вложенные транзакции, и не стартует, если уже был старт, а при коммите вычитает вложенность, а реально коммитит только если вложенности не осталось. Что-то вроде кода из комментариев к beginTransaction(), подравняв его напильником
    class \MyPDO extends \PDO
    {
        protected $transactionCounter = 0;
    
        public function beginTransaction()
        {
            if($this->transactionCounter++ === 0) {
                return parent::beginTransaction();
            }
        }
        public function commit()
        {
            $this->transactionCounter--;
            if($this->transactionCounter === 0) {
                return parent::commit();
            }
        }
        public function rollback()
        {
            $this->transactionCounter = 0;
            return parent::rollback();
        }
    }

    разместив его либо прямо в PDO, либо в своем враппере.
    Ответ написан
    3 комментария
  • Как найти опечатку в номере телефона?

    @knigaman
    Во-первых даже у одного человека могут быть номера, которые отличаются на одну-две цифры, такое может быть в реальности - это не всегда ошибка.

    Во-вторых подойдет любая функция сравнения строк, например в пыхе что первое гуглится функция similar_text. Тупо смотришь процент схожести и если он высок - порог определи сам - тупо выдавай предупреждение о возможной опечатке. Можешь наколхозить свой вариант - не возбраняется.
    Ответ написан
    Комментировать
  • VPN между VPS и сервером без блокировки РКН возможен?

    @Drno
    вопрос на этот ответ знает только РКН
    Ответ написан
    2 комментария
  • Как установить Linux Mint на все ssd диски?

    @rPman
    Во время установки тебя спросят, куда устанавливать, небольшой менеджер раздела, где можно создать раздел, отформатировать и указать, какая точка монтирования будет на нем. Например на одном диске корень /, на другом /usr, на третьем /home

    Полагаю вопрос задан не корректно, так как диски большие, типовая установка linux пара десятков гигабайт, все влезет на один диск.

    Подключить диски можно вручную после установки, отредактировав /etc/fstab

    Какую именно задачу решаешь?
    Ответ написан
    1 комментарий
  • Что будет, если закрыть терминал в VS Code без отключения программы?

    Прекратила.
    Ответ написан
    Комментировать
  • Как прикрутить авторизация запросов по API key или Token в Django?

    Модель
    from django.db import models
    from django.contrib.auth.models import User
    
    class APIKey(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE)
        key = models.CharField(max_length=64, unique=True)


    Проверка ключа API
    from django.http import JsonResponse
    from your_app.models import APIKey
    
    def api_key_required(view_func):
        @wraps(view_func)
        def _wrapped_view(request, *args, **kwargs):
            api_key = request.headers.get("X-API-Key")
            if not api_key or not APIKey.objects.filter(key=api_key).exists():
                return JsonResponse({"error": "Unauthorized"}, status=403)
            return view_func(request, *args, **kwargs)
        
        return _wrapped_view


    Вью для API
    from django.http import JsonResponse
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    @api_key_required
    def my_api_view(request):
        return JsonResponse({"message": "Success"})
    Ответ написан
    1 комментарий
  • Стоит ли использовать Django для создания многофункционального сайта?

    @Belvarm
    Java TeamLead, интеграционные решения
    Стоит использовать те фреймворки, которые вы знаете, а то будет мало пользы
    Ответ написан
    Комментировать
  • No such file or directory django как исправить?

    VoidVolker
    @VoidVolker
    Dark side eye. А у нас печеньки! А у вас?
    А что мешает посмотреть на реальный путь файла и сравнить с текущим путём в консоли?
    6797fe2c30986221244028.png
    Ответ написан
    7 комментариев
  • Можете помочь с установкой Wubuntu?

    NVidia не пускает вас скачать свои драйверы.
    Используйте VPN

    Но смысла особого в использовании именно в "Wubuntu" нет, используйте обычные версии: Ubuntu/Kubutu/Xubuntu.
    Ответ написан
    Комментировать
  • Вирус (глупый) запускает очень много окон cmd.exe просто загружая оперативку. Как его отследить и устранить?

    VoidVolker
    @VoidVolker Куратор тега Windows
    Dark side eye. А у нас печеньки! А у вас?
    1. Загрузиться в безопасном режиме
    2. Скачать пакет Sysinternals
    3. Запустить Autoruns
    4. Найти и убрать лишние записи в атозагрузке
    Ответ написан
    3 комментария
  • Как узнать длину видео в PHP?

    @rPman
    Установить пакет ffmpeg и использовать утилиту ffprobe
    Вот информация о видео в json:
    ffprobe -v quiet -print_format json -show_format example.avi

    или вот конкретно одно поле с длительностью в секундах
    ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 example.avi


    соответственно на php выполни эту команду, например:
    $duration=`ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$filename"`';

    и получишь в $duration секунды в float или пусто при ошибке.
    Ответ написан
    1 комментарий
  • Возможно ли парсить разные сайты одним скриптом?

    Steel_Balls
    @Steel_Balls
    с такой формулировкой вопроса всё возможно
    Ответ написан
    Комментировать
  • VLESS (XKEEN/XRAY) для ChatGPT. Поможете неастроить?

    @Drno
    виноват IP впн сервера, который видимо бьется как РФ
    Ответ написан
    2 комментария
  • Как получить доступ к панели 3x-ui?

    888AndeR888
    @888AndeR888
    IT специалист
    В терминале введите
    x-ui
    Дальше будет понятно...
    Ответ написан
    Комментировать
  • Как выбрать максимальное значение во вложенных массивах?

    delphinpro
    @delphinpro Куратор тега PHP
    frontend developer
    $array = [
                [
                    "label" => "Bad",
                    "number" => 0.99999895728755
                ],
                [
                    "label" => "Good",
                    "number" => 4.2713489950201E-8
                ]
            ];
    
    $max = array_reduce($array, fn($a, $i) => $i['number'] > $a['number'] ? $i : $a, $array[0]);
    
    var_dump($max);
    Ответ написан
    Комментировать
  • Как отобразить содержимое json файла в wordpress?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    function display_forecast_json() {
        $file_path = ABSPATH . 'wp-content/forecast.json';
    
        if (file_exists($file_path)) {
            $json_content = file_get_contents($file_path);
            $data = json_decode($json_content, true);
    
            if (!empty($data)) {
                $output = '<table border="1" style="width:100%; text-align: left;">';
                $output .= '<thead><tr><th>Дата и время</th><th>Вероятность</th></tr></thead>';
                $output .= '<tbody>';
                
                foreach ($data as $item) {
                    $output .= '<tr>';
                    $output .= '<td>' . esc_html($item['дата и время']) . '</td>';
                    $output .= '<td>' . esc_html($item['вероятность']) . '</td>';
                    $output .= '</tr>';
                }
                
                $output .= '</tbody></table>';
                return $output;
            } else {
                return '<p>JSON файл пуст или содержит некорректные данные.</p>';
            }
        } else {
            return '<p>Файл forecast.json не найден.</p>';
        }
    }
    
    // Регистрируем шорткод [forecast_display], чтобы отображать данные
    add_shortcode('forecast_display', 'display_forecast_json');
    Ответ написан
    Комментировать
  • Направления создание клона Minecraft?

    @dim5x
    ЗИ, ИБ. Помогли? Поблагодарите. Отметьте ответом.
    Освоить базовый синтаксис русского языка.
    Ответ написан
    1 комментарий