Oracle
 sql >> Baza danych >  >> RDS >> Oracle

cx_Oracle i obsługa wyjątków — dobre praktyki?

Jeśli jednak nie może się połączyć, to db nie będzie istnieć dalej - dlatego ustawiłem db = None nad. Czy to jednak dobra praktyka?

Nie, ustawienie db = None nie jest najlepszą praktyką. Istnieją dwie możliwości, albo połączenie z bazą danych będzie działać, albo nie.

  • Połączenie z bazą danych nie działa:

    Ponieważ zgłoszony wyjątek został przechwycony i nie został ponownie zgłoszony, kontynuujesz, dopóki nie osiągniesz cursor = db.Cursor() .

    db == None , więc wyjątek przypominający TypeError: 'NoneType' object has no attribute 'Cursor' zostanie podniesiony. Ponieważ wyjątek generowany, gdy połączenie z bazą danych nie powiodło się, zostało już przechwycone, przyczyna niepowodzenia jest zamaskowana.

    Osobiście zawsze zgłaszam wyjątek dotyczący połączenia, chyba że zamierzasz wkrótce spróbować ponownie. Jak to złapiesz, zależy od ciebie; jeśli błąd będzie się powtarzał, piszę e-mailem "idź i sprawdź bazę danych".

  • Połączenie z bazą danych działa:

    Zmienna db jest przypisany w twoim try:... except blok. Jeśli connect metoda działa wtedy db zostanie zastąpiony obiektem połączenia.

Tak czy inaczej, początkowa wartość db nigdy nie jest używany.

Jednak słyszałem, że używanie obsługi wyjątków do kontroli przepływu, jak to jest złą praktyką.

W przeciwieństwie do innych języków Python robi użyj obsługi wyjątków do kontroli przepływu. Na końcu mojej odpowiedzi podałem link do kilku pytań dotyczących przepełnienia stosu i programistów, które zadają podobne pytanie. W każdym przykładzie zobaczysz słowa „ale w Pythonie”.

Nie oznacza to, że powinieneś przesadzać, ale Python generalnie używa mantry EAFP, "Łatwiej prosić o wybaczenie niż o pozwolenie." Trzy najczęściej głosowane przykłady w artykule Jak sprawdzić, czy istnieje zmienna? są dobrymi przykładami tego, jak można używać kontroli przepływu lub nie.

Czy zagnieżdżanie wyjątków to dobry pomysł? A może istnieje lepszy sposób radzenia sobie z zależnymi/kaskadowymi wyjątkami, takimi jak ten?

Nie ma nic złego w zagnieżdżonych wyjątkach, o ile robisz to rozsądnie. Rozważ swój kod. Możesz usunąć wszystkie wyjątki i zapakować całość w try:... except blok. Jeśli zostanie zgłoszony wyjątek, wiesz, co to było, ale trochę trudniej jest dokładnie wyśledzić, co poszło nie tak.

Co się wtedy stanie, jeśli chcesz sam powiedzieć e-mail w przypadku niepowodzenia cursor.execute ? Powinieneś mieć wyjątek wokół cursor.execute w celu wykonania tego jednego zadania. Następnie ponownie podnosisz wyjątek, aby został przechwycony w zewnętrznym try:... . Brak ponownego podbicia spowoduje, że kod będzie kontynuowany tak, jakby nic się nie wydarzyło, i jakąkolwiek logikę umieściłeś w swoim zewnętrznym try:... radzenie sobie z wyjątkiem zostanie zignorowane.

Ostatecznie wszystkie wyjątki są dziedziczone z BaseException .

Ponadto są pewne części (np. awarie połączenia), w których chciałbym, aby skrypt po prostu się zakończył - stąd zakomentowane wywołanie sys.exit().

Dodałem prostą klasę i sposób jej nazywania, czyli mniej więcej tak, jak zrobiłbym to, co próbujesz zrobić. Jeśli ma to być uruchomione w tle, drukowanie błędów nie jest warte zachodu - ludzie nie będą tam siedzieć ręcznie, szukając błędów. Powinni oni być zalogowani w dowolny sposób, a odpowiednie osoby powiadomione. Z tego powodu usunąłem drukowanie i zastąpiłem je przypomnieniem o logowaniu.

Ponieważ podzieliłem klasę na wiele funkcji, gdy connect metoda kończy się niepowodzeniem i zgłaszany jest wyjątek execute wywołanie nie zostanie uruchomione, a skrypt zakończy się po próbie rozłączenia.

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()

Następnie zadzwoń:

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()

Dalsza lektura:

cx_Oracle dokumentacja

Dlaczego nie używać wyjątków jako zwykłego przepływu kontroli?
Czy obsługa wyjątków Pythona jest bardziej wydajna niż PHP i/lub inne języki?
Argumenty za lub przeciw używaniu try catch jako operatorów logicznych



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. jak wstawić aktualną datę do pola DATE w formacie dd/mm/rrrr w Oracle

  2. Oracle:jaka jest sytuacja, aby użyć RAISE_APPLICATION_ERROR?

  3. Dostawca OraOLEDB.Oracle nie jest zarejestrowany na komputerze lokalnym

  4. Liczba piątków między dwiema datami

  5. Wymuszaj ograniczenie klucza obcego do kolumn tej samej tabeli