2010-12-15 25 views
28

Me he preguntado durante mucho tiempo por qué la API de JDBC proporciona un modo de confirmación automática (java.sql.Connection.setAutocommit()). Parece una molestia atractiva que solo atrae a la gente a problemas. Mi teoría es que solo se agregó a JDBC para simplificar la vida de los proveedores que querían crear herramientas para editar y ejecutar SQL utilizando JDBC. ¿Hay alguna otra razón para activar el compromiso automático o siempre es un error?¿Por qué configurar Autocommit en true?

Respuesta

11

Desafortunadamente, el uso de autocommit es específico de la base de datos (como es el comportamiento de la transacción). Creo que si no tienes una estrategia global de transacciones programáticas, la confirmación automática es probablemente mejor que simplemente esperar que todos cierren/cancelen las transacciones correctamente.

Hablando en MySQL, puede dejar autocommit = true activado de forma predeterminada, y se apagará automáticamente cuando COMIENCE una transacción. La única razón para establecer autocommit = false es si desea forzar un error si alguien intenta iniciar una transacción sin un BEGIN.

Para simplificar en una aplicación Java + MySQL típica de hoy, me gustaría más o menos ignorar la configuración de confirmación automática, utilizar un patrón de sesión abierta en vista y llamarlo bueno.

Desaconsejaré explícitamente los bloqueos de fila de RDBMS explícitos y utilizaré en su lugar cerraduras optimistas. Hibernate ofrece soporte integrado para bloqueos optimistas, pero es un patrón fácil de adoptar incluso para código enrollado a mano y ofrece un mejor rendimiento.

+2

Para aclarar el típico Ja Aplicación va + MySQL: deje la confirmación automática establecida en verdadero. Abra una sesión (y comience una transacción) una vez, al comienzo de la solicitud entrante (ya sea una página web o un REST/JSON). Si la solicitud procesa normalmente, confirme la transacción al final del proceso de solicitud. Luego, agregue una vuelta atrás a su representación de 500 páginas para la solicitud. Esta es básicamente la forma en que Play Framework maneja las cosas, por ejemplo. Es intuitivo para el usuario y el desarrollador. –

+0

Esta es una buena respuesta: "solicitud web" debería correlacionarse bastante con la "transacción DB" en una aplicación web. Por lo tanto, necesitamos confiar en el bloqueo optimista, no DB. Ayuda utilizar OpenSessionInView para mantener abierta una sesión a lo largo de toda la solicitud, incluido el renderizado de vista, y luego vaciar/confirmar al final de la solicitud. –

+0

En mi opinión, no es una buena respuesta, si la aplicación típica Java + MySQL es algo más que un "proyecto por algunas semanas", considere la sesión abierta en la vista como antipatrón. Perderá rápidamente el control de lo que ocurre en su aplicación, prácticamente seguro conducirá a problemas de rendimiento o concurrencia, la confirmación automática lo dejará sin tiempo de espera de transacción o tiempo de espera de transacción funcionando como "tiempo de espera de procesamiento de solicitud general". Yo declararía que la solicitud web NO tiene correlaciones en la transacción de SQL en más del 90% de los casos –

5

El modo de compromiso cambia la forma en que el db mantiene bloqueos.

Se recomienda desactivar el modo de confirmación automática solo durante el modo de transacción. De esta forma, evitará mantener bloqueos de base de datos para varias sentencias, lo que aumenta la probabilidad de conflictos con otros usuarios.

...

Para evitar conflictos durante una transacción, un DBMS utiliza cerraduras, mecanismos para bloquear el acceso de otros a los datos que se esté accediendo a la transacción. (Tenga en cuenta que en el modo auto-commit, donde cada declaración es una transacción, bloqueos se mantienen durante una sola declaración.)

http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

Dado que incluso mySQL y DB2 tienen varias versiones en la actualidad, ese tutorial se está volviendo algo anacrónico. :( – Affe

+0

Los niveles de aislamiento de instantáneas no se obtienen de forma gratuita: http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/overhead-of-row-versioning.aspx Obtiene concurrencia con el aislamiento de instantáneas , pero agrega sobrecarga. – hythlodayr

+0

Entender la forma en que adquiere los bloqueos siempre es relevante. –

18

única razón razonable que puedo ver es la de deshacerse de la connection.commit() y connection.rollback() repetitivo en transacciones sencillas de consulta simple en aplicaciones pequeñas. JDBC en forma cruda requiere por sí solo una gran repetición. Cada línea menos hace que JDBC sea menos aterrador para los principiantes.

3

El 95% de la base de código con la que estoy trabajando ahora implica actualizaciones únicas donde la confirmación automática es perfectamente razonable. Por lo tanto, estamos predeterminados para eso. Solo lo apaga el tiempo suficiente para hacer las secciones de código que deben ser una transacción, ¡y luego vuelve a activarse automáticamente!

+0

Tenga en cuenta que las transacciones también le pueden dar un tiempo de espera de transacción de su administrador de transacciones. ¿Estableces tiempo de espera en cada una de tus consultas? –

8

Casi siempre funciono con autocommit = true. 99% del tiempo, mis actualizaciones son atómicas. Claro, hay casos en los que escribe el débito y luego falla al intentar escribir el crédito que desea revertir. Pero en mi experiencia, estos son relativamente raros. Por lo general, cada registro que escribo se sostiene por sí mismo. En ese caso, no es necesario preocuparse por hacer una confirmación después de cada escritura es conveniente. Guarda una línea de código aquí y allá. Puede ahorrar más que eso si, dada la estructura del programa, significa que no necesito un bloque try/catch adicional o que no necesito pasar un objeto de conexión entre funciones. Ahorra en molestos errores donde alguien olvidó hacer un commit.

La única forma en que veo que podría "atraer a alguien a problemas" es que decide desactivar Autocommit y realizar la confirmación o reversión es demasiado problema, por lo que realiza actualizaciones que deben realizarse en una transacción individualmente. Entonces todo parece funcionar bien siempre y cuando no pase nada que deba abortar la transacción. Si los escenarios de prueba son inadecuados, podría imaginarse que esto se deslice hacia la producción.

Pero podría decir lo mismo sobre casi cualquier característica de un idioma. Como, supongamos que escribes un programa que procesa números que el 90% del tiempo cabrán en un largo, pero de vez en cuando puede ser más grande. Frente a esta situación, lo correcto es usar BigInteger o crear una nueva clase para manejar los números más grandes. Un programador perezoso puede ser atraído a usar mucho porque normalmente funcionará y otras alternativas son demasiados problemas. ¿Concluiría por lo tanto que Java no debería incluir long (o int) porque alguien podría ser atraído a usarlos cuando no son apropiados?

Si en sus programas la mayoría de las actualizaciones deben realizarse dentro del contexto de una transacción, desactive la confirmación automática. Su presencia no te hace daño. Está ahí para cuando sea conveniente, pero cuando no lo esté, puede apagarlo.

+1

Desde la especificación JDBC 3, las conexiones en el modo "autocompromiso" no pueden tener más de una instrucción abierta. Por lo tanto, UPDATEs anidados o incluso SELECT dentro de un bucle SELECT externo causará problemas. –

+0

No es solo atomicidad, la transacción también puede tener un tiempo de espera asignado si el administrador de transacciones lo admite. El uso de autocommit y ningún tiempo de espera de consulta puede llevarlo a problemas de rendimiento de SQL no detectados, consultas pesadas colgadas, etc. –

+0

He estado fuera de Javaland durante años, por lo que quizás las versiones más nuevas de Java sean diferentes o simplemente estoy recordando cosas incorrectamente. Pero estoy bastante seguro de que obtuve tiempos de espera de SQL al ejecutar consultas con autocommit. Tengo muchos buenos recuerdos de las consultas que se ejecutaron en el entorno de desarrollo, pero se agotó el tiempo de espera en prod. Tal vez los valores predeterminados son diferentes o algo así. En cualquier caso, confiar en un tiempo de espera para decirle que tiene un problema de rendimiento es una herramienta muy contundente. – Jay

6

La confirmación automática es conveniente; pero con los cambios a la especificación JDBC 3, se ha vuelto mucho menos útil.

Dado que las 3 conexiones JDBC en modo "confirmación automática" no pueden tener más de una instrucción abierta. Al ejecutar otra instrucción, se cerrará la primera, incluido cualquier ResultSet.

Por lo tanto, el bucle dentro de un SELECCIONAR y emitir ACTUALIZACIONES (o incluso SELECT anidados) tenderá a fallar. Al parecer, es un crimen, para realmente querer hacer algo con los resultados de su SELECCIÓN externa!


De todos modos, depende de la versión específica del conductor & .. pero en general la especificación JDBC 3 aparece con el mandato de este comportamiento poco útil. La actualización de los controladores también puede "descubrir" inútilmente este comportamiento.

¿Por qué utilizar el autocompromiso? Originalmente, fue útil & conveniente. Como dicen otras respuestas, JDBC requiere grandes cantidades de GUFF y gastos de envío para llamar correctamente .. JDBC no es realmente una API bien diseñado :(


En estos días, que sería mejor usar Hibernate o JdbcTemplate de primavera. . Y si está haciendo servlets/aplicaciones web, coloque su gestión de transacciones (inicio/fin) o hibernación de sesión (vincúlelo a un hilo local) en los límites de la "Solicitud de usuario"

por ejemplo, obtener enlazar su conexión/transacción al inicio de ServletRequest y devolverlo al final.

Puede usar un javax.servlet.Filter o similar y vincularlo a un local de subprocesos, hacer un ayudante estática para conseguirlo o requiere que, etc.

+0

No recomiende la conexión/transacción/sesión vinculada al patrón ANTI de solicitud web ... si desea que su transacción abarque, p.proceso de solicitud, procesamiento de carga multiplart, envío del cuerpo al cliente con conexión lenta, puede hacerlo, pero diría que es una muy mala idea en casi todos los casos. –

+0

Gracias @ PiotrMüller: ¿algún razonamiento o referencias? Probablemente esperaría que se te ocurra un caso malo del 0.001% para casi cualquier patrón, pero probablemente sea mejor distinguir "casos de esquina problemáticos aislados son posibles" de ser "casi todos los casos", y en el momento que di esta recomendación (2012), creo que fue un buen consejo. El límite de solicitud de usuario es el límite más importante e importante en una aplicación de servicio HTTP. Por eso, es un candidato sólido y obvio para diseñar. Cualquier solución alternativa probablemente sería más compleja. –

+0

en la aplicación web se aplicará la mayoría de los "casos malos" mencionados (para cualquier aplicación web típica). Al habilitar la sesión a la vista, debe asegurarse de que se aborden de inmediato muchos aspectos técnicos, p. búfer de respuesta: asegúrese de que la transacción y la conexión SQL no abarquen durante todo el tiempo de conexión del cliente extrayendo la respuesta (por qué mantener la conexión SQL por mucho tiempo si el cliente tiene un ancho de banda bajo). Esto también conduce rápidamente a problemas de diseño/rendimiento si la aplicación crecer. Para un proyecto pequeño, rápido y de pocas semanas, puede ser una solución, pero no lo recomendaría con algo grande –

2

Bueno, hay ciertas condiciones que necesita una cuidadosa mirada al tiempo que permite la “auto-entrega” a nivel mundial:

a.) La gestión de transacciones en el nivel de consulta quedará a criterio del usuario; para una instancia, si se necesita una gran cantidad de consultas para tener éxito o fallar juntas, entonces se debe ajustar en BEGIN y confirmar Transacción.

b.) Recuerde, no hay retroceso cuando se activa la "confirmación automática".

c.) También hay una sobrecarga de escribir (cometer) todas y cada una de las transacciones.

d.) Para las consultas de solo lectura no existe una necesidad explícita de "autocompromiso", pero habilitando "autocompromiso" se aplica automáticamente para todas las consultas.

Si el bloqueo de tablas es la única preocupación para habilitar el autocompromiso, entonces puede que no sea una buena idea, más bien se puede recurrir a tiempos de espera de bloqueo más bajos.

Cuestiones relacionadas