| |  |  | Miembros: Mensajes: Temas: Online: Ultimo Miembro: | | |  | | |
 | 
24-09-2006, 20:02:39
|  | Gran Participación en el Foro | | Registrado: jul 2005 Ubicación: Libertad / Merlo prov Buenos Aires Posts: 206
| | Transacciones - Multiusuario Quisiera saber si hay alguna forma de poder controlar dos transacciones en access que se intentan realizar a la vez. Es decir, hay dos usuarios que intentan grabar un campo de la misma tabla al mismo tiempo. Como podría hacer que se incremente el campo clave para que no de error. Pues yo intenté de varias formas, pero siempre graba una y la otra da error pues queda con el mismo número de código que la anterior.
Esto es lo último que probé: Código: Case ALTA
DoEvents
cnnBase.BeginTrans
strSql = "SELECT (MAX(busqCod)+1) FROM tblBusquedas"
consultasql cnnBase, strSql, recDatos
recDatos.Requery
mCodigo = recDatos.Fields(0)
recDatos.Close
Set recDatos = Nothing
strSql = "INSERT INTO tblBusquedas(busqCod,busqCliente,busqReferencia," _
& "busqPuesto,busqEmail,busqResponsable,busqAviso,busqObs," _
& "busqAltaFecha,busqAltaHora,busqAltaUsr,busqEstadoNom)" _
& "VALUES(" & mCodigo & "," & consultaCodCliente(cboCliente.Text) _
& ",'" & txtFields(2) & "','" & txtFields(3) _
& "','" & txtFields(4) & "'," & consultaCodPersonal(cboResponsable.Text) _
& ",'" & txtFields(6).Text & "','" & txtFields(7).Text _
& "',#" & Format(Date, "mm-dd-yyyy") & "#,#" & Format(Now, "hh:mm:ss") & "#," _
& glngUserCod & "," & consultacodEstados(cboEstado.Text) & ")"
cnnBase.Execute strSql
cnnBase.CommitTrans Es posible lo que intento hacer, o es algo que siempre va a dar error. Ya que probé de muchas formas y no hay caso, siempre se desencadena el error de que el campo clave ya existe.
Este es mi único inconveniente, ya que si hay más de 5 segundos entre envío de transacciones no hay problema, peros i el tiempo es menor, se desencadena el error.
Desde ya muchas gracias por cualquier aporte. | 
24-09-2006, 20:51:48
| | Moderador | | Registrado: dic 2002 Ubicación: Madrid Posts: 4.271
| | Una opción no siempre deseada son los campos autonuméricos. En tu caso particular, tendrás que realizar la captura del error y reintentar la inserción del dato consultando nuevamente el mayor código existente y añadir '1'.
Parece primitivo pero me parece que no existe alternativa posible. Las colisiones de acceso se deben controlar por el correcto tratamiento de errores detectados. | 
24-09-2006, 21:12:43
|  | Gran Participación en el Foro | | Registrado: jul 2005 Ubicación: Libertad / Merlo prov Buenos Aires Posts: 206
| | Entonces no hay otra alternativa que capturar el error y volver a ejecutar la transacción.
Lo de los campo autonumérico puede ser una solución, lo malo es que no todas las tablas tienen un campo de código numérico, sino que hay algunas con campo tipo texto.
Bueno, voy a ver como lo soluciono y después les cuento.
Lo más cómodo sería mostrarle un mensaje al usuario e indicarle que vuelva a presionar grabar.
Muchas gracias por sus consejos. | 
24-09-2006, 22:16:19
|  | Administrator | | Registrado: dic 2002 Ubicación: BURGOS - ESPAÑA Posts: 5.431
| | Yo uso una rutina que espero te sirva. No podría explicarte el por qué de esas líneas que dicen: " For n = 0 To 20000: Next". Recuerdo que sin esas líneas tuve algún problema; no me servía un simple DoEvents... Así que puse ese "delay", y me va PERFECTO. Como ves, hago otras dos cuestiones para asegurarme de que en ese lapsus de tiempo no se haya realizado un bloqueo inesperado...
Bueno, teóricamente miro a ver si el campo "Bloqueo" (Numérico tipo Integer de una tabla específica para realizar este control) vale 0. En ese caso quiere decir que nadie está haciendo transación. Si es así, grabo en ese campo mi número de usuario, con lo que ya nadie puede pasar de ese punto, hasta que yo termine mi rutina. O hasta que termine cualquier otro usuario que lo haya bloqueado previamente. Obviamente NumUsua es mi número de usuario... Código: Controlar:
' Bloqueo Update de Transacción
Do While rsNume!Bloqueo > 0
' Por si está bloqueado por otro usuario
Loop
For n = 0 To 20000: Next
If rsNume!Bloqueo > 0 Then GoTo Controlar
' Lo bloqueo yo hasta que termine de actualizar toda la transacción
rsNume!Bloqueo = NumUsua
rsNume.Update
DoEvents
For n = 0 To 20000: Next
If rsNume!Bloqueo <> NumUsua Then GoTo Controlar
' Ejecuto todo el código de la transacción
' Una vez finalizada, LIBERO el bloqueo:
rsNume!Bloqueo = 0
rsNume.Update
DoEvents | 
24-09-2006, 22:49:05
|  | Gran Participación en el Foro | | Registrado: jul 2005 Ubicación: Libertad / Merlo prov Buenos Aires Posts: 206
| | Muchas gracias Sr Movilla por su consejo. Todo sirve como ayuda, y más de alguien que tiene experiencia.
Igualmente yo me incliné por los consejos del Sr Acalanto y capturé el código de error, quedango algo así: Código: Select Case mintEdicion
Case ALTA
DoEvents
TransaccionGrabar:
strSql = "SELECT (MAX(busqCod)+1) FROM tblBusquedas" '// Se busca el máximo y se le suma 1
consultasql cnnBase, strSql, recDatos
mCodigo = recDatos.Fields(0)
recDatos.Close
Set recDatos = Nothing
strSql = "INSERT INTO tblBusquedas(busqCod,busqCliente,busqReferencia," _
& "busqPuesto,busqEmail,busqResponsable,busqAviso,busqObs," _
& "busqAltaFecha,busqAltaHora,busqAltaUsr,busqEstadoNom)" _
& "VALUES(" & mCodigo & "," & codCliente _
& ",'" & txtFields(2) & "','" & txtFields(3) _
& "','" & txtFields(4) & "'," & codPersonal _
& ",'" & txtFields(6).Text & "','" & txtFields(7).Text _
& "',#" & Format(Date, "mm-dd-yyyy") & "#,#" & Format(Now, "hh:mm:ss") & "#," _
& glngUserCod & "," & codEstado & ")"
cnnBase.BeginTrans
blnTransaccion = True
cnnBase.Execute strSql
cnnBase.CommitTrans
blnTransaccion = False
.....................
.....................
error:
'// Si hubo error
If blnTransaccion Then
cnnBase.RollbackTrans
End If
If Err.Number = -2147467259 Then '//Si ya existe la clave
GoTo TransaccionGrabar
End If Esta rutina no tiene en cuenta otros errores más que el de campo clave repetido.
Quizas con más pruebas lo tenga que depurar mejor, pero por ahora funciona. Y que más puede pedir uno, la no perfección se logra, siempre uno se acerca lo más que puede.
Desde ya, otra vez, muchas gracias por su ayuda. | 
25-09-2006, 01:08:30
|  | Administrator | | Registrado: dic 2002 Ubicación: BURGOS - ESPAÑA Posts: 5.431
| | A buen seguro que ese método es mejor que el mío, por el origen del código... Voy a seguir con mi rutina en las aplicaciones que tengo funcionando, pero ya me lo tendré en cuenta para el futuro. | 
25-09-2006, 01:22:23
|  | Gran Participación en el Foro | | Registrado: jul 2005 Ubicación: Libertad / Merlo prov Buenos Aires Posts: 206
| | No creo que sea mejor que el suyo, ya que este código tan solo lo he probrado con access. Habría que ver si con otro tipo de base de datos arroja el mismo error, si fuera así seria un código general. Por ahora es solo un código para bases de access.
Mientras que su código es general, y no interesa el tipo de base, siempre funcionará.
Yo no lo he implementado porque pienso que usar transacciones directamente con execute es mucho más rápido que con el método update.
Cuando tenga más experiencia le cuento cual es más rápido. Por ahora sigo con este método, sino nunca voy a terminar el programa.
Y como dicen los que saben, es mejor teminar un programa y luego mejorarlo, que nunca terminarlo. | 
25-09-2006, 10:57:20
|  | Administrator | | Registrado: dic 2002 Ubicación: BURGOS - ESPAÑA Posts: 5.431
| | Yo lo único que puedo asegurarte es que el sistema de "pido-paso" que me inventé yo hace un par de años (digo "me inventé" porque no sé que nadie lo haya utilizado hasta ahora, aunque reconozco que en esta vida nada se inventa, sino que todo existe ya de siempre y lo único que hacemos es encontrárnoslo...) funciona a la perfección, y sirve también para generar números incrementales, sin utilizar campos autonuméricos, que a mí personalmente me producen gastroenteritis... Cierro el paso, busco el máximo del número que debo controlar, lo incremento, grabo los datos y abro el paso... Así nunca nadie puede repetir un número de factura, por ejemplo, o duplicar un código de cliente o producto... | 
25-09-2006, 18:31:37
|  | Gran Participación en el Foro | | Registrado: jul 2005 Ubicación: Libertad / Merlo prov Buenos Aires Posts: 206
| | Que más puede pedir uno. Tiene un código que ahorra dolores de cabeza y además no crea duplicados.
Con respecto a lo de los campos autoincremental estoy totalmente deacuerdo de que son muy conflictivos, y cualquier programador de base de datos debería evitar utilizarlos como clave principal. Como experiencia personal puedo mensionar lo que pasa al hacer un rollBacktrans, estos campos se incrementan igual, con lo cual luego de hacer varias grabaciones fallidas tenía solamente dos registros, uno con el campo autoincremental en 1 y el otro en 8. Pero bueno, cada uno hara uso de lo más le conviene. Yo personalmente, no lo recomiendo como clave principal, prefiero usar campos numéricos e autoincrementarlos por código. | 
12-10-2006, 19:48:45
| | Un Nuevo Amigo | | Registrado: jun 2005 Posts: 15
| | disculpen, con respecto a lo de incremental.... pueden acceder a la escritura de una buena practica para estos casos, se encunetra en www.sqlgurus.org
__________________
Lic. Fernando Princich
| | Herramientas | | | | Desplegado | Mode Lineal |
Normas de Publicación
| no Puedes crear nuevos temas no Puedes responder a temas no Puedes adjuntar archivos no Puedes editar tus mensajes Código [IMG] está habilitado Código HTML está deshabilitado | | | La franja horaria es GMT. Ahora son las 02:05:14.
Powered by vBulletin® Version 3.6.8 Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO 3.1.0
A vBSkinworks Design
|  |