FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
|||
|
|||
Manejo de transacciones B.D. en WebService
Buenas tardes.
Estoy desarrollando WebService REST ISAP en DelphiXE3 utilizando bases de datos SQL Server. En el proceso del W.S., debo realizar varios pasos en una sola transacción y lo hago de la siguiente forma: Código:
VAR lTransactionDesc: TDBXTransaction; ... // ** Inicio Transacción ** // if not wsDataModule.SQLConnectionServer.InTransaction then begin wsDataModule.SQLConnectionServer.CloseDataSets; lTransactionDesc := wsDataModule.SQLConnectionServer.BeginTransaction(TDBXIsolations.ReadCommitted); end; //Acá van todas las operaciones que debo hacer en mi transacción // ** Finalizo transacción ** // if wsDataModule.SQLConnectionServer.InTransaction then wsDataModule.SQLConnectionServer.CommitFreeAndNil(lTransactionDesc); ¿Cual sería la manera correcta de manejar las transacciones? |
#2
|
||||
|
||||
Es porque no estas siguiendo el modelo "state-less" de la web, sino el "state-full". Osea, tienes una conexión que comparte todo el programa. En cambio, debes crear una conexión POR CADA* request que se haga.
* Si hay que soportar muchas conexiones al mismo tiempo, esto se vuelve un problema. Para ello, se necesita un pool de conexiones y un manejo que reparta esas conexiones. Con ADO es sencillo, pero no se que usas. ---- Un problema endemico de la programacion y que el modelo OO "tradicional" mal empleado amplifica es el manejo de estado global. Todos saben que las variables globales son (generalmente) malas. Pues eso es lo que pasa aqui, y en todo momento donde las llamadas de un programa pueden alterar el estado interno de los componentes, en vez de que sean independientes de cada una. Un DataModule es una vble global. Tener accesos concurrentes a una vble global es una conocida receta para el desastre y bugs dificiles de anticipar.
__________________
El malabarista. Última edición por mamcx fecha: 13-09-2016 a las 21:00:50. |
#3
|
|||
|
|||
Muchas gracias por tu respuesta!, supuse que estaba sucediendo lo que indicas.
Estoy utilizando TSQLQuery conectados con TSQLConnection, ¿sabras decirme como manejar el pool de conexión con estos componentes? de lo contrario, podrás darme un ejemplo de como hacerlo con ADO. Lo que se me ocurrió también, es instanciar un TSQLConnection en cada llamada al servicio, ¿puede ser esta la forma? ¿en que evento del WebModule se debería realizar? Gracias! |
#4
|
||||
|
||||
__________________
El malabarista. |
#5
|
||||
|
||||
Un data module no es una variable global. Que el IDE te cree una variable global es otro tema. Lo mismo se podria decir de los form. Pero ese comportamiento se arregla fácilmente cambiando una opción para que no te cree nada automáticamente (no agrega las "líneas mágicas" en el dpr)
|
#6
|
||||
|
||||
Corrección clara!
__________________
El malabarista. |
#7
|
||||
|
||||
Sin embargo y aunque estoy de acuerdo con lo que plantea mamcx incluida la aclaración de Agustín, hay algo aquí que no me suena y es el hecho que Andres diga que se "mezclen" las transacciones. Pues si estás usando DataSnap para crear dicho servidor, ese no debería ser un problema ya que él crea un Hilo por cada petición que se le hace, lo cual crearía una instancia de dicha conexión para cada una de tus peticiones.
Claro, asumiendo que estás usando DataSnap... la única cosa que se me ocurre... generaría tal comportamiento, sea que el LifeCycle de la clase publicada en tu modulo Container sea de tipo Server y no Invocation o Session... lo cual parece ser el caso que requieres. Ahora bien, la solución puede que sea cambiar dicha propiedad, sin embargo debes plantear el cambio de esquema en tus WS de "state-full" a "state-less" como plantea mamcx.
__________________
Lecciones de mi Madre. Tema: modificación del comportamiento, "Pará de actuar como tu padre!" http://www.purodelphi.com/ http://www.nosolodelphi.com/ |
#8
|
||||
|
||||
No se como tendra configurado el server. Yo solo se que lo que controla esa propiedad es el tiempo de vida de las DSServerClass, osea de lo que el IDE te genera como TServerMethods1
Si no me falla la memoria el DataModule va aparte del TServerMethods Las DSServerClass basicamente reciben una referencia a una clase descendiente de TPersistent, osea una TPersistentClass, y lo que hacen es crear una instancia de dicha clase para exponer al cliente |
#9
|
|||
|
|||
Por el momento lo resolví de la siguiente forma:
En el WebModule declaro una variable en threadvar del tipo TwsDataModule. Luego en el evento BeforeDispatch instancio esta variable con mi dataModule (TwsDataModule) que tiene las conexiones. Posteriormente en el evento AfterDispatch realizo un freeAndNil de esta variable. De esta forma logro que por cada invocación a mi W.S., se cree un dataModule con las conexiones que utilizarán en esa petición, y cada conexión puede tener una transacción distinta. |
#10
|
||||
|
||||
No hombre, esa no es la forma correcta.
No intentes de hackear las cosas. USa la forma correcta de programar de acuerdo al caso, no el torcer la que usas para que se le parezca. La mejor optimizacion es a nivel de arquitectura.
__________________
El malabarista. |
#11
|
|||
|
|||
MAMCX, no estoy intentando hackear nada!!
No existe una única solución para resolver un problemas, si lo resolví de esta forma fue porque no supe como hacerlo de otra, y si estoy escribiendo en este foro es para que alguien pueda enseñarme como se debe hacer. Revise el link que me compartiste, y no entiendo como funcionaría seteando la propiedad Connection Pooling de mi SQLCOnnection, ¿cuantas conexiones se crean y en que momento? ¿Cada invocación a mi W.S. crea automáticamente una conexión? ¿Como luego creo una transacción en una de las conexiones existentes? De la forma que describí funciona según lo que esperado, si existe una mejor forma desconozco (de lo contrario no estaría escribiendo este hilo), si me la puedes explicar claramente estaré agradecido. |
#12
|
||||
|
||||
El término hack hace referencia a que estás aplicando una solución que no es la mejor; te estás disparando en el pie. Que veas que aparentemente funciona no quiere decir que este bien
|
#13
|
|||
|
|||
Bien AgustinOrtu, entonces si vos sabes como resolverlo, ¿me podrías dar respuestas a mis preguntas?
|
#14
|
||||
|
||||
Según los datos que nos has dado, en el post 7 y 8, te hemos dado una posible solución.
__________________
Lecciones de mi Madre. Tema: modificación del comportamiento, "Pará de actuar como tu padre!" http://www.purodelphi.com/ http://www.nosolodelphi.com/ |
#15
|
|||
|
|||
Hola Jhonny.
¿Será que pueden compartir algún ejemplo de código? con las respuesta del Post 7 y 8 no lo pude resolver y no lo entiendo. Las preguntas del Post 11 quedaron sin respuesta, tal vez aclarando esas dudas puedo terminar de entender sus anteriores publicaciones. Muchas gracias! |
#16
|
||||
|
||||
Lo que te estan diciendo los post es que debes tener claro como es que funciona DataSnap para asi saber que es lo que debes o no alterar.
Un servidor tipo web debe operar como una cadena Solicitud -> Respuesta, idealmente, sin que los afecten el que hayan otras llamadas concurrentes. Comúnmente la BD se convierte el repositorio del estado cambiante de la aplicación. Ahora, hace rato que no toco Delphi y menos DataSnap, asi es la razon que no te he dado nada mas concreto. Pero si tienes claro el concepto, veras que se traslada a cualquier lenguaje de programacion. Lo que pasa ademas es que es raro que tengas ese problema a menos que haya una alteracion en como esta configurado el proyecto (porque dudo que DataSnap no provea unos defaults sanos). Que tal si creas un proyecto en blanco con un ejemplo minimo de lo que quieres y revisas en que se diferencia del que tienes? ---- Aun mas concretamente: Todo el setup de objetos/llamadas deberias poder ponerlo en una LINEA CONTINUA, sin que haya probabilidades de que exista una vble/objeto/archivo no transaccional que pueda tocarse desde otra linea de ejecución paralela. Dentro del código servidor no debe haber creado ni compartido nada (incluso la vble threadvar!) porque entonces tendrás potencial contención entre las ejecuciones y posibilidades a varios tipos de errores (como dead-locks) y ademas, el desempeño sera pobre. Asi que a partir de la clase que "arranca" todo, de ESTA debe armar la linea ENTRADA -> CREA OBJETO -> CREA OBJETO .... y todo debe referenciar hacia atras (ya sea como propiedad o solo vero en términos historicos). Es claro?
__________________
El malabarista. |
#17
|
||||
|
||||
Es que el desarrollo multitier es distinto al desarrollo cliente-servidor que fomento toda la vida Delphi. Eso de poner componentes de acceso a datos en un DataModule y dejarlos alli vivitos y coleando no sirven en un ambiente web en donde no hay estado, stateless como puntualizo mamcx
Lo correcto para acceder a la base de datos es: Llega peticion -> Peticion debe acceder a BD -> Crear conexion a la BD -> Crear Query -> Ejecutar Query -> Devolver resultado -> liberar recursos usados En el modelo cliente servidor clasico, creas una sola conexion a la bd cuanto mucho, y luego los query/command depende de como lo hagas (no estas obligado aunque siempre lo mas sano es devolver un objeto nuevo) |
#18
|
|||
|
|||
Buen día!, muchas gracias por sus respuestas.
Entendia que lo correcto para acceder a la base de datos es: Llega peticion -> Peticion debe acceder a BD -> Crear conexion a la BD -> Crear Query -> Ejecutar Query -> Devolver resultado -> liberar recursos usados Es por eso que BeforeDispatch instancio mi dataModule (TwsDataModule) para que se creen las conexiones y luego lo libero en el evento AfterDispatch . Mi duda es si estaba bien crear una conexión por cada petición y en que evento se debería hacer, o si existía alguna forma de que las conexiones se creen y administren solas. |
|
|
Temas Similares | ||||
Tema | Autor | Foro | Respuestas | Último mensaje |
Manejo de transacciones | StartKill | MS SQL Server | 7 | 23-09-2008 21:46:53 |
Manejo de transacciones en SQL server | look | SQL | 6 | 21-08-2008 17:27:17 |
error en manejo de transacciones | JODELSA | Varios | 1 | 11-07-2005 16:50:56 |
Manejo de Transacciones | takeo | Conexión con bases de datos | 0 | 01-12-2004 05:29:53 |
Manejo de Transacciones | senpiterno | Conexión con bases de datos | 1 | 08-10-2004 15:05:34 |
|