Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Delphi para la web
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 13-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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);
La transacción la estoy creando sobre la conexión a mis datos (TSQLConnection), el problema es que si el servicio es invocado más de una vez al mismo tiempo, las transacciones se mezclan porque todas utilizan la misma conexión.

¿Cual sería la manera correcta de manejar las transacciones?
Responder Con Cita
  #2  
Antiguo 13-09-2016
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
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 22:00:50.
Responder Con Cita
  #3  
Antiguo 13-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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!
Responder Con Cita
  #4  
Antiguo 14-09-2016
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Buscando en google:

http://docwiki.embarcadero.com/RADSt...rs_tutorial%29
__________________
El malabarista.
Responder Con Cita
  #5  
Antiguo 14-09-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
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)
Responder Con Cita
  #6  
Antiguo 14-09-2016
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Corrección clara!
__________________
El malabarista.
Responder Con Cita
  #7  
Antiguo 14-09-2016
Avatar de jhonny
jhonny jhonny is offline
Jhonny Suárez
 
Registrado: may 2003
Ubicación: Colombia
Posts: 7.058
Poder: 29
jhonny Va camino a la famajhonny Va camino a la fama
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/
Responder Con Cita
  #8  
Antiguo 14-09-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
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
Responder Con Cita
  #9  
Antiguo 14-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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.
Responder Con Cita
  #10  
Antiguo 14-09-2016
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
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.
Responder Con Cita
  #11  
Antiguo 14-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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.
Responder Con Cita
  #12  
Antiguo 14-09-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
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
Responder Con Cita
  #13  
Antiguo 14-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
Bien AgustinOrtu, entonces si vos sabes como resolverlo, ¿me podrías dar respuestas a mis preguntas?
Responder Con Cita
  #14  
Antiguo 14-09-2016
Avatar de jhonny
jhonny jhonny is offline
Jhonny Suárez
 
Registrado: may 2003
Ubicación: Colombia
Posts: 7.058
Poder: 29
jhonny Va camino a la famajhonny Va camino a la fama
Cita:
Empezado por andres_04_08 Ver Mensaje
Bien AgustinOrtu, entonces si vos sabes como resolverlo, ¿me podrías dar respuestas a mis preguntas?
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/
Responder Con Cita
  #15  
Antiguo 14-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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!
Responder Con Cita
  #16  
Antiguo 14-09-2016
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
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.
Responder Con Cita
  #17  
Antiguo 15-09-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
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)
Responder Con Cita
  #18  
Antiguo 15-09-2016
andres_04_08 andres_04_08 is offline
Registrado
NULL
 
Registrado: ago 2016
Posts: 9
Poder: 0
andres_04_08 Va por buen camino
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.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Manejo de transacciones StartKill MS SQL Server 7 23-09-2008 22:46:53
Manejo de transacciones en SQL server look SQL 6 21-08-2008 18:27:17
error en manejo de transacciones JODELSA Varios 1 11-07-2005 17:50:56
Manejo de Transacciones takeo Conexión con bases de datos 0 01-12-2004 06:29:53
Manejo de Transacciones senpiterno Conexión con bases de datos 1 08-10-2004 16:05:34


La franja horaria es GMT +2. Ahora son las 14:07:44.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi