Cómo mantener la información de estado de COM+ en Delphi
Liu Xiaoming (cipherliu)
El problema comienza así: necesito escribir un COM+ para conectarme a diferentes bases de datos. Algunos amigos pueden decir que se debe establecer un COM+ para cada base de datos, pero esto no se puede hacer en mi sistema. Estamos creando un sistema de asistencia educativa y los usuarios son las escuelas (incluidos profesores, estudiantes y padres de la escuela, por supuesto). Creamos una base de datos para cada escuela. Las estructuras de estas bases de datos son las mismas. Por supuesto, también disponemos de una base de datos de gestión para coordinar las relaciones entre bases de datos. Cada vez que se agrega un usuario de la escuela, activamos una nueva base de datos para que la use el cliente. En otras palabras, el número de nuestras bases de datos aumenta constantemente y solo tenemos un cliente. En el lado del cliente, solo tenemos un conjunto de COM+, en lugar de desarrollar un conjunto para cada base de datos. Entonces tengo que dejar que se conecte a diferentes bases de datos según la identidad del usuario en COM+.
Obviamente, este COM+ debería proporcionar un método para permitir que su llamador (que puede ser una aplicación cliente u otro middleware) seleccione la base de datos a la que conectarse. En la práctica, consultamos la base de datos en la biblioteca de administración según el ID del usuario. nombre de la base de datos y luego conectarse a la base de datos del usuario. Aquí, para simplificar el problema, creemos que la persona que llama ya conoce el nombre de la base de datos y solicita directamente llamar a esta base de datos.
Agregue un miembro privado DBName:cadena a la clase COM+ para guardar el nombre de la base de datos que se conectará. También deberíamos proporcionar un método de este tipo para establecer su valor. Inicialmente lo escribí así.
Procedimiento TmtsDBConn.ConnectTo(sDBName:string);
comenzar
intentar
NombreBD:=sNombreBD;
Conjunto completo;
Excepto
Establecer aborto;
fin;
fin;
Luego, coloque en ellos los controles ADOConnection, ADODataSet y DataSetProvider, denominados adoc, adods y dsp respectivamente. Establezca la relación de conexión entre ellos, establezca la cadena de conexión de adoc a la base de datos de conexión "DB1", que es el valor predeterminado, y luego en el evento BeforeConnect de adoc:
adoc.ConnectionString:=ConnectStringA+'Initial Catalog='+DBName+';'+ConnectStringC;
ConnectStringA y ConnectStringC aquí son constantes de cadena preestablecidas para construir dinámicamente la cadena de conexión, de la siguiente manera:
constante
ConnectStringA='Provider=SQLOLEDB.1;PassWord=2003;Persist Security Info=True;User ID=sa;';
ConnectStringB='Catálogo inicial=DB1;';
ConnectStringC='Fuente de datos=servidor3;Usar procedimiento para preparar=1;Traducción automática=True;Tamaño del paquete=4096;ID de estación de trabajo=LXM;Usar cifrado para datos=False;Etiquetar con intercalación de columnas cuando sea posible=False';
Compile e instale este COM+. Luego escriba un programa cliente para llamarlo.
Coloque un DCOMConnection en el programa cliente, conéctese a él y escriba el servidor COM+, coloque un ClientDataSet, establezca sus propiedades RemoteServer y Provider y luego escriba declaraciones SQL en su CommandText. Luego, coloque el control DataSource y el control DBGrid para establecer la conexión entre ellos. Finalmente ponga un botón y en su evento Click:
Dcomconexión1.Conectado:=verdadero;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=verdadero;
Dcomconnection1.Connected:=falso;
Este código sirve para probar si se puede acceder a los datos de la base de datos DB2. Pero el resultado es que al hacer clic en el botón, siempre se informa un error. ¿Cuál es el motivo?
Regrese al proyecto COM+, depurelo, establezca puntos de interrupción en ConnectTo y adocBeforeConnect, y descubra que el programa se ejecuta en
NombreBD:=sNombreBD;
Al ejecutar, el valor de DBName de hecho se ha establecido en "DB2", pero al ejecutar
adoc.ConnectionString:=ConnectStringA+'Initial Catalog='+DBName+';'+ConnectStringC;
, DBName volvió a ser una cadena vacía, por lo que se produjo un error.
¿Por qué se pierde el valor de DBName? Resulta que el método SetComplete se llama en ConnectTo. El método SetComplete cree que COM+ ha completado la tarea y liberará el objeto COM+. Por lo tanto, al conectarse a la base de datos, se crea un nuevo COM+ y, por supuesto, su DBName. nulo. .
Encontré el motivo, cambié SetComplete a EnableCommit; compilé y luego ejecuté el cliente. Finalmente, se ejecutó correctamente y recuperó los datos en la base de datos DB2.
Sin embargo, en el programa cliente, puse otro ClientDataSet. Después de abrir ClientDataSet1, abrí ClientDataSet2 y quise continuar accediendo a los datos en DB2, pero se informó otro error. Cambie el programa a
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=verdadero;
ClientDataset1.Active:=falso;
ClientDataset1.Active:=verdadero;
Incluso si solo se utiliza un ClientDataSet, se producirá un error cuando se vuelva a abrir después de cerrarlo.
Pero si el cliente escribe
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=verdadero;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset2.Active:=verdadero;
Se puede ejecutar con éxito. Pero esto parece muy feo. ¿Por qué COM+ se libera después de conectarse a la base de datos?
Resulta que TmtsDataModule tiene un atributo de Autocompletar y el valor predeterminado es verdadero, por lo que después de conectarse a la base de datos, aún se liberará.
Después de configurar Autocompletar en falso, aún se producía un error. El seguimiento en el evento OnActivate de COM+ encontró que cuando se activaba, el atributo Autocompletar se establecía automáticamente en verdadero, por lo que después de conectarse a la base de datos por primera vez, aún se liberaba. sí mismo.
En el evento OnOnActivate de COM+, escriba:
Autocompletar:=falso;
No hay problema si el cliente se conecta una vez y accede a la base de datos varias veces.
Pero en este caso, COM+ no se lanzará automáticamente. Debe agregar un método a COM+, SetComplete en este método, y luego llamar a este método para liberar COM+ una vez que el cliente haya terminado con COM+.
Después de la exploración anterior, llegamos a la siguiente conclusión: en COM+, si desea mantener la información de estado, debe trabajar un poco, porque COM+ no tiene estado de forma predeterminada. Cada vez que el cliente lo llama, juzgará si. debería liberarse solo, si no queremos que se libere, tenemos que intervenir manualmente y finalmente tenemos que liberarlo manualmente.