Utilización multiusuario de una base de datos



Descargar 21.37 Kb.
Fecha de conversión26.01.2017
Tamaño21.37 Kb.
Utilización multiusuario de una base de datos

Hasta ahora hemos examinado las características del lenguaje SQL que se refieren a la definición y a la manipulación de los datos presentes en una base de datos, sin preocuparnos del hecho de que normalmente el acceso a tales datos se produce al mismo tiempo por parte de muchos usuarios.
Los mecanismo que hay que tener en cuenta para este método de acceso se refieren principalmente a la seguridad de los datos, la gestión de las transacciones y la posibilidad de definir las vistas en las tablas de la base de datos.

1. Seguridad

La ejecución de una operación en los datos de la base de datos por parte de un usuario está supeditada a la posesión por parte del usuario de los privilegios necesarios para la operación concreta ejecutada en el conjunto de datos específico.


En general, los privilegios se asignan del siguiente modo:


 Un usuario que crea una tabla o cualquier otro objeto de la base de datos es el propietario y se le garantizan automáticamente todos los privilegios aplicables a dicho objeto, con la posibilidad de darles también a otros usuarios dichos privilegios (privilegio de concesión).

 Un usario que tenga un privilegio y posea además sobre él el privilegio de concesión puede asignarle tal pricilegio a otro usuario y pasarle también el privilegio de concesión.


 Los privilegios los concede quien tiene el permiso (es decir el propietario del objeto y quien tiene el privilegio de concesión) mediante la orden GRANT, y los revoca mediante la orden REVOKE.

La sintaxis de la orden GRANT es la siguiente:

GRANT lista_privilegios ON objeto TO lista_usuarios [ WITH GRANT OPTION ]

Esto asigna al usuario los privilegios presentes en la lista_privilegios sobre el objeto especificado.


Los privilegios asignables son los siguientes (con sus respectivas sintaxis):

USAGE
Privilegio para usar un dominio específico u otro objeto de la base de datos.

SELECT
Privilegio para acceder a todas las columnas de una tabla o de una vista.

INSERT [ (nombre_columna) ]
Si se especifica la opción nombre_columna, es el privilegio para incluir valores en la columna indicada de una tabla o de una vista. Sin el nombre_columna es el privilegio para añadir valores a todas las columnas, incluidas las que se añadirán a continuación.

UPDATE [ (nombre_columna) ]
Si se especifica la opción nombre_columna, se trata del privilegio para actualizar el valor en la columna indicada de una tabla o de una vista. Si no, permite actualizar el valor de todas las columnas, incluidas las que se añadirán a continuación.

DELETE
Privilegio para eliminar líneas de una tabla o de una vista.

REFERENCES [ (nombre_columna) ]
Si se especifica la opción nombre_columna, es el privilegio de referirse a la columna indicada de una tabla o de una vista en la definición de un vínculo de integridad. Sin la opción, concede dicho privilegio para todas las columnas, incluidas las que se añaden a continuación.

El objeto al que se refiere el privilegio es generalmente una tabla o una vista. La sintaxis para su especificación es en ese caso:



[TABLE] nombre_tabla

En el caso de otros objetos, sigue la sintaxis:



tipo_objeto nombre_objeto

donde tipo_objeto puede ser DOMAIN, CHARACTER SET, COLLATION o TRANSLATION (véase C.J. Date - "A Guide to The SQL Standard" para una explicación de tales objetos).


En el caso de objetos que no sean tablas o vistas, el único privilegio aplicable es el de USAGE.

La lista_usuarios es una lista de identificativos de usuarios o grupos de usuarios. Puede usarse también la palabra clave PUBLIC, que indica todos los usuarios y los grupos coocidos en el sistema.

Si está presente la opción [ WITH GRANT OPTION ], se asigna además el privilegio de concesión, que permite a los usuarios transferir ulteriormente los privilegios que se les han asignado.

Por ejemplo:



GRANT SELECT, INSERT, UPDATE(nombre) ON persona TO benfante WITH GRANT OPTION

le asigna al usuario benfante los privilegios de SELECT e INSERT sobre todas las columnas de la tabla persona y el de UPDATE sobre la columna nombre de dicha tabla. Se les garantiza, además, el privilegio de asignar estos permisos a otros usuarios.

Para quitarles los privilegios a los usuarios se usa REVOKE:

REVOKE [ GRANT OPTION FOR ] lista_privilegios ON objeto FROM lista_usuarios { RESTRIC | CASCADE }

lista_privilegios, objeto y lista_usuarios tienen el mismo significado que las correspondientes opciones de GRANT. La opción GRANT OPTION FOR revoca el privilegio de concesión. Si se especifica la cláusula RESTRICT, la orden REVOKE puede fallar si el usuario al que se le han revocado los privilegios se los ha concedido posteriormente a otros. Si está presente la cláusula CASCADE, la instrucción se completará siempre con éxito y se revocarán también los privilegios de esos usuarios y de todos aquellos a quienes a su vez se les han concedido (...y así hasta que no haya más privilegios "abandonados", es decir concedidos sin que quien los ha concedido los posea todavía). Se destruirán, además, los objetos de la base de datos construidos gracias a dichos permisos.



2. Gestión de las transacciones

Las transacciones SQL son conjuntos de instrucciones que hay que tratar como unidades atómicas, es decir no descomponibles en las instrucciones individuales de las que están formadas. Gracias a esta atomicidad, las transacciones permiten que se ejecuten operaciones complejas en la base de datos, manteniendo la integridad. Efectivamente, una transacción se ejecuta con éxito si y sólo si todas las operaciones que la componen terminan con éxito. Si no, es decir si una de las operaciones falla, o si la transacción se anula explícitamente, todas las operaciones anteriores son también anuladas. Las operaciones de una transacción no tienen ningún efecto sobre la base de datos hasta que la transacción no se completa con éxito. 


Desde el momento en que a una base de datos pueden acceder diferentes usuarios al mismo tiempo, en cada instante podremos tener distintas transacciones que manipulen la base de datos a la vez. El estándar SQL prevé que normalmente las transacciones se ejecuten en el "nivel de aislamiento serializable" (isolation level SERIALIZABLE), o sea en una modalidad de ejecución que garantice la "serializabilidad" de las transacciones. El hecho de que las transacciones se puedan serializar significa que su efecto global sobre la base de datos es el que se obtendría si aquéllas se ejecutasen no al mismo tiempo, sino una después de otra. 
En el lenguaje SQL estándar, no existe una instrucción que haga iniciar explícitamente una transacción. Las instrucciones se dividen en dos clases: las que pueden empezar una transacción y las que no la hacen empezar. En el momento en que se intenta ejecutar una instrucción del primer tipo, si no está ya en marcha una transacción, empieza una. La transacción continúa hasta que una de las instrucciones falla, provocando la anulación de toda la transacción, o hasta que se ejecuten las instrucciones COMMIT WORK o ROLLBACK WORK. La instrucción COMMIT WORK termina la transacción confirmándola, convirtiendo en definitivos los efectos de sus instrucciones sobre la base de datos. Sin embargo, la instrucción ROLLBACK WORK acaba anulándola.
A menudo, las DBMS que se encuentran en el mercado implementan la gestión de las transacciones de modo distinto a como está previsto en el estándar (al menos en sus colocaciones por defecto). En este caso, normalmente está prevista una orden que empieza explícitamente una transacción (BEGIN TRANSACTION, START WORK u otro). Si una transacción no se ha empezado explícitamente, las instrucciones concretas componen una cada una.
Para entender mejor cuáles podrían ser las consecuencias de la manipulación concurrente de los datos de una base de datos sin usar transacciones, veamos un ejemplo. Supongamos que tenemos una base de datos con la que gestionamos los pedidos de los productos que vendemos. En concreto, cuando un cliente nos solicita un producto, comprobamos la disponibilidad y, en el caso en que podamos satisfacer el pedido, restamos a la cantidad que tenemos la cantidad que se nos ha pedido. Traduciendo todo esto a SQL, obtenemos la cantidad almacenada con la instrucción (instrucción A):

SELECT almacenamiento FROM productos
WHERE productoID=1453

La actualización del almacenamiento, una vez comprobada la disponibilidad se obtiene con la siguiente instrucción (instrucción B):



UPDATE productos
SET almacenamiento=almacenamiento-1
WHERE productoID=1453

Si dos usuarios intentan ejecutar esta operación, sin que las dos instrucciones que la componen se hayan reagrupado en una transacción, podría suceder que las instrucciones se ejecuten en el orden y con los resultados siguientes:



  1. Instrucción A, ejecutada por el usuario 1: se devuelve un almacenamiento del producto equivalente a 1, por lo que el pedido será aprobado.

  2. Instrucción A, ejecutada por el usuario 2: como antes, el almacenamiento es 1 y también en este caso el pedido se aprobará.

  3. Instrucción B, ejecutada por el usuario 1: en este punto, en la base de datos el almacenamiento para el producto vale 0.

  4. Instrucción B, ejecutada por el usuario 2: ahora el almacenamiento vale -1, que, obviamente, es un valor equivocado.

Como se ve, el resultado final es que uno de los dos clientes no podrá recibir (al menos no inmediatamente) la mercancía, dado que no teníamos en almacén una cantidad suficiente para ambos clientes. Si las dos instrucciones se hubieran incluido en una transacción, el problema no se habría producido, dado que la transacción del segundo usuario no habría podido leer el valor del almacenamiento hasta que no se hubiese completado la transacción del primer usuario. En ese momento, el almacenamiento habría tenido valor 0 y el pedido no habría estado erróneamente aprobado.

3. Vistas

Hasta ahora las únicas tablas de las que nos hemos ocupado han sido las definidas con la orden CREATE TABLE. El lenguaje SQL también pone a disposición la posibilidad de definir tablas "virtuales", las vistas, calculadas a partir de otras tablas. Son virtuales en el sentido que no ocupan espacio en el disco, pero son el resultado de interrogaciones sobre otras tablas y, por lo tanto, siempre están alineadas con los valores contenidos en dichas tablas.


La instrucción SQL para definir una vista es la siguiente:

CREATE VIEW nombre_vista [ ( lista_nombres_columnas ) ]
AS expresión_tabla

Crea una vista llamada nombre_vista definitda por la expresión_tabla. Típicamente, expresión_tabla es una instrucción select que producirá la tabla que interesa. La lista_nombres_columnas se puede usar para asignar nombres a las columnas de la vista. Esto es útil en el caso en que las columnas que derivan de la expresión_tabla sean resultado de un cálculo (por ejemplo COUNT(nombre_columna)) y por ello no tengan un nombre explícito. Una vez creada, una vista se puede utilizar como una tabla normal. Las unicas limitaciones se refieren a las operaciones que cambian los datos contenidos en ella. En efecto, no todas las vistas pueden actualizarse. Las reglas que discriminan entre una vista actualizable y una no actualizable son más bien complejas, y no es este el lugar para describirlas (véanse los libros en la bibliografía, concretamente el de C.J. Date). Aquí vamos a limitarnos a intentar entender, mediante un ejemplo, por qué sucede esto.


Hagamos la prueba usando la siguiente vista en nuestra base de datos bibliográfica:

CREATE VIEW book_publisher89
AS SELECT B.title, P.name
FROM Book B, Publisher P
WHERE B.publisher = P.ID
AND B.pub_year=1989

Ésta nos permite ejecutar la query que la define simplemente utilizando la instrucción:



SELECT * FROM book_publisher89

Podemos también introducir ulteriores condiciones (o hacer que el resultado se ordene según una columna concreta de la vista, etc...):



SELECT title FROM book_publisher89
WHERE name = "ACM Press"

Esta última interrogación nos ofrece la lista de los títulos de los libros publicados por ACM Press en 1989.

Como se ve, por lo que respecta a las operaciones de interrogación, una vista se comporta como una tabla normal. Las diferencias aparecen cuando se intentan aplicar a una vista operaciones de actualización. Por ejemplo, si intentamos ejecutar la siguiente instrucción:

INSERT INTO book_publisher89
VALUES( "Nuevo libro", "publisher")

La DBMS no conseguirá ejecutarla, devolviendo un error del tipo "No INSERT permission". El motivo es que no es capaz de crear las líneas correspondientes a nuestro nuevo récord en las dos tablas "reales" en las que se ha originado la vista (los problemas son varios: tiene que crear sólo una línea en la tabla Book y conectarla a una línea concreta de la tabla Publisher, o crear una línea en ambas tablas; cómo decidir qué valores darles a las llaves primarias de los eventuales nuevos récords; qué valores darles a los otros campos de las dos tablas, etc...)



Gracias a las vistas (y a la asignación prudente de los permisos a los usuarios) es posible conseguir que diferentes usuarios tengan una percepción de la estructura de la base de datos, si bien muy diferentes de la que tiene realmente, e impedir que algunas categorías de usuarios puedan acceder a informaciones que no les competen.
Por ejemplo, supongamos que contamos con una tabla en la que se han memorizado los datos personales de los empleados de una empresa, así como las cantidades que conforman sus respectivos sueldos. Obviamente, habría que evitar la consulta de los datos relativos a los sueldos por parte de los usuarios, excepto quienes se tienen que ocupar de su erogación/administración. Un sistema para hacerlo consiste en definir una vista que contenga sólo las columnas de los datos personales. Así, todos los usuarios autorizados a acceder a dichos datos, pero no a los de los sueldos, podrán entrar sólo a través de dicha vista. Ulteriores particiones podrían hacerse en sentido horizontal, creando por ejemplo una vista que sólo contenga las informaciones sobre los directivos y otra con los datos del resto de los dependientes. Además, las vistas a menudo contribuyen a facilitar la independencia entre aplicaciones y estructura de los datos, lo que hace que las bases de datos de los instrumentos sean tan útiles. Efectivamente, si en un momento determinado fuese necesario cambiar la estructura de la base de datos (descomponiendo, por ejemplo, una tabla en dos por motivos de eficacia), no habría que modificar todas las aplicaciones adaptándolas a la nueva estructura, sino que sería suficiente crear las vistas pertinentes, de modo que, desde el punto de vista de las aplicaciones, nada haya cambiado.


La base de datos está protegida por derechos de autor ©bazica.org 2016
enviar mensaje

    Página principal