Laravel ошибка несоответствия данных при использовании \ PDO :: ATTR_EMULATE_PREPARES => true - PullRequest
3 голосов
/ 07 февраля 2020

У нас есть сборка приложения Php Laravel, а для базы данных мы используем postgres sql. Кроме того, postgres мы настроили pgBouncer для ограничения максимального количества соединений на стороне сервера, управляя пулом незанятых соединений, которые могут использоваться любыми приложениями.

Теперь мы столкнулись с проблемой логические значения (True (0), False (1)), используемые в приложении (Php Laravel). Это дает ошибку ниже, когда выполняется любая операция CRUD. В приведенном ниже столбце ошибки «отозвано» указан логический тип.

столбец «отозван» относится к типу логический, но выражение имеет целочисленный тип. Вам нужно будет переписать или привести выражение. (SQL: \ "отзывано \", \ "создано_ат \") значения (0, 2020-02-07 06:09:06)

Теперь, после изучения, я узнал, что логические значения должны рассматриваться как строки с pgBouncer. Поэтому я внес изменения в файл . php, расположенный в " \ vendor \ laravel \ framework \ src \ Illuminate \ Database ". Я изменил код для учета логического значения, как указано ниже.

public function bindValues($statement, $bindings)
{
    foreach ($bindings as $key => $value) {
        //if(is_bool($value))
        $statement->bindValue(
            is_string($key) ? $key : $key + 1, $value,
            //is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR
            is_int($value) ? PDO::PARAM_INT : is_bool($value) ? PDO::PARAM_STR : PDO::PARAM_STR
        );
    }
}

После вышеуказанных изменений ошибка с логическими значениями была решена.

Но теперь я сталкиваюсь со странными проблемами на сервере, когда я проверяю ошибку журнала базы данных, я последовательно получаю следующую ошибку:

ОШИБКА: подготовленный оператор "pdo_stmt_00000001" уже существует STATEMENT: установить имена 'utf8' ОШИБКА: подготовленный оператор "pdo_stmt_00000001" не существует ЗАЯВЛЕНИЕ: DEALLOCATE pdo_stmt_00000001

Это действительно было странно, и после изучения inte rnet я внес следующие изменения в мою базу данных . php file, чтобы отключить операторы подготовки.

'pgsql' => [
        'driver' => 'pgsql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '5432'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix' => '',            
        'schema' => 'public',
        'sslmode' => 'prefer',
        'options' => [
            \PDO::ATTR_EMULATE_PREPARES => true
        ]
]

Причина появления ATTR_EMULATE_PREPARES => true заключается в том, что я установил режим " Транзакция " в " pgbouncer .ini"файл.

Теперь, чтобы заставить подготовленные операторы работать в режиме Транзакция , потребуется PgBouncer для внутреннего их отслеживания, чего он не делает. Поэтому единственный способ продолжать использовать PgBouncer в этом режиме - отключить подготовленные операторы в клиенте, который в моем случае равен PHP Laravel, и я уже обработал его в базе данных ". php "файл, когда соединение установлено, как показано в приведенном выше коде.

Я перепробовал все варианты, которые приведены в http://www.pgbouncer.org/faq.html#how -произвести-подготовлено-утверждений-с- пул транзакций , но он не устраняет ошибку подготовки отчета , отображаемую в журнале базы данных.

ОШИБКА: подготовленный оператор "pdo_stmt_00000001" уже существует STATEMENT: set имена 'utf8' ОШИБКА: подготовленный оператор "pdo_stmt_00000001" не существует ЗАЯВЛЕНИЕ: DEALLOCATE pdo_stmt_00000001

Пожалуйста, укажите мне то же самое, и какие дополнительные настройки требуются для ошибки. Эти ошибки находятся на рабочем сервере клиента, и мы не можем go опережать эти ошибки на рабочем сервере.

Пожалуйста, дайте мне ваш ценный отзыв как можно раньше, так как я столкнулся с проблемой в течение 5 дней, и попробуйте со всеми варианты, которые попадаются.

Спасибо!

Ответы [ 2 ]

7 голосов
/ 19 марта 2020

1) Во-первых, вам нужно изменить параметр PDO, который вы задаете в параметрах массива pg sql вашей базы данных. php правильный путь указан ниже.

'pgsql' => [
        'driver' => 'pgsql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '5434'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),           
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
        'options' => [
            PDO::ATTR_EMULATE_PREPARES => true
        ]       
        ]

2) Во-вторых, и самое главное, убедитесь, что вы используете значение «ATTR_EMULATE_PREPARES», равное «true», при каждом подключении к базе данных, которое вы пытаетесь подключить в вашей базе данных . php файл.

Например,

'test' => [
        'driver' => 'pgsql',
        'host' => env('test', '127.0.0.1'),
        'port' => env('test', '5434'),
        'database' => env('DB_TEST_DATABASE', 'test'),
        'username' => env('DB_USERNAME', 'test'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
        'options' => [
            PDO::ATTR_EMULATE_PREPARES => true
        ]           
    ],
'test1' => [
        'driver' => 'pgsql',
        'host' => env('test1', '127.0.0.1'),
        'port' => env('test1', '5434'),
        'database' => env('DB_TEST1_DATABASE', 'test1'),
        'username' => env('DB_USERNAME', 'test'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
        'options' => [
            PDO::ATTR_EMULATE_PREPARES => true
        ]           
    ]

Пожалуйста, не забудьте использовать «ATTR_EMULATE_PREPARES» для true для каждого соединения с базой данных, которое вы устанавливаете в приложении, в ваших комментариях вы устанавливаете соединение только с «pg sql ", который делает акцент только на postgres sql подключении, а не на базе данных, с которой ваше приложение связывается, которая находится в postgres.

Надеюсь, это поможет вам разрешить ваш запрос. Наслаждайтесь !!!

2 голосов
/ 14 февраля 2020

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

Из laravel .com / docs / master / eloquent-mutators # приведение атрибутов

Свойство $ castts в вашей модели предоставляет удобный метод преобразования атрибутов в распространенные типы данных. Свойство $ casts должно быть массивом, в котором ключом является имя преобразуемого атрибута, а значением является тип, к которому вы будете преобразовывать столбец. Поддерживаемые типы приведения: целочисленные, вещественные, плавающие, двойные, десятичные :, строка, логическое значение, объект, массив, коллекция, дата, дата и время и метка времени. При приведении к десятичному типу вы должны определить количество цифр (десятичное число: 2).

Чтобы продемонстрировать приведение атрибутов, давайте приведем атрибут is_admin, который хранится в нашей базе данных как целое число (0 или 1), чтобы логическое значение:

Итак, в вашем случае вам нужно будет привести revoked к типу bool, добавив к Eloquent model свойство $casts следующим образом:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class YourModel extends Model
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'revoked' => 'boolean',
    ];
}

А для вашей проблемы с pgBouncer кажется, что у pgBouncer есть внутренняя проблема с пулами транзакций и подготовленных операторов ,

От: stackoverflow.com / a / 7612639/7047493

Это оказалось проблемой pgBouncer, возникающей при использовании чего-либо, кроме пула сеансов. Мы использовали пул транзакций, который, очевидно, не может поддерживать подготовленные операторы. Переключившись на пул сеансов, мы обошли проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...