sql >> Database >  >> RDS >> Oracle

cx_Oracle en Exception Handling - Goede praktijken?

Als het echter geen verbinding kan maken, dan db zal niet verder bestaan ​​- daarom heb ik db = None . ingesteld boven. Is dat echter een goede gewoonte?

Nee, instelling db = None is geen beste praktijk. Er zijn twee mogelijkheden:verbinding maken met de database werkt of niet.

  • Verbinding maken met de database werkt niet:

    Aangezien de verhoogde uitzondering is opgevangen en niet opnieuw is verhoogd, gaat u verder totdat u cursor = db.Cursor() bereikt. .

    db == None , dus een uitzondering die lijkt op TypeError: 'NoneType' object has no attribute 'Cursor' zal worden verhoogd. Omdat de uitzondering die werd gegenereerd toen de databaseverbinding mislukte al is opgevangen, is de reden voor de fout verhuld.

    Persoonlijk zou ik altijd een verbindingsuitzondering aanmaken, tenzij je het binnenkort opnieuw gaat proberen. Hoe je het vangt is aan jou; als de fout zich blijft voordoen, stuur ik een e-mail om te zeggen "ga de database controleren".

  • Verbinding maken met de database werkt wel:

    De variabele db is toegewezen in uw try:... except blok. Als de connect methode werkt dan db wordt vervangen door het verbindingsobject.

Hoe dan ook de initiële waarde van db wordt nooit gebruikt.

Ik heb echter gehoord dat het een slechte gewoonte is om exception handling voor flow control te gebruiken.

In tegenstelling tot andere talen doet Python dat wel gebruik exception handling voor flow control. Aan het einde van mijn antwoord heb ik gekoppeld aan verschillende vragen over Stack Overflow en Programmers die een vergelijkbare vraag stellen. In elk voorbeeld zie je de woorden "maar in Python".

Dat wil niet zeggen dat je overboord moet gaan, maar Python gebruikt over het algemeen de mantra EAFP, "Het is gemakkelijker om vergeving te vragen dan toestemming." De top drie gestemde voorbeelden in Hoe controleer ik of een variabele bestaat? zijn goede voorbeelden van hoe je zowel flow control kunt gebruiken als niet.

Zijn nestuitzonderingen een goed idee? Of is er een betere manier om met dergelijke afhankelijke/cascade-uitzonderingen om te gaan?

Er is niets mis met geneste uitzonderingen, nogmaals, zolang je het verstandig doet. Denk aan je code. Je zou alle uitzonderingen kunnen verwijderen en het hele ding in een try:... except . kunnen stoppen blok. Als er een uitzondering wordt gemaakt, weet je wat het was, maar het is iets moeilijker om op te sporen wat er precies is misgegaan.

Wat gebeurt er dan als je jezelf wilt e-mailen over het falen van cursor.execute ? Je zou een uitzondering moeten hebben rond cursor.execute om deze ene taak uit te voeren. Je verhoogt dan de uitzondering opnieuw zodat deze gevangen wordt in je buitenste try:... . Als je niet opnieuw verhoogt, zou je code doorgaan alsof er niets was gebeurd en welke logica je ook in je buitenste try:... had gestopt om te gaan met een uitzondering zou worden genegeerd.

Uiteindelijk worden alle uitzonderingen overgenomen van BaseException .

Er zijn ook enkele delen (bijv. verbindingsfouten) waarvan ik zou willen dat het script gewoon wordt beëindigd - vandaar de becommentarieerde sys.exit()-aanroep.

Ik heb een eenvoudige klasse toegevoegd en hoe deze te noemen, wat ongeveer is hoe ik zou doen wat je probeert te doen. Als dit op de achtergrond wordt uitgevoerd, is het afdrukken van de fouten niet de moeite waard - mensen zullen daar niet handmatig naar fouten zoeken. Ze moeten zijn ingelogd, wat uw standaardmanier ook is, en de juiste mensen moeten op de hoogte worden gesteld. Ik heb de afdrukken om deze reden verwijderd en vervangen door een herinnering om in te loggen.

Omdat ik de klas heb opgesplitst in meerdere functies wanneer de connect methode mislukt en er wordt een uitzondering gemaakt execute oproep zal niet worden uitgevoerd en het script zal eindigen, na een poging om de verbinding te verbreken.

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

Noem het dan:

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

Verder lezen:

cx_Oracle documentatie

Waarom gebruik je geen exceptions als reguliere controle?
Is de afhandeling van uitzonderingen in Python efficiënter dan PHP en/of andere talen?
Argumenten voor of tegen het gebruik van try catch als logische operatoren



  1. 2 manieren om dubbele rijen in Oracle te verwijderen

  2. SQL Server v.Next:STRING_AGG Prestaties, deel 2

  3. Hoe make_timestamptz() werkt in PostgreSQL

  4. Hoe MySQL-databases in de opdrachtregel te importeren