Estoy tratando de utilizar cx_Oracle para conectarse a una instancia de Oracle y ejecutar algunas instrucciones DDL:

db = None
try:
    db = cx_Oracle.connect('username', 'password', 'hostname:port/SERVICENAME')
#print(db.version)
except cx_Oracle.DatabaseError as e:
    error, = e.args
    if error.code == 1017:
        print('Please check your credentials.')
        # sys.exit()?
    else:
        print('Database connection error: %s'.format(e))
cursor = db.cursor()
try:
    cursor.execute(ddl_statements)
except cx_Oracle.DatabaseError as e:
    error, = e.args
    if error.code == 955:
        print('Table already exists')
    if error.code == 1031:
        print("Insufficient privileges - are you sure you're using the owner account?")
    print(error.code)
    print(error.message)
    print(error.context)
cursor.close()
db.commit()
db.close()

Sin embargo, no estoy muy seguro de cuál es el mejor diseño para el manejo de excepciones aquí.

En primer lugar, creo que la db objeto dentro de un bloque try, para detectar los errores de conexión.

Sin embargo, si no se puede conectar, luego db no existen más abajo – que es por eso que me puse db = None arriba. Sin embargo, es que una buena práctica?

Idealmente, necesito para detectar los errores con la conexión, a continuación, los errores de la ejecución de las instrucciones DDL, y así sucesivamente.

Es de anidación de las excepciones es una buena idea? O hay una mejor manera de tratar con los dependientes/cascada excepciones como esta?

También, hay algunas partes (por ejemplo, fallos en la conexión), donde me gustaría que el script se acaba de terminar – de ahí el comentario sys.exit() llamada. Sin embargo, he oído que el manejo de excepciones para el control de flujo como esta es una mala práctica. Los pensamientos?

  • Dudo que usted necesita para manejar por separado los códigos de error para imprimir ellos, la excepción debe tener los mensajes desde el controlador. Usted puede utilizar excepciones anidadas por ejemplo, si usted realiza la conmutación por error de código, como tratar de consulta -> fallos> volver a conectar -> vuelva a intentarlo. Su flujo de código se ve bien para mí. Una buena idea puede ser crear una función y poner el código de limpieza en el bloque finally (cerca de cursor db etc)
InformationsquelleAutor victorhooi | 2011-09-19

2 Comentarios

  1. 31

    Sin embargo, si no se puede conectar, luego db no existen más abajo –
    es por eso que establecer db = None arriba. Sin embargo, es que una buena práctica?

    No, la configuración de db = None no es la mejor práctica. Hay dos posibilidades, o bien la conexión a la base de datos funcionará o no.

    • La conexión a la base de datos no funciona:

      Como la excepción ha sido atrapado y no una re-subida continúa hasta llegar a cursor = db.Cursor().

      db == None, así, una excepción similar TypeError: 'NoneType' object has no attribute 'Cursor' serán resucitados. Como la excepción generada cuando la base de datos error de conexión ya ha sido capturado, la razón del fracaso es encubierta.

      Personalmente, yo siempre iba a plantear una excepción de la conexión, a menos que usted va a tratar de nuevo en breve. Cómo se captura es de usted; si el error persiste I e-mail a decir «vaya y compruebe la base de datos».

    • La conexión a la base de datos no funciona:

      La variable db es asignado en su try:... except bloque. Si el connect método no funciona, entonces db es reemplazado con el objeto de conexión.

    De cualquier manera, el valor inicial de db no se utiliza nunca.

    Sin embargo, he oído que el manejo de excepciones para el control de flujo
    como esta es una mala práctica.

    A diferencia de otros lenguajes Python hace utilizar el manejo de excepciones para el control de flujo. Al final de mi respuesta me he ligado a una serie de preguntas en el Desbordamiento de Pila y los Programadores que hacen una pregunta similar. En cada ejemplo se verá las palabras», pero en Python».

    Eso no quiere decir que usted debe ir por la borda, pero Python utiliza el mantra EAFP, «Es más fácil pedir perdón que permiso». Los tres primeros votado ejemplos en ¿Cómo puedo comprobar si una variable existe? son buenos ejemplos de cómo usted puede utilizar el control de flujo o no.

    Es de anidación de las excepciones es una buena idea? O hay una mejor manera de tratar
    con dependientes/cascada excepciones como esta?

    No hay nada de malo con excepciones anidadas, una vez más, como siempre que lo haga con cordura. Considere la posibilidad de su código. Puede eliminar todas las excepciones y envolver todo en un try:... except bloque. Si se produce una excepción, entonces usted sabe lo que era, pero es un poco más difícil de rastrear exactamente lo que salió mal.

    Entonces, ¿qué ocurre si usted desea decir de correo electrónico a ti mismo en el fracaso de cursor.execute? Usted debe tener una excepción alrededor de cursor.execute en el fin de realizar esta tarea. Usted, a continuación, volver a subir la excepción por lo que queda atrapado en su exterior try:.... No volver a subir sería el resultado en el código de continuar como si nada hubiera pasado y lo que la lógica se había puesto en su exterior try:... para lidiar con una excepción sería ignorado.

    En última instancia, todas las excepciones se heredan de BaseException.

    También, hay algunas partes (por ejemplo, fallos en la conexión), donde me gustaría
    la secuencia de comandos que acaba de terminar – de ahí el comentario sys.llamada exit ().

    He añadido una simple clase y cómo lo llaman, que es más o menos como me gustaría hacer lo que estamos tratando de hacer. Si esto va a ser ejecutado en el fondo, a continuación, la impresión de los errores no vale la pena – la gente no va a estar sentado allí manualmente buscando errores. Se debe haber iniciado sesión en cualquiera que sea su forma estándar es y las personas adecuadas notificado. Me he quitado la impresión por esta razón y reemplazado con un recordatorio de registro.

    Como he dividido la clase en múltiples funciones cuando el connect método falla y se produce una excepción, el execute llamada no ejecutarse el script va a terminar, después de intentar desconectar.

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

    A continuación, llamar:

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

    Leer más:

    cx_Oracle documentación

    ¿Por qué no utilizar excepciones como regular el flujo de control?

    Es python excepción manejo más eficiente de PHP y/o en otros idiomas?

    Argumentos a favor o en contra del uso de try catch como operadores lógicos

    • Estoy usando el fragmento de código que usted sugirió Ben, pero estoy chocando con el siguiente error ORA-24550: señal recibida: excepción no Controlada: Código=c0000005 Flags=0 no es capaz de atrapar la excepción en host incorrecta o SID entrada y mi python Django servidor se bloquea
    • Supongo este es tu pregunta @sarath. Esta es una de Oracle problema, nada que ver con el Python y no veo la manera de que su servidor Django es relevante, a menos que usted está diciendo quecx_Oracle.DatabaseError no es la captura de la excepción. Puede agregar más detalles a tu pregunta?
    • Así que la declaración cx_Oracle.connect es no ser atrapado por mi bloques de excepción en mal anfitrión y SID entrada. ¿Cómo capturar la excepción estoy utilizando cx.Oracle.conectar en un bloque try, con excepción de los bloques que siga como excepción cx_Oracle.DatabaseError como e: error = e.args si el error.código == 1017: print(‘por Favor, compruebe sus credenciales.’) else: print(‘Base de datos de error de conexión: %s’ % (e,)) elevar excepto cx_Oracle.Error como e: error=e.args print («Error.’) elevar
    • Yo no voy a ser capaz de responder a una pregunta en los comentarios de @sarath, usted necesita preguntarse a uno (y si se quiere conservar la eliminación de ellos obtendrá pregunta prohibido así que no lo hagas). Acaba de editar su pregunta anterior con toda la información. Usted en realidad no ha publicado el código exacto que usted está usando o el mensaje de error exacto que estás recibiendo de Python. No se captura la excepción, vamos a ser planteadas y ver lo que es.
    • El connect no debería estar dentro del bloque try.
    • En __main__ @Beau? Gracias, me he mudado a cabo. También he quitado print que ha sido molesto conmigo por 6 años.
    • Sí, mucho mejor @Ben 👍
    • Hmm…. usted se olvidó de crear Orcale instancia en la principal

  2. 1

    Diferente y, posiblemente, elegante solución es utilizar un decorador a su Base de datos las funciones de llamada. El decorador permite la posibilidad de remediar el error y tratar de la Base de datos de llamar de nuevo. Para obsoleto de las conexiones, la remediación es volver a conectar y volver a emitir la llamada.
    Aquí está el decorador, que trabajó para mí:

    ####### Decorator named dbReconnect ########
    #Retry decorator
    #Retries a database function twice when  the 1st fails on a stale connection
    def dbReconnect():
        def real_decorator(function):
            def wrapper(*args, **kwargs):
                try:
                    return function(*args, **kwargs)
                except  Exception as inst:
                    print ("DB error({0}):".format(inst))
                    print ("Reconnecting")
                    #...Code for reconnection is to be placed here..
                    ......
                    #..end of code for reconnection
                return function(*args, **kwargs)
            return wrapper
        return real_decorator
    
    ###### Decorate the DB Call like this: #####
        @dbReconnect()
        def DB_FcnCall(...):
        ....

    Más detalles en Github: https://github.com/vvaradarajan/DecoratorForDBReconnect/wiki

    Nota: Si utiliza grupos de conexión, la conexión interna de la piscina técnicas que comprobar una conexión y se actualiza si rancio, también va a resolver el problema.

Dejar respuesta

Please enter your comment!
Please enter your name here