Перехват исключения / ошибки в транзакции базы данных

11

Я использую следующий способ в Joomla 2.5 и 3 для выполнения запроса к базе данных -

$database = JFactory::getDBO();
$database->setQuery
$database->execute();

но как я могу отловить ошибки / исключения, если запрос не выполняется по каким-либо причинам, что $database->getErrorNum()считается устаревшим?

DEV-м
источник

Ответы:

13

JError устарела в J3.x в пользу исключений PHP, так как в ней смешаны 2 разные концепции программирования : ведение журнала и обработка ошибок (теперь сторона ведения журнала реализована как JLog ).

Для вашего точного случая вы можете заключить код в блок try / catch, чтобы получить ошибку, как показано в этом ответе SO :

try {
    ...
    $db->setQuery($query);
    $result = $db->loadResult();
}
catch (Exception $e){
    echo $e->getMessage();
}

Обратите внимание, что $database->execute()указано, что НЕ работает в J2.5 . Вы должны использовать, $database->query()если вам нужен эквивалент.

В Joomla 2.5 и 3.x JDatabaseметоды объекта, updateRecord() а insertRecord()также выбрасывают ошибки, которые вы можете поймать, если они потерпят неудачу:

try {
    JFactory::getDbo()->updateObject('#_table_name', $data);
} catch (Exception $e) {
    //...handle the exception
}

Если вы разрабатываете только для Joomla 3.x, вы также можете использовать блок try catch с транзакциями SQL, чтобы получить подробную информацию об ошибке:

$db = JFactory::getDbo();

try {
    $db->transactionStart();

    $query = $db->getQuery(true);

    $values = array($db->quote('TEST_CONSTANT'), $db->quote('Custom'), $db->quote('/path/to/translation.ini'));

    $query->insert($db->quoteName('#__overrider'));
    $query->columns($db->quoteName(array('constant', 'string', 'file')));
    $query->values(implode(',',$values));

    $db->setQuery($query);
    $result = $db->execute();

    $db->transactionCommit();
}
catch (Exception $e) {
    // catch any database errors.
    $db->transactionRollback();
    JErrorPage::render($e);
}
codinghands
источник
в моей joomla 2.5.11 $ database-> execute (); работает хорошо, так как я делаю один компонент для joomla 2.5 и 3. Но ваш первый блок try-catch с execute () не работает в 2.5.11. Как вы сказали, методы объекта Jdatabase работают только с 2.5 и 3.1, поэтому не будем их использовать. Итак, какие еще методы доступны для реализации и совместимы с версиями J 2.5 и 3?
dev-m
Да, странно, документы, похоже, утверждают, что -> execute () не работает в 2.5. Буду редактировать. Методы объекта JDatabase должны работать во всех версиях
J3.X
1
«Но ваш первый блок try-catch с execute () не работает в 2.5.11» ... какую ошибку вы получаете, если есть?
codinghands
Я не проверял сообщение, но я поставил возвращение false; там, но он точно не возвращает false, поэтому контроль не входит в блок catch на моем сайте 2.5.11.
dev-m
Не могли бы вы включить отчеты об ошибках в глобальной конфигурации, чтобы увидеть, генерирует ли PHP какие-либо ошибки.
codinghands
0

В идеале установите pecl, затем расширьте соответствующий класс JDatabase * и переопределите JFactory :: getDbo () с помощью реализации, приведенной ниже, чтобы исключить необходимость в обновлениях кода в несколько миллиардов, чтобы обернуть каждый критический запрос БД в операторах try catch.

Следующая лучшая вещь для меня - это поддержка старого и нового способов:

Включите это где-нибудь

class jDbUtils
{
    protected static $dbErrorMessage = '';

    public static function stupidJ3CatchDatabaseExecute($db, $cmd, $report = false) {
        self::$dbErrorMessage = '';
        try {
            $res = $db->$cmd();
            // legacy db error support
            if (method_exists($db, 'getErrorNum') && $db->getErrorNum())
                throw new Exception($db->getErrorMsg());
            return $res;
        } catch(Exception $e) {
            self::$dbErrorMessage = $e->getMessage();
            if ($report)
                self::reportIfDbError();
            return false;
        }
    }

    public static function reportIfDbError()
    {
        if (self::$dbErrorMessage) {
            JFactory::getApplication()->enqueueMessage(self::$dbErrorMessage, 'error');
            return true;
        }
    }
}

Тогда используйте это как это

function someDbInteraction(){
    $db = JFactory::getDbo();
    $db->setQuery('SELECT no_such_col FROM no_such_table LIMIT 1');
    $res = jDbUtils::stupidJ3CatchDatabaseExecute($db, 'loadResult');
    if (jDbUtils::reportIfDbError())
        return false;
    // do more processing
    return $res;
}
ekerner
источник