sql >> Databáze >  >> RDS >> Oracle

cx_Oracle a zpracování výjimek – osvědčené postupy?

Pokud se však nemůže připojit, pak db níže nebude existovat - proto jsem nastavil db = None výše. Je to však dobrá praxe?

Ne, nastavení db = None není nejlepší praxe. Jsou dvě možnosti, buď připojení k databázi bude fungovat, nebo ne.

  • Připojení k databázi nefunguje:

    Protože vyvolaná výjimka byla zachycena a nebyla znovu vyvolána, budete pokračovat, dokud nedosáhnete cursor = db.Cursor() .

    db == None , takže výjimka, která se podobá TypeError: 'NoneType' object has no attribute 'Cursor' bude zvýšen. Vzhledem k tomu, že výjimka vygenerovaná při selhání připojení k databázi již byla zachycena, důvod selhání je skryt.

    Osobně bych vždy upozorňoval na výjimku připojení, pokud to zanedlouho nezkusíte znovu. Jak to chytíte, je na vás; pokud chyba přetrvává, pošlu e-mailem "jdi a zkontrolujte databázi".

  • Připojení k databázi funguje:

    Proměnná db je přiřazeno ve vašem try:... except blok. Pokud connect metoda funguje, pak db je nahrazeno objektem připojení.

V obou případech počáteční hodnota db se nikdy nepoužívá.

Slyšel jsem však, že používání zpracování výjimek pro řízení toku, jako je toto, je špatný postup.

Na rozdíl od jiných jazyků Python dělá použijte zpracování výjimek pro řízení toku. Na konci své odpovědi jsem propojil několik otázek o Stack Overflow a Programmers, které pokládají podobnou otázku. V každém příkladu uvidíte slova „ale v Pythonu“.

To neznamená, že byste to měli přehánět, ale Python obecně používá mantru EAFP, „Je snazší požádat o odpuštění než o povolení.“ Tři nejlépe volené příklady v části Jak zkontroluji, zda proměnná existuje? jsou dobrými příklady toho, jak můžete oba používat řízení toku nebo ne.

Je vnořování výjimek dobrý nápad? Nebo existuje lepší způsob, jak se vypořádat se závislými/kaskádovými výjimkami, jako je tento?

Na vnořených výjimkách není nic špatného, ​​ještě jednou, pokud to děláte rozumně. Zvažte svůj kód. Můžete odstranit všechny výjimky a celou věc zabalit do try:... except blok. Pokud se objeví výjimka, víte, co to bylo, ale je trochu těžší vysledovat, co přesně se pokazilo.

Co se pak stane, když se chcete o selhání cursor.execute informovat e-mailem ? Měli byste mít výjimku kolem cursor.execute k provedení tohoto jediného úkolu. Poté znovu vyvoláte výjimku, aby byla zachycena ve vašem vnějším try:... . Nenavýšení by vedlo k tomu, že by váš kód pokračoval, jako by se nic nestalo, a bez ohledu na logiku, kterou jste vložili do vnějšího try:... řešení výjimky by bylo ignorováno.

Nakonec jsou všechny výjimky zděděny z BaseException .

Také existují některé části (např. selhání připojení), kde bych chtěl, aby se skript právě ukončil – proto zakomentované volání sys.exit().

Přidal jsem jednoduchou třídu a jak ji nazvat, což je zhruba způsob, jakým bych udělal to, o co se snažíte. Pokud to bude běžet na pozadí, pak se tisk chyb nevyplatí - lidé tam nebudou sedět ručně a hledat chyby. Měli by být přihlášeni jakýmkoliv vaším standardním způsobem a měli by být informováni příslušní lidé. Z tohoto důvodu jsem odstranil tisk a nahradil jej připomenutím k přihlášení.

Když jsem connect třídu rozdělil na více funkcí metoda selže a je vyvolána výjimka execute volání se nespustí a skript se po pokusu o odpojení dokončí.

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

Pak tomu zavolejte:

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

Další čtení:

cx_Oracle dokumentaci

Proč nepoužít výjimky jako běžný tok kontroly?
Je zpracování výjimek v pythonu efektivnější než PHP a/nebo jiné jazyky?
Argumenty pro nebo proti použití try catch jako logických operátorů



  1. 4 způsoby, jak zkontrolovat typ dat sloupce v MariaDB

  2. Webinář:Nové funkce v Postgres 12 [Následovat]

  3. Výběr dat ze dvou různých serverů v SQL Server

  4. Jak opravit typické chyby WordPress