Oracle
 sql >> база данни >  >> RDS >> Oracle

cx_Oracle и обработка на изключения – добри практики?

Ако обаче не може да се свърже, тогава db няма да съществува по-надолу - поради което зададох db = None по-горе. Това обаче добра практика ли е?

Не, настройка db = None не е най-добрата практика. Има две възможности, или свързването с базата данни ще работи, или не.

  • Свързването с базата данни не работи:

    Тъй като повдигнатото изключение е било уловено и не е повторно рейзвано, продължавате, докато достигнете cursor = db.Cursor() .

    db == None , така че изключение, което прилича на TypeError: 'NoneType' object has no attribute 'Cursor' ще бъдат повдигнати. Тъй като изключението, генерирано при неуспешна връзка с базата данни, вече е уловено, причината за неуспеха е прикрита.

    Лично аз винаги бих повдигнал изключение за връзка, освен ако няма да опитате отново скоро. Как ще го хванете зависи от вас; ако грешката продължава, изпращам имейл, за да кажа "отидете и проверете базата данни".

  • Свързването с базата данни работи:

    Променливата db е присвоен във вашия try:... except блок. Ако connect методът работи, тогава db се заменя с обекта за връзка.

Така или иначе първоначалната стойност на db никога не се използва.

Чух обаче, че използването на обработка на изключения за контрол на потока като това е лоша практика.

За разлика от други езици Python прави използвайте обработка на изключения за контрол на потока. В края на отговора си се свързах с няколко въпроса относно препълването на стека и програмистите, които задават подобен въпрос. Във всеки пример ще видите думите "но в Python".

Това не означава, че трябва да прекалявате, но Python обикновено използва мантрата EAFP, „По-лесно е да поискаш прошка, отколкото разрешение.“ Първите три гласувани примера в Как да проверя дали съществува променлива? са добри примери за това как и двамата можете да използвате контрол на потока или не.

Добра идея ли е изключенията за гнездене? Или има по-добър начин за справяне със зависими/каскадни изключения като този?

Няма нищо лошо във вложените изключения, още веднъж, стига да го правите разумно. Помислете за вашия код. Можете да премахнете всички изключения и да обвиете цялото нещо в try:... except блок. Ако бъде повдигнато изключение, тогава знаете какво е било, но е малко по-трудно да се проследи точно какво се е объркало.

Какво ще се случи тогава, ако искате да си кажете имейл при неуспех на cursor.execute ? Трябва да имате изключение около cursor.execute за да изпълни тази една задача. След това повдигате отново изключението, така че да бъде уловено във вашия външен try:... . Ако не се повдига повторно, кодът ви ще продължи, сякаш нищо не се е случило и каквато и логика да сте вложили във външния си try:... за справяне с изключение ще бъде игнорирано.

В крайна сметка всички изключения са наследени от BaseException .

Освен това има някои части (напр. неуспехи на връзката), където бих искал скриптът просто да приключи - оттук и коментираното извикване sys.exit().

Добавих прост клас и как да го нарека, което е приблизително как бих направил това, което се опитвате да направите. Ако това ще се изпълнява във фонов режим, тогава отпечатването на грешките не си струва - хората няма да седят там ръчно и да търсят грешки. Те трябва да бъдат влезли по какъвто и да е стандартният ви начин и да бъдат уведомени съответните хора. Премахнах отпечатването поради тази причина и го замених с напомняне за влизане.

Тъй като разделих класа на множество функции, когато connect методът е неуспешен и се създава изключение execute повикването няма да се изпълни и скриптът ще завърши, след като се опита да прекъсне връзката.

import cx_Oracle

class Oracle(object):

    def connect(self, username, password, hostname, port, servicename):
        """ Connect to the database. """

        try:
            self.db = cx_Oracle.connect(username, password
                                , hostname + ':' + port + '/' + servicename)
        except cx_Oracle.DatabaseError as e:
            # Log error as appropriate
            raise

        # If the database connection succeeded create the cursor
        # we-re going to use.
        self.cursor = self.db.cursor()

    def disconnect(self):
        """
        Disconnect from the database. If this fails, for instance
        if the connection instance doesn't exist, ignore the exception.
        """

        try:
            self.cursor.close()
            self.db.close()
        except cx_Oracle.DatabaseError:
            pass

    def execute(self, sql, bindvars=None, commit=False):
        """
        Execute whatever SQL statements are passed to the method;
        commit if specified. Do not specify fetchall() in here as
        the SQL statement may not be a select.
        bindvars is a dictionary of variables you pass to execute.
        """

        try:
            self.cursor.execute(sql, bindvars)
        except cx_Oracle.DatabaseError as e:
            # Log error as appropriate
            raise

        # Only commit if it-s necessary.
        if commit:
            self.db.commit()

След това го обадете:

if __name__ == "__main__":

    oracle = Oracle.connect('username', 'password', 'hostname'
                           , 'port', 'servicename')

    try:
        # No commit as you don-t need to commit DDL.
        oracle.execute('ddl_statements')

    # Ensure that we always disconnect from the database to avoid
    # ORA-00018: Maximum number of sessions exceeded. 
    finally:
        oracle.disconnect()

Допълнително четене:

cx_Oracle документация

Защо да не използвате изключения като редовен поток на контрол?
По-ефективно ли е обработката на изключенията в python от PHP и/или други езици?
Аргументи за или против използването на try catch като логически оператори



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. изчислете текущия баланс в заявка на Oracle

  2. Как да промените формата на датата във вашата сесия на Oracle

  3. Промени в сервизната група в R12.2

  4. Автоматично увеличение в Oracle без използване на тригер

  5. Как да върнете корекцията след неуспешна фаза на превключване в R12.2