Visual Basic Foro
Programación => Bases de Datos => Mensaje iniciado por: Jeronimo en Octubre 17, 2013, 08:27:01 pm
-
En mi proyecto hay una aplicación secundaria que correrá en el servidor de la base de datos, cuya única tarea es hacer actualizaciones masivas de datos una vez al día. La configuraría para ejecutarse diariamente a partir de las 4 am, para tener menos oportunidad de que hubiera alguien utilizando la aplicación principal en una de las computadoras donde se empleará. En ese momento la base de datos no debiera admitir ninguna petición de la aplicación principal, porque podría afectar el resultado final.
Entonces, aquí va mi duda: ¿es suficiente con que comience una transacción (trabajo con VB6 y MySQL) desde la aplicación del servidor, realice todos los procesos y luego culmine la transacción (CommitTrans), o debo bloquear la base de datos de alguna manera? Si fuese correcta la segunda opción, ¿cuál es la manera más conveniente de hacerlo? Y si fuese la primera la adecuada, ¿la base de datos rechazaría o postergaría toda otra petición (que viniera de la aplicación principal, desde otra computadora) hasta que se finalice la transacción de la aplicación que corre en el servidor (ya sea con CommitTrans o con RollBackTrans)?
¡Muchas gracias!
Jerónimo
-
Tu inquietud me plantea esta pregunta ¿Que MySQL siendo un motor potente y grande no puede permitir los backups en caliente?
Te comento un poco, Si usas Access lo que comentas es muy valido, Access es susceptible a daños cuando haces un backup por el tema de la exclusividad, pero eso es Access, una BD que algunos entendidos les molesta llamarlo Base de Datos, me parece que todos los motores C/S no tienen esa restriccion.
En mi cuasi olvidado motor FirebirdSQL que es un motor potente que a nivel técnico es casi al nivel de las grandes (MySQL, SQL Server, etc) se puede hacer un backup en caliente. Tengo varios ejemplos pero el mas antiguo es uno que desde hace casi 3 años todos los dias a las 10am y a las 6pm (la tienda abre a las 9am y cierra a las 8pm) el sistema hace backup como dije TODOS LOS DIAS (bueno domingos no) sin necesidad de bloquear a nadie y muchos hasta ya se olvidaron que el backupeo esta corriendo en segundo plano (obvio solo en el servidor) y hasta la fecha no tenemos ningún problema, tanto que hasta ya me molesta jaja. Solo hice hace unos pocos meses un restore y un redefinicion de los indices por un tema de simple mantenimiento debido a nuevos querys que habia creado.
Te comento esto para decir: Si FirebirdSQL puede ¿porque MySQL no?, yo creo que si se puede, debe haber en MySQL alguna funcionalidad externa o interna que te permita hacer eso, en el caso de Firebird por ejemplo es externa usando un utilitario llamado GBack que dicho vulgar y simplemente hace una fotografia de la BD y la empieza a reconstruir (+/-).
Para estos motores no es necesario interrumpir la operatividad del sistema, estuve incluso en época de campaña navideña (alto trafico para la BD) entre 5pm y 7pm y podía ver que habían casi 10 usuarios atacando concurrentemente a la BD y todo ferpecto.
Ya algún compañero conocedor de MySQL te podrá dar la fija de que hacer en este caso con los backups de MySQL.
-
En realidad no se trata de hacer backups. Lo que hace la aplicación del lado del servidor es actualizar algunos campos de algunos registros de algunas tablas. Por supuesto, calculo que todo el proceso se correrá en 30 segundos y no creo que justo a las 4 am (o cuando se encienda el equipo) nadie vaya a hacer nada, pero quiero evitar que justo en el medio la aplicación principal acceda a la base para modificar algo, porque no sé cómo resultaría si eso sucediera.
A raíz de esta duda leí el hilo que iniciaste en este mismo foro (http://leandroascierto.com/foro/index.php?topic=473.msg2368#msg2368) y no me termina de quedar claro. No sé si con solo hacer "bd.BeginTrans" se posterga cualquier otra petición a la base de datos (incluso, desde otras computadoras) hasta que se haga "bd.CommitTrans", de manera que nada afecte ninguna tabla hasta que se terminen de hacer todas las operaciones. Porque lo que quiero es eso: que nada altere ningún campo de ningún registro de ninguna tabla mientras la aplicación del lado del servidor esté haciendo esta tarea. Ahora bien, una vez que termina, que se pueda seguir accediendo a la bd normalmente.
¡Muchas gracias!
Jerónimo
-
Sorry doc, tienes razon, eso me pasa por hacer las cosas apurado, ya acabo de verificar que pusiste "actualizaciones masivas", y no tiene nada que ver con backup sorry.
Ok, entonces quieres hacer un proceso en "bath", bien en ese caso no basta con el tema del begin/commit porque esto solo es para la transacción de las tablas que afecta no de toda la BD.
Para no marear con Firebird debe haber algún método en MySQL para que cuando lances ese proceso que entiendo sera otro aplicativo, puedas abrir la BD en modo exclusivo, o sea, ese aplicativo verifique que no halla nadie conectado, una vez que lo verifica se conecta a la BD de forma exclusiva y en ese caso ninguna otra conexión se podra realizar y eso lo gestiona la BD y luego liberas esta cuando tu procesos por lotes termine.
-
Mira doc, aqui creo que esta tu tema
http://dev.mysql.com/doc/refman/5.0/es/lock-tables.html
-
Para no marear con Firebird debe haber algún método en MySQL para que cuando lances ese proceso que entiendo sera otro aplicativo, puedas abrir la BD en modo exclusivo, o sea, ese aplicativo verifique que no halla nadie conectado, una vez que lo verifica se conecta a la BD de forma exclusiva y en ese caso ninguna otra conexión se podra realizar y eso lo gestiona la BD y luego liberas esta cuando tu procesos por lotes termine.
Es exactamente eso lo que nececito.
Mira doc, aqui creo que esta tu tema
http://dev.mysql.com/doc/refman/5.0/es/lock-tables.html
Eso lo había leído, pero habla de bloquear tablas y yo pensé que se podía bloquear toda la bd (obviamente, sin tener que especificar cada tabla). Si no encuentro la manera de bloquear toda la bd, entonces iré con esta opción y bloquearé de un saque todas las tablas que se vean afectadas por los procesos que debe correr el aplicativo.
¡Muchas gracias!
-
La otra alternativa menos ortodoxa si es que algun camarada no alcanza otra alternativa mejor que el Lock Table, es que lo hagas por aplicativo, o sea programando.
Te suelto una idea, ten una tabla que llames por ejemplo BLOQUEO con un campo y un solo registro con valor cero. Bueno, cuando corres el programa Bath cambias el estado de 0 a 1. Tu aplicativo normal deberá preguntar (usando una función para que sea facil, algo asi como If BdBloqueada Then... y fncBdBloqueada sera una función que solo devuelva true o false) por dicho valor, si lo encuentra en 1 da un mensaje a usuario y se cierra el programa (porque el bath estará trabajando) y si intenta volver a conectarse de entrada no mas lo botas.
Cuando termine el programa de bath vuelves el estado a cero.
El inconveniente que habría es que si por alguna razón el programa bath se queda a la mitad, o si se va la luz o lo que fuera, la BD quedara "bloqueada", entonces deberá haber alguien con los permisos adecuados para que mediante una interfaz cambie el valor de 1 a 0.
El otro punto es que representa un poquito de chamba, deberás llamar a esa función (fncBdBloqueada) antes de entrar a un BeginTrans, o sea, antes de grabar nada... al final se trata de un simple copy/paste por todos los módulos transaccionales. Pon en balanza cual te da mas chamba y cual pueda ser sostenible, si meter mano a bloquear todas las tablas con el lock o meter mano a todos los módulos con la función... o esperar que algun colega venga con el procedimiento MySQL con el cual bloqueas la BD completa de forma exclusiva.
Suerte
-
Una "negrada" ... cambia el nombre de la base de datos durante la actualizacion masiva x'D
Los programas que intenten conectarse simplemente no encontrarán la base de datos....
-
asu mae, si que es una negrada jajaja
(http://i.ytimg.com/vi/mlIk8zvupXA/0.jpg)
Tanta vaina mejor en tu soft de bath programa el cierre o borra el puerto del MySQL y luego que termina lo vuelves abrir o crear.
-
Una "negrada" ... cambia el nombre de la base de datos durante la actualizacion masiva x'D
Eso mismo se me había ocurrido, pero, justamente por lo que ponés al principio, quise buscar una solución más "elegante". Pero hasta ahora me parece la más concreta y fácil de implementar.
Tanta vaina mejor en tu soft de bath programa el cierre o borra el puerto del MySQL y luego que termina lo vuelves abrir o crear.
En eso no había pensado y también me gustó. Incluso, creo que es mejor que cambiar el nombre a la bd.
Voy a probar primero con esta última opción, a ver qué pasa.
¡Muchas gracias, muchachos!
Jerónimo
-
Y por que en vez de bloquear la base de datos, en mysql no te creas un usuario para las terminales y otro para el servidor y bloqueas el usuario para las terminales????? ???
y cuando acabes de actualizar masivamente lo desbloqueas y ya stubo.
y con respecto al backup en clientes
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=59638&lngWId=1
cao
-
Mirate el Administración de usuarios de este, esta bien explicado.
http://www.xtec.cat/~acastan/textos/Administracion%20de%20MySQL.html
-
Y por que en vez de bloquear la base de datos, en mysql no te creas un usuario para las terminales y otro para el servidor y bloqueas el usuario para las terminales????? ???
y cuando acabes de actualizar masivamente lo desbloqueas y ya stubo.
y con respecto al backup en clientes
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=59638&lngWId=1
cao
Esa idea es buena siempre y cuando se controlen usuarios por BD y muchas veces pasa que se crean y controlan usuarios por aplicativo. No se como es en MySQL pero sino es muy complicado implementar eso entonces seria buena alternativa.
-
Esa idea es buena siempre y cuando se controlen usuarios por BD y muchas veces pasa que se crean y controlan usuarios por aplicativo. No se como es en MySQL pero sino es muy complicado implementar eso entonces seria buena alternativa.
Toda aplicacion se conecta mediante un usuario, de ahí que controle sus propios usuarios es otra cosa. Se puede aplicar perfectamente.
-
Me parece que voy a hacer una conjunción de varias de las cosas que me están sugiriendo.
Hasta ahora lo que más me conviene (porque en teoría daría resultado y porque es lo único que sé cómo hacer) es lo siguiente:
Creo un usuario para la aplicación que corre en el servidor y otro para las aplicaciones que corren en las pc.
Cuando la aplicación del servidor necesita realizar sus tareas, cambia la clave del usuario de las terminales. Además, busca si el usuario de las terminales está conectado. En caso afirmativo, espera que se desconecte. Luego realiza su trabajo y, finalmente, restablece la clave del usuario de las terminales.
¿Cómo la ven?
-
Esa idea es buena siempre y cuando se controlen usuarios por BD y muchas veces pasa que se crean y controlan usuarios por aplicativo. No se como es en MySQL pero sino es muy complicado implementar eso entonces seria buena alternativa.
Toda aplicacion se conecta mediante un usuario, de ahí que controle sus propios usuarios es otra cosa. Se puede aplicar perfectamente.
Es correcto, pero he visto programa que muchas veces ese usuario con el que se conecta viene siendo el unico usuario para todas las transacciones de todos los terminales, igual es una forma menos negrera :-)
-
En realidad yo lo tengo pensado así, es decir, un usuario para la aplicación que corre en el servidor y otro para la aplicación de las terminales (en todas las terminales el mismo usuario). Siempre lo probé con dos o tres equipos y no tuve problemas. ¿Está mal hacerlo así?
-
En realidad yo lo tengo pensado así, es decir, un usuario para la aplicación que corre en el servidor y otro para la aplicación de las terminales (en todas las terminales el mismo usuario). Siempre lo probé con dos o tres equipos y no tuve problemas. ¿Está mal hacerlo así?
No, al contrario me parece que es una de las mejores formas.
-
¡Excelente!
¡Muchas gracias!
Jerónimo
-
Esta bien crearte los dos usuarios. Uno para el servidor y otro para las terminales.
De hecho, debe de ser así siempre!!!!!!!
en vez de cambiarle la contraseña (que ignoro que algoritmo vas a utilizar) por que simplemente no le quitas los permisos al usuario de las terminales y ya. Es una linea de código.
PD. Las terminales de un soft deben de utilizar un usuario que tenga permisos de lectura y escritura. Pero no deben de usuar el usuario de administrador. Es mala costumbre utilizar el mismo usuario.
-
Le cambio la contraseña porque es lo que más fácil encontré para hacer. Se me hace que quitar los permisos es más engorroso.
Lo hago de la siguiente manera:
BD.Execute "UPDATE mysql.user SET Password=PASSWORD('claveparainhabilitar') WHERE User='nombreusuario'"
El usuario de las terminales tiene solo permisos para SELECT, INSERT, DELETE, UPDATE y EXECUTE.
El problema de cambiar la clave es que solo impide conexiones nuevas, pero si un usuario ya está conectado no puedo impedir que siga trabajando. A lo mejor cambiando los permisos, como decís, deje de admitir tanto conexiones nuevas como consultas de conexiones existentes. ¿Es así? En ese caso, ¿me podrás pasar la línea para cambiar los permisos al usuario, por favor?
¡Muchas gracias!
Jerónimo
-
No viste ningún enlace que te di vdd :'(
Ok aquí esta una síntesis de los que te interesa
REVOKE ALL ON *.* FROM pepito@localhost;
ADMINISTRACIÓN DE USUARIOS
* Nombre de usuario:
Cuando creamos un nuevo usuario en MySQL, éste queda identificado por su
nombre de usuario más el nombre o IP del ordenador desde el cual hemos dicho
que accederá (podemos utilizar el carácter comodín '%' para representar
varios ordenadores). La sintaxis es:
usuario@ordenador
Ejemplos de usuarios:
pepito
pepito@'%'
pepito@localhost
pepito@'192.168.0.%'
pepito@'%.midominio.org'
Por ejemplo, el usuario 'pepito@localhost' se considera diferente del usuario
'pepito@192.168.0.%', aunque tengan el mismo nombre 'pepito', y por lo tanto
pueden tener permisos diferentes.
* Ver los usuarios:
SELECT User,Host,Password FROM mysql.user;
* Crear un usuario:
CREATE USER usuario [IDENTIFIED BY 'contraseña'] [, usuario [IDENTIFIED BY 'contraseña']] ...
Ejemplos:
CREATE USER Pepito IDENTIFIED BY 'Griyo';
CREATE USER Anonimo@localhost;
CREATE USER Alumno@'192.168.0.%' IDENTIFIED BY 'Alumno';
* Borrar un usuario:
DROP USER usuario [, usuario] ...
Ejemplos:
DROP USER Anonimo;
* Cambiar el nombre de un usuario:
RENAME USER viejo_usuario TO nuevo_usuario [, viejo_usuario TO nuevo_usuario] ...
Ejemplos:
RENAME USER Pepito TO Pepito@127.0.0.1;
* Cambiar la contraseña de un usuario:
SET PASSWORD FOR usuario = PASSWORD('contraseña')
Ejemplos:
SET PASSWORD FOR Pepito = PASSWORD('Grillo')
* Ver los privilegios de un usuario:
SHOW GRANTS FOR usuario
Ejemplos:
SHOW GRANTS FOR root;
SHOW GRANTS FOR Pepito;
* Otorga privilegios a un usuario:
GRANT privilegios ON base_datos.tabla(columnas) TO usuario;
Sintaxis ampliada:
GRANT privilegios [(columnas)] [, privilegios [(columnas)]] ...
ON [objecto] {tabla | * | *.* | basedatos.*}
TO usuario [IDENTIFIED BY [PASSWORD] 'contraseña'] [, usuario [IDENTIFIED BY [PASSWORD] 'contraseña']] ...
[REQUIRE NONE | [{SSL| X509}] [CIPHER 'cipher' [AND]] [ISSUER 'issuer' [AND]] [SUBJECT 'subject']]
[WITH opcion [opcion] ...]
privilegios = ALL, ALTER, CREATE, CREATE USER, CREATE VIEW, DELETE, DROP, EXECUTE, INDEX, INSERT,
LOCK TABLES, RELOAD, SELECT, SUPER, UPDATE, GRANT OPTION, ...
objecto = TABLE | FUNCTION | PROCEDURE
opcion = GRANT OPTION
| MAX_QUERIES_PER_HOUR count
| MAX_UPDATES_PER_HOUR count
| MAX_CONNECTIONS_PER_HOUR count
| MAX_USER_CONNECTIONS count
Ejemplos:
GRANT UPDATE, INSERT, SELECT ON world.City TO pepito@localhost;
GRANT UPDATE, INSERT, SELECT ON world.City TO fulanito@localhost IDENTIFIED BY 'nuevapasswd', tu@equipo.remoto.com;
GRANT UPDATE, INSERT, SELECT ON world.Country TO pepito@'%.empresa.com', fulanito@'%', menganito;
GRANT UPDATE, INSERT, SELECT ON world.Country TO pepito@192.168.10.111, fulanito@'192.168.10.%', menganito;
GRANT UPDATE(Population), SELECT(Name, Population) ON world.Country TO pepito@localhost;
GRANT SELECT ON world.* TO pepito@'%' REQUIRE ssl;
GRANT SELECT ON world.* TO pepito@'%' WITH MAX_CONECTIONS_PER_HOUR 3 MAX_QUERIES_PER_HOUR 300 MAX_UPDATES_PER_HOUR 30;
GRANT ALL ON *.* TO operador@localhost
GRANT ALL ON *.* TO operador@localhost WITH GRANT OPTION;
* Elimina privilegios de un usuario:
REVOKE privilegios ON base_datos.tabla(columnas) FROM usuario;
Sintaxis ampliada:
REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ...
ON [object_type] {tbl_name | * | *.* | db_name.*} FROM user [, user] ...
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...
Ejemplos:
REVOKE ALL ON *.* FROM pepito@localhost;
* Todos los privilegios se guardan en las tablas 'user', 'db', 'tables-priv',
'columns_priv' y 'host' de la base de datos 'mysql'. Se pueden realizar las
modificaciones directamente sobre estas tablas, para obtener los mismos
resultados que con GRANT, REVOKE, DROP o SET PASSWORD:
USE mysql;
SHOW TABLES;
DESCRIBE user;
DESCRIBE db;
DESCRIBE tables_priv;
SELECT User, Host, Select_priv FROM user WHERE User = 'pepito';
UPDATE user SET Password = PASSWORD('nuevapasswd') WHERE User = 'pepito' AND Host = 'localhost';
FLUSH PRIVILEGES;
DELETE FROM user WHERE User = 'pepito' AND Host = 'localhost';
FLUSH PRIVILEGES;
DELETE FROM user WHERE Password = '';
FLUSH PRIVILEGES;
* Podemos iniciar el servidor pidiéndole que no tenga en cuenta los privilegios
otorgados a los usuarios. Por ejemplo, si hemos olvidado la contraseña del
administrador de la base de datos y necesitamos poner una nueva:
mysqld --skip-grant-tables --skip-networking
mysql -e "UPDATE mysql.user SET Password = PASSWORD('nuevo') WHERE User = 'root'"
* De nada sirve controlar los privilegios de los usuarios dentro del servidor
de bases de datos si fuera del servidor, en el entorno del sistema operativo,
estos usuarios tienen libre acceso al sistema de ficheros. Para evitarlo
debemos vigilar los permisos de acceso de los siguientes archivos:
- Las bases de datos y sus tablas, para que usuarios no autorizados no puedan
acceder a ellas directamente.
- Ficheros de logs y de estado, para que usuarios no autorizados no puedan
acceder a ellas directamente.
- Ficheros de configuracion, para que usuarios no autorizados no puedan
reemplazarlos o modificarlos.
- Programas y scripts que manejan y acceden a bases de datos, para que
los usuarios no puedan reemplazarlos o modificarlos.
* Una capa adicional de seguridad nos la da encriptar los datos que escribimos
y leemos de la base de datos, mediante las funciones ENCODE(), DECODE(),
DES_ENCRYPT(), DES_DECRYPT(), AES_ENCRYPT(), AES_DECRYPT(), y PASSWORD();
* Lecturas para profundizar:
- http://dev.mysql.com/doc/refman/5.0/es/user-account-management.html
- http://dev.mysql.com/doc/refman/5.0/es/account-management-sql.html
- http://dev.mysql.com/doc/refman/5.0/es/privilege-system.html
- http://dev.mysql.com/doc/refman/5.0/es/encryption-functions.html
-
Sí, los había leído, pero se ve que no muy bien porque pensé que tenía que especificar todas las tablas de la bd en el comando REVOKE. Luego advertí que podía usar el asterisco y funciona perfectamente.
Pero de aquí me surge otra duda: ¿se puede hacer algo para que el cambio de privilegios afecte a un usuario que ya esté conectado, es decir, que no le permita seguir haciendo consultas? Cuando revoco privilegios para un usuario los cambios tienen efecto para conexiones nuevas de ese usuario, pero si el usuario ya está conectado sigue pudiendo hacer consultas. ¿Hay manera de bloquear a ese usuario que está conectado?
Cambio los privilegios así:
REVOKE ALL ON mibd.* FROM usuario@'%'Esto funciona bien para la siguiente vez que el usuario se conecta. Pero si el usuario ya está conectado puede seguir operando sin ninguna restricción. Y según el sitio de MySQL: Los cambios en los privilegios de tabla y columna toman efecto en la siguiente petición del cliente.
Si usted modifica las tablas grant utilizando GRANT, REVOKE, o SET PASSWORD,el servidor se da cuenta de estos cambios y recarga las tablas grant en la memoria inmediatamente.
¿Me está faltando algo?
Muchas gracias.
Jerónimo
-
si, FLUSH PRIVILEGES, para que tome efecto al momento de los que no se toman al momento x'D
-
Omití decirlo en el post anterior, pero lo probé y no hubo diferencia.
Aclaro como me conecto, por si el error está ahí.
1.- La aplicación VB6 se conecta por DSN a la base de datos, utilizando el usuario A.
2.- Se trabaja normalmente y se cierra la conexión con la base de datos cuando se cierra la aplicación.
Entonces, luego del paso 1 desde el servidor cambio los privilegios al usuario A y hago "FLUSH PRIVILEGES", pero el usuario sigue consultando la base de datos como si nada hubiera pasado.
Ahora, si cierro la aplicación y la vuelvo a iniciar, el usuario ya conecta sin los privilegios. Eso está bien, pero me gustaría que entre el paso 1 y el 2 pueda hacer que el usuario no pueda seguir haciendo consultas en la BD.
Muchas gracias, raul338.
Jerónimo
EDITO: También omití decir que luego de cambiar los privilegios voy al MySQL Administrator y en los privilegios de ese usuario contra esa bd se ve la información actualizada, pero la aplicación sigue trabajando sin problemas.
-
Es que eso depende exactamente de qué tipo de usuario tengan las terminales, si tu usuario es Administrador o SuperAdministrador, claro que va a seguir consultando los registros.
Los de un usuario normal deberían de ser estos:
SELECT- Selecciona los registros de la tabla/s
INSERT- Insertar registro en la tabla/s
UPDATE- Actualizar datos ya existentes en la tabla/s
ALTER- Modificar la estructura de la tabla/s
CREATE- Crear nuevas tablas, bases datos.
DROP- Eliminar tablas o BD
Los de un administrador ademas de esos deberian de ser estos:
FILE- Permite al admin leer y gravar achivos en el server mySQL
PROCESS- Permite al administrador controlar los procesos.
RELOAD- Permite al administrador reformar los acesos,privilegios...
SHUTDOWN- Permite al admin apagar el servidor
Y los privilegios especiales deben de ser muy bien tratados:
ALL- Todos los privilegios comentadas anteriormente
USAGE- Permite el acceso.
Si así no se te cumple lo que quieres, despues de revocar los privilegios al usuario de las temrinales hasle un reset al servidor, antes de que hagas tu proceso.
Intenta con RELOAD
Para mayor referencia
http://dev.mysql.com/doc/refman/5.0/es/privilege-changes.html
-
Aqui esta mejor explicado
http://dev.mysql.com/doc/refman/5.0/es/privileges-provided.html
Suerte y saludos.