2009-04-07 13 views
10

Tengo un programa Java que es independiente de la base de datos y necesito saber, al insertar, si se produjo una excepción SQLException debido a una clave duplicada.Buscar si se produjo una excepción SQLException debido a un duplicado

Si estuviera usando un único controlador de base de datos simplemente usaría el Código de Error, pero como puedo usar motores muy diferentes, el Código de Error no es el mismo.

¿Alguien ha hecho esto antes? ¿Algunas ideas?

Muchos TIA!

Editar: Tengo un archivo de configuración donde almaceno la clase controlador (es decir: org.apache.derby.jdbc.ClientDriver) y alguna otra información necesaria (es decir: nombre de usuario, contraseña, URL ...). La conexión siempre pasa como una "java.SQL.Connection", así que realmente no me importa qué controladores se estén utilizando.

+0

¿Cómo está accediendo a los datos en el código? ¿Estás pasando por JDBC o tienes clases específicas de la base de datos? –

+0

Tengo un archivo de configuración donde se almacenan la clase de controlador y los parámetros de conexión. – ferro

Respuesta

7

Con JDBC básico, realmente no hay una manera de hacer lo que dice en una base de datos cruzada. Como mencionó getErrorCode podría utilizarse, pero se requieren códigos de error específicos del proveedor.

Las únicas tres maneras que veo de evitar esto es:

  1. utilizar algún tipo de marco que hace todo el traductor de código de error a excepciones significativas (Hibernate probablemente hacer esto, alguien ha mencionado que Spring lo hace)
  2. Compruebe la duplicación manualmente (con una selección) antes de hacer su inserción. (Esto no sería 100%, ya que es técnicamente posible que alguien haya hecho una inserción después de su consulta).
  3. Después de obtener cualquier excepción sql en la inserción, intente realizar una consulta para esa identificación. Si realmente puede encontrar la coincidencia, puede estar bastante seguro de que el error que recibió se debió a una clave principal duplicada. (Aunque es posible que haya problemas múltiples, y ese no fue realmente el que se lanzó).

Mi recomendación sería escribir su código para evitar el problema tanto como sea posible, y luego (si es absolutamente necesario), use # 3.

+0

# 3 no parece ser un buen consejo porque ignora la simultaneidad. Es decir, ¿qué pasa si alguna otra conexión elimina o agrega el registro en cuestión, pero esta conexión arrojó una excepción por un motivo completamente relacionado? No hay forma de que esta conexión bloquee una fila que no está allí, por lo que no puede probar que es la indicada. (Supongo que podría bloquear toda la tabla, pero minimiza el acceso simultáneo a la tabla.) Realmente, entonces, los números 2 y 3 tienen los mismos problemas de simultaneidad; eso nos deja con el # 1 como la única opción viable. – MikeB

0

Creo que una manera simple y confiable es verificar si la clave existe antes de hacer la inserción. Como correctamente ha señalado, cada base de datos tiene su propia forma de informar el error.

+0

Depende de cómo se accede a los datos en el código. Esto no está claro a partir de la pregunta, así que definitivamente no diría que esta es la "única" manera. –

+0

No puedo ver cómo los datos que se acceden en el código afectarán a una clave duplicada en la inserción. Sin embargo, no puedo afirmar que esta es la única solución. Mi respuesta ha sido modificada. – wentbackward

1

Bueno, si no puede confiar en la excepción para decirle por qué se lanzó, puede probar siguiendo la excepción con un "select count (*) from table where key = @keyfailedtoinsert;"

Desafortunadamente, no se garantiza que la excepción le proporcione el nombre de la tabla y el nombre de la clave. En algunos casos, el código java llamado llamado controlador JDBC puede que nunca los haya tenido, por ejemplo, si el inserto sucedió con un procedimiento almacenado o como un desencadenante.

Ha vuelto a tener que confiar en el proveedor de cada controlador JDBC.

2

Puede "entrenar" el programa al inicio (o config) insertando una clave duplicada conocida y registrando el código de error generado.

+0

Esto supone que el error devuelto es de hecho la clave duplicada en la inserción. No tienes forma de demostrar que el error fue, de hecho, el que esperabas. – wentbackward

+0

@wentbackward: puede tomar el 90% de los casos y asumir que es correcto después de conectar, seleccionar, probar, seleccionar y/o simplemente pedirle al usuario que lea el mensaje de error y confirme. No es una ciencia exacta, pero es muy probable que esté lo suficientemente cerca. –

0

¿Echo de menos algo? Si está utilizando JDBC, debe obtener una excepción de clave duplicada, independientemente de la base de datos que se utilice.

¿O le preguntó cómo determinaría un dupkey ANTES de probar el inserto?

-1

Supongo que no está utilizando JDBC o esto sería una búsqueda de error muy simple.

¿Tiene un conjunto diferente de clases para acceder a las diferentes bases de datos? Si es así, podría atrapar la excepción en las clases específicas de la base de datos y arrojar su propio tipo de excepción que se comparte entre todos los tipos de bases de datos.

2

Creo que la solución ideal sería hacer que la capa de datos arroje una excepción específica en este caso, tal vez una subclase de SQLException para DuplicateKeyException o algo similar.

Si desea poder tratar diferentes excepciones de manera diferente, debe lanzar diferentes tipos de excepción (o subtipos) para comenzar.

Creo que esta es un área donde el Spring Framework hace que las cosas realmente correcta: proporcionan a very rich hierarchy of "database exceptions" todos los cuales se extienden DataAccessException, con sub-árboles de tipos para "excepciones recuperables", "excepciones transitorias", "excepciones de integridad de datos" , etc. Esto deja al código del cliente libre para capturar cualquiera (o ninguno) de los tipos de excepción que puede manejar o preocuparse: excepciones que indican un error que puede no ser repetible si re-ejecuta la transacción, un error fatal -recortable error, o simplemente puede atrapar el tipo de raíz.

8

Esto es exactamente para lo que es SQLException.getSQLState(). Según Google, "23000" indica una violación de restricción única en al menos MySQL, PostgreSQL y Oracle.

+1

Por ejemplo, en DB2 no es lo mismo – ferro

+0

Hrm, tienes razón. ¿Cuántas bases de datos necesita para apoyar? ¿Es realmente un número infinito? Tal vez sea mejor que averigüe qué es el par SQLState/ErrorCode para cada DB y maneje todos. Todavía funcionará mucho, mucho mejor que hacer un SELECCIONAR para verificar la fila antes de tiempo. –

+0

Voy a crear un método que recibirá la conexión de base de datos, para verificar qué controlador se está utilizando, y la excepción, luego compararé el getSQLState() y verifica si es una clave duplicada. – ferro

Cuestiones relacionadas