7.1.
VISIÓN GENERAL
En una base de datos orientada a objetos, la información se representa
mediante objetos como los presentes en la programación orientada a objetos.
Cuando se integra las características de una base de datos con las de un
lenguaje de programación orientado a objetos, el resultado es un sistema gestor
de base de datos orientada a objetos (ODBMS, object data base management
system). Un ODBMS hace que los objetos de la base de datos aparezcan como
objetos de un lenguaje de programación en uno o más lenguajes de programación a
los que dé soporte. Un ODBMS extiende los lenguajes con datos persistentes de
forma transparente, control de concurrencia, recuperación de datos, consultas
asociativas y otras capacidades.
Las bases de datos orientadas a objetos se diseñan para trabajar bien en
conjunción con lenguajes de programación orientados a objetos como Java, C#,
Visual Basic.NET y C++. Los ODBMS usan exactamente el mismo modelo que estos
lenguajes de programación.
Los ODBMS son una buena elección para aquellos sistemas que necesitan un
buen rendimiento en la manipulación de tipos de dato complejos.
Los ODBMS proporcionan los costes de desarrollo más bajos y el mejor
rendimiento cuando se usan objetos gracias a que almacenan objetos en disco y
tienen una integración transparente con el programa escrito en un lenguaje de
programación orientado a objetos, al almacenar exactamente el modelo de objeto
usado a nivel aplicativo, lo que reduce los costes de desarrollo y
mantenimiento.
Los orígenes del término orientados a objetos (abreviado OO) se remontan a
los lenguajes de programación orientadas a objetos. Los lenguajes de programación
OO tienen sus raíces en el lenguaje SIMULA 67, propuesto a finales de la década
de 1960. En Simula, el concepto de clase agrupa la estructura de datos interna
de un objeto en una declaración de clase, es decir, introduce en el lenguaje
Algol los conceptos de objeto y de clase. Como Algol, Simula es un lenguaje
fuertemente tipado para entornos compilados. Sin embargo, el primer lenguaje
que popularizó la aproximación a objetos fue Smalltalk (1976); este puede
considerarse una síntesis de años del lenguaje Liso, que ofrece una gran
flexibilidad gracias a la interpretación, y de Simula, añadiendo el concepto de
metaclase. Smalltalk ha podido responder a las necesidades de flexibilidad
presentadas por el desarrollo de entornos de programación gráficos, favoreciendo
la rápida creación de prototipos de interfaces de usuarios amigables. Fue
utilizado con éxito en la primera estación gráfica de Xerox.
Con la llegada de las estaciones de trabajo en los años 80, han crecido
numerosos lenguajes orientados a objetos inspirados en Simula o Smalltalk.
Entre los lenguajes compilados, los más celebres son C++, Objective C y Eiffel,
debido a la compatibilidad del lenguaje o del código producido con el lenguaje
de programación C. La mayor parte de los lenguajes interpretados son
extensiones del Lisp; por ejemplo, Loops y CLOS. Es interesante notar que la
mayor parte de los lenguajes populares existentes se encuentran en curso de
ampliación para convertirse en orientados a objetos, incluyendo al Cobol y Ada
(más exactamente Ada 9X, que aporta la herencia).
En años recientes, han aparecido muchos prototipos experimentales y
sistemas de bases de datos comerciales orientados a objetos. Entre los primeros
se encuentran los sistemas ORION, OpenOODB, IRIS, ODE y el proyecto ENCORE/ObServer.
Y entre los sistemas disponibles en el mercado están: GEMSTONE/OPAL de
ServicLogic, ONTOS de Ontologic, Objectivity de Objectivity Inc., Versant de
Versant Technologies, ObjecStore de Object Design y O2 de O2 Technology. Esta
es solo una lista parcial de los prototipos experimentales y de los sistemas de
bases de datos comerciales orientados a objetos. Desafortunadamente, es aún
demasiado pronto para saber cuáles sistemas se instalarán como líderes en este
campo.
7.2.
TIPOS DE DATOS COMPLEJOS
Estos son los tipos de datos que soporta el SQL. Los sinónimos son palabras
equivalentes al tipo de dato indicado. El tamaño indica cuánto ocupará una
columna del tipo indicado.
Tipo de dato
|
Sinónimos
|
Tamaño
|
Descripción
|
BINARY
|
VARBINARY
BINARY VARYING BIT VARYING |
1 byte por
carácter
|
Se puede
almacenar cualquier tipo de datos en un campo de este tipo. Los datos no se
traducen (por ejemplo, a texto). La forma en que se introducen los datos en
un campo binario indica cómo aparecerán al mostrarlos.
|
BIT
|
BOOLEAN
LOGICAL LOGICAL1 YESNO |
1 byte
|
Valores Sí y
No, y campos que contienen solamente uno de dos valores.
|
TINYINT
|
INTEGER1
BYTE |
1 byte
|
Un número
entero entre 0 y 255.
|
COUNTER
|
AUTOINCREMENT
|
Se utiliza
para campos contadores cuyo valor se incrementa automáticamente al crear un
nuevo registro.
|
|
MONEY
|
CURRENCY
|
8 bytes
|
Un número
entero comprendido entre
– 922.337.203.685.477,5808 y 922.337.203.685.477,5807. |
DATETIME
|
DATE
TIME |
8 bytes
|
Una valor de
fecha u hora entre los años 100 y 9999
|
UNIQUEIDENTIFIER
|
GUID
|
128 bits
|
Un número de
identificación único utilizado con llamadas a procedimientos remotos.
|
DECIMAL
|
NUMERIC
DEC |
17 bytes
|
Un tipo de
datos numérico exacto con valores comprendidos entre 1028 - 1 y - 1028 - 1.
Puede definir la precisión (1 - 28) y la escala (0 - precisión definida). La
precisión y la escala predeterminadas son 18 y 0, respectivamente.
|
REAL
|
SINGLE
FLOAT4 IEEESINGLE |
4 bytes
|
Un valor de
coma flotante de precisión simple con un intervalo comprendido entre – 3,402823E38
y – 1,401298E-45 para valores negativos, y desde 1,401298E-45 a 3,402823E38
para valores positivos, y 0.
|
FLOAT
|
DOUBLE
FLOAT8 IEEEDOUBLE NUMBER |
8 bytes
|
Un valor de
coma flotante de precisión doble con un intervalo comprendido entre – 1,79769313486232E308
y – 4,94065645841247E-324 para valores negativos, y desde
4,94065645841247E-324 a 1,79769313486232E308 para valores positivos, y 0.
|
SMALLINT
|
SHORT
INTEGER2 |
2 bytes
|
Un entero
corto entre – 32.768 y 32.767.
|
INTEGER
|
LONG
INT INTEGER4 |
4 bytes
|
Un entero
largo entre – 2.147.483.648 y 2.147.483.647.
|
IMAGE
|
LONGBINARY
GENERAL OLEOBJECT |
Lo que se
requiera
|
Desde cero
hasta un máximo de 2.14 gigabytes.
Se utiliza para objetos OLE. |
TEXT
|
LONGTEXT
LONGCHAR MEMO NOTE NTEXT |
2 bytes por
carácter. (Consulte las notas).
|
Desde cero
hasta un máximo de 2.14 gigabytes.
|
CHAR
|
TEXT(n)
ALPHANUMERIC CHARACTER STRING VARCHAR CHARACTER VARYING NCHAR NATIONAL CHARACTER NATIONAL CHAR NATIONAL CHARACTER VARYING NATIONAL CHAR VARYING |
2 bytes por
carácter. (Consulte las notas).
|
Desde cero a
255 caracteres.
|
Un campo LONGTEXT se almacena siempre en el formato de representación
Unicode.
Si se utiliza el nombre del tipo de datos TEXT sin especificar la longitud
opcional (TEXT(25), por ejemplo), se crea un campo LONGTEXT. Esto permite
escribir instrucciones CREATE TABLE que producirán tipos de datos coherentes
con Microsoft SQL Server.
Un campo CHAR se almacena siempre en el formato de representación Unicode,
que es el equivalente del tipo de datos NATIONAL CHAR del SQL de ANSI.
Si se utiliza el nombre del tipo de datos TEXT y se especifica la longitud
opcional (TEXT(25), por ejemplo), el tipo de datos del campo es equivalente al
tipo de datos CHAR. De ese modo, se mantiene la compatibilidad con versiones
anteriores para la mayoría de las aplicaciones de Microsoft Jet, a la vez que
se habilita el tipo de datos TEXT (sin especificación de longitud) para la
alineación con Microsoft SQL Server.
Los caracteres de los campos definidos como TEXT (también conocidos como
MEMO) o CHAR (también conocidos como TEXT(n) con una longitud específica) se
almacenan en el formato de representación Unicode. Los caracteres Unicode
requieren siempre dos bytes para el almacenamiento de cada carácter. Para las
bases de datos de Microsoft Jet ya existentes que contengan principalmente
datos de tipo carácter, esto puede significar que el tamaño del archivo de base
de datos sea casi el doble cuando se convierta al formato Microsoft Jet 4.0.
Sin embargo, la representación Unicode de muchos juegos de caracteres, antes
denominados juegos de caracteres de un solo byte (SBCS), puede comprimirse
fácilmente a caracteres de un solo byte. Si define una columna CHAR con el
atributo COMPRESSION, los datos se comprimirán automáticamente a medida que se
almacenen y se descomprimirán cuando se recuperen de la columna.
7.3.
TIPOS ESTRUCTURADOS
Antes de SQL: 1999 el sistema de tipos
de SQL consistía en un conjunto bastante sencillo de tipos predefinidos. SQL:
1999 añadió un sistema de tipos extenso a SQL, lo que permite los tipos
estructurados y la herencia de tipos.
Los tipos estructurados permiten representar directamente los atributos compuestos de los diagramas E-R. Por ejemplo, se puede definir el siguiente tipo estructurado para representar el atributo compuesto nombre con los atributos componentes nombre pila y apellidos:
Los tipos estructurados permiten representar directamente los atributos compuestos de los diagramas E-R. Por ejemplo, se puede definir el siguiente tipo estructurado para representar el atributo compuesto nombre con los atributos componentes nombre pila y apellidos:
create type Nombre as
(nombre_pila varchar(20),
apellidos varchar(20))
final
De manera parecida, el tipo estructurado siguiente puede usarse para representar el atributo compuesto dirección:
create type Direccion as
(calle varchar(20),
ciudad varchar(20),
codigo_postal varchar(9))
not final
En SQL estos tipos se denominan tipos definidos por el usuario. La especificación final indica que no se puede crear subtipos de nombre, mientras que la especificación not final de dirección indica que se pueden crear subtipos de dirección. Ahora se pueden usar estos tipos para crear atributos compuestos en las relaciones, con sólo declarar que un atributo es de uno de estos tipos. Por ejemplo, se puede crear una tabla cliente de la siguiente manera.
create table cliente (
nombre Nombre,
direccion Direccion,
fecha_nacimiento date)
O bien, realizando una estructura más del tipo Cliente y generar la tabla a partir de ella:
create type TipoCliente as
(nombre Nombre,
direccion Direccion,
fecha_nacimiento date)
not final
create table client of TipoCliente
Se puede tener acceso a los componentes de los atributos compuestos usando la notación “punto”; por ejemplo, nombre.nombre_pila devuelve el componente nombre de pila del atributo nombre. El acceso al atributo nombre devolvería un valor del tipo estructurado Nombre.
La siguiente consulta ilustra la manera de tener acceso a los atributos componentes de los atributos compuestos. La consulta busca el apellido y la ciudad de cada cliente.
select nombre.apellido, direccion.ciudad
from cliente
En SQL: 1999 se usan funciones constructoras para crear valores de los tipos estructurados. Las funciones con el mismo nombre que un tipo estructurado son funciones constructoras de ese tipo estructurado. Por ejemplo, se puede declarar una función constructora para el tipo Nombre de esta manera:
create functionNombre(nombre_pila varchar(20), apellidos varchar(20))
returns Nombre
begin
set self.nombre_pila = nombre_pila;
set self.apellidos =
apellidos;
end
De manera predeterminada, cada tipo estructurado tiene una función sin argumentos que configura los atributos con sus valores predeterminados. Cualquier otra función constructora hay que crearla de manera específica.
La instrucción siguiente ilustra la manera de crear una nueva tupla de la relación Cliente. Se da por supuesto que se ha definido una función constructora para Direccion, igual que la función constructora que se definió para Nombre.
insert into Cliente
values
(new Nombre(‘Martín’, ‘Gómez’),
new Direccion(‘Calle Mayor
20’, ‘Madrid’, ‘28045’),
date ‘22-8-1960’)
Herencia de tipos:
Supóngase que se tiene la siguiente
definición de tipo para las personas:
create type Persona
(nombre varchar(20),
direccion varchar(20))
Puede que se desee almacenar en la base de datos información adicional sobre las personas que son estudiantes y sobre las que son profesores. Dado que los estudiantes y los profesores también son personas, se puede usar la herencia para definir en SQL los tipos estudiante y profesor:
create typeEstudiante
under Persona
(grado varchar(20),
departamento varchar(20))
create typeProfesor
under Persona
(sueldo Integer,
departamento varchar(20))
Tanto Estudiante como Profesor heredan los atributos de Personas.
Herencia de tablas:
Las subtablas de SQL se corresponden con
el concepto de especialización / generalización de E-R Por ejemplo, supóngase
que se define la tabla personas de la siguiente manera:
create tablepersonas of Persona
A continuación se puede definir las tablas estudiantes y profesores como subtablas de personas, de la manera siguiente:
create tableestudiantes of Estudiante
under personas
create tableprofesores of Profesor
under personas
Los tipos de las subtablas deben ser subtipos del tipo de la tabla madre. Por tanto, todos los atributos presentes en personas también están presentes en las subtablas.
Además, cuando se declaran estudiantes y profesores como subtablas de personas, todas las tuplas presentes en estudiantes y profesores pasan a estar también presentes de manera implícita en personas. Por tanto, si una consulta usa la tabla personas, no sólo encuentra tuplas directamente insertadas en esa tabla, sino también tuplas insertadas en sus subtablas, es decir, estudiantes y profesores. No obstante, esa consulta sólo puede tener acceso a los atributos que están presentes en personas.
SQL permite hallar tuplas que se encuentran en personas pero no en sus subtablas usando en las consultas “only personas” en lugar de personas. La palabra clave only también puede usarse en las sentencias delete y update. Sin la palabra clave only, la instrucción delete aplicada a una supertabla, como personas, también borra las tuplas que se insertaron originalmente en las subtablas (como estudiantes); por ejemplo, la instrucción:
delete from personas where P
Borrará todas las tuplas de la tabla personas, así como de sus
subtablas estudiantes y profesores, que satisfagan P.
Si se añade la palabra clave only a la instrucción anterior, las tuplas
que se insertaron en las subtablas no se ven afectadas, aunque satisfagan las
condiciones de la cláusulawhere.
SQL soporta dos tipos de conjuntos: arrays y multiconjuntos; los tipos
array se añadieron en SQL:1999, mientras que los tipos multiconjuntos se
agregaron en SQL:2003. Un multiconjunto es un conjunto no ordenado, en el que
cada elemento puede aparecer varias veces.
Supóngase que se desea registrar
información sobre libros, incluido un conjunto de palabras clave para cada
libro. Supóngase también que se deseara almacenar almacenar el nombre de los
autores de un libro en forma de array; a diferencia de los elementos de los
multiconjuntos, los elementos de los arrays están ordenados, de modo que se
puede distinguir el primer autor del segundo autor, etc. El ejemplo siguiente
ilustra la manera en que se puede definir en SQL estos atributos como arrays y
como multiconjuntos.
create type Editor as
(nombre varchar(20),
sucursal varchar(20))
create type Libro as
(titulo varchar(20),
array_autores varchar(20) array[10],
fecha_publicacion date,
editor Editor,
conjunto_palabras_clave varchar(20) multiset)
create table libros of Libro
Creación y acceso a los valores de los conjuntos:
En SQL:1999 se puede crear un array de
valores de esta manera:
array[‘Silberschartz’, ‘Korth’, ‘Sudarshan’]
array[‘Silberschartz’, ‘Korth’, ‘Sudarshan’]
De manera parecida, se puede crear un
multiconjunto de palabras clave de la manera siguiente:
multiset[‘Silberschartz’, ‘Korth’, ‘Sudarshan’]
Por lo tanto, se puede crear una tupla
definido por la relación libros como:
insert into libros
values
(‘Compiladores’, array[‘Gómez’,
‘Santos’’],
new Editor(‘McGraw-Hill’,
‘Nueva York’),
multiset[‘análisis sintáctico’,
‘análisis’])
Se puede tener acceso a los elementos del array o actualizarlos especificando el índice del array, por ejemplo, array_autores[1].
Consulta de los atributos valorados como
conjuntos
Ahora se considerará la forma de manejar
los atributos que se valoran como conjuntos. Las expresiones que se valoran
como conjuntos pueden aparecer en cualquier parte en la que pueda aparecer el
nombre de una relación, como las cláusulas from.
Si se desea averiguar todos los libros
que contengan las palabras “base de datos” entre sus palabras clave, se puede
usar la consulta siguiente:
select titulo
form libros
where ‘base de datos’ in
(unnest(conjunto_palabras_clave))
Identidad de los objetos y tipos de referencia en SQL:
Los lenguajes orientados a objetos ofrecen la posibilidad de hacer referencia a objetos. Los atributos de un tipo dado pueden servir de referencia para los objetos de un tipo concreto. Por ejemplo, en SQL se puede definir el tipo Departamento con el campo nombre y el campo director, que es una referencia al tipo Persona, y la tabla departamentos del tipo Departamento, de la manera siguiente:
irecc type Departamento(
nombre varchar(20),
director ref(Persona) scope personas)
irecc table departamentos of Departamento
En este caso, la referencia está restringida a las tuplas de la tabla personas. La restricción del ámbito de referencia a las tuplas de una tabla es obligatoria en SQL, y hace que las referencias se comporten como las claves externas.
La tabla a la que hace referencia debe tener un atributo que guarde el identificador para cada tupla. Ese atributo, denominado atributo autorreferenciable (self-referential attribute), se declara añadiendo una cláusula irecc a la instrucción irecc table:
create table personas of Persona
ref is id_persona system generated
En este caso, id_persona es el nombre del atributo, no una palabra clave, y la instrucción system generated especifica que la base de datos genera de manera automática el identificador.
Para inicializar el atributo de
referencia hay que obtener el identificador de la tupla a la que se va a hacer
referencia. Se puede conseguir el valor del identificador de la tupla mediante
una consulta. Por tanto, para crear una tupla con el valor de referencia,
primero se puede crear la tupla con una referencia nula y luego definir la
referencia de manera independiente:
insert into departamentos
values (‘CS’, null)
update departamentos set director = (select p.id_persona
from persona as p
where nombre = ‘Martín’)
where nombre = ‘CS’
Una alternativa a los identificadores generados por el sistema es permitir que los usuarios generen los identificadores. El tipo del atributo autoreferencial debe especificarse como parte de la definición de tipos de la tabla a la que se hace referencia, y la definición de la tabla debe especificar que la referencia está generada por el usuario (user generated):
irecc type Persona
(nombre varchar(20),
irección varchar(20))
ref using varchar(20)
create table personas of Persona
ref is id_persona user generated
Al insertar tuplas en personas hay que proporcionar el valor del identificador:
insert intopersonas (id_persona, nombre, irección) values
(‘01284567’, ‘Martín’, ‘Av del Segura,
23’)
Implementación de las características O-R:
Los sistemas de bases de datos relacionales
orientadas a objetos son básicamente extensiones de los sistemas de bases de
datos relacionales ya existentes. Las modificaciones resultan claramente
necesarias en muchos niveles del sistema de base de datos.
Las interfaces de programas de aplicación
como ODBC y JDBC se han extendido para recuperar y almacenar tipos
estructurados; por ejemplo, JDBC ofrece el método getObject() que devuelve un
objeto Java Struct, a partir del cual se pueden extraer los componentes del
tipo estructurado. También es posible asociar clases de Java con tipos
estructurados de SQL, y JDCB puede realizar conversiones entre los tipos.
Lenguajes de programación persistentes:
Lenguajes de programación persistentes:
Los lenguajes de las bases de datos se
diferencian de los lenguajes de programación tradicionales en que trabajan
directamente con datos que son persistentes; es decir, los datos siguen
existiendo una vez que el programa que los creó haya concluido. Las relaciones
de las bases de datos y las tuplas de las relaciones son ejemplos de datos
persistentes.
El acceso a las bases de datos es sólo un componente de las aplicaciones del mundo real. Mientras que los lenguajes para el tratamiento de datos como SQL son bastante efectivos en el acceso a los datos, se necesita un lenguaje de programación para implementar otros componentes de las aplicaciones como las interfaces de usuario o la comunicación con otras computadoras. La manera tradicional de realizar las interfaces de las bases de datos con los lenguajes de programación es incorporar SQL dentro del lenguaje de programación.
El acceso a las bases de datos es sólo un componente de las aplicaciones del mundo real. Mientras que los lenguajes para el tratamiento de datos como SQL son bastante efectivos en el acceso a los datos, se necesita un lenguaje de programación para implementar otros componentes de las aplicaciones como las interfaces de usuario o la comunicación con otras computadoras. La manera tradicional de realizar las interfaces de las bases de datos con los lenguajes de programación es incorporar SQL dentro del lenguaje de programación.
Los lenguajes de programación persistentes son lenguajes de programación extendidos con estructuras para el tratamiento de los datos persistentes. Los lenguajes de programación persistentes pueden distinguirse de los lenguajes con SQL incorporado, al menos, de dos maneras:
En los lenguajes incorporados el sistema
de tipos del lenguaje anfitrión suele ser diferente del sistema de tipos del
lenguaje para el tratamiento de los datos. Los programadores son responsables
de las conversiones de tipo entre el lenguaje anfitrión y SQL. Hacer que los
programadores lleven a cabo esta tarea presenta varios inconvenientes:
El código para la conversión entre
objetos y tuplas opera fuera del sistema de tipos orientado a objetos y, por lo
tanto, tiene más posibilidades de presentar errores no detectados.
La conversión en la base de datos entre
el formato orientado a objetos y el formato relacional de las tuplas necesita
gran cantidad de código. El código para la conversión de formatos, junto con el
código para cargar y descargar datos de la base de datos, puede suponer un
porcentaje significativo del código total necesario para la aplicación.
Por el contrario, en los lenguajes de
programación persistentes, el lenguaje de consultas se halla totalmente integrado
con el lenguaje anfitrión y ambos comparten el mismo sistema de tipos. Los
objetos se pueden crear y guardar en la base de datos sin ninguna modificación
explícita del tipo o del formato; los cambios de formato necesarios se realizan
de manera transparente.
Los programadores que usan lenguajes de
consultas incorporados son responsables de la escritura de código explícito
para la búsqueda en la memoria de los datos de la base de datos. Si se realizan
actualizaciones, los programadores deben escribir explícitamente código para
volver a guardar los datos actualizados en la base de datos.
Por el contrario, en los lenguajes de programación persistentes, los programadores pueden trabajar con datos persistentes sin tener que escribir explícitamente código para buscarlos en la memoria o volver a guardarlos en el disco.
Por el contrario, en los lenguajes de programación persistentes, los programadores pueden trabajar con datos persistentes sin tener que escribir explícitamente código para buscarlos en la memoria o volver a guardarlos en el disco.
Sin embargo, los lenguajes de
programación persistentes presentan ciertos inconvenientes que hay que tener
presentes al decidir su conviene usarlos. Dado que los lenguajes de
programación suelen ser potentes, resulta relativamente sencillo cometer
errores de programación que dañen las bases de datos. La complejidad de los
lenguajes hace que la optimización automática de alto nivel, como la reducción
de E/S de disco, resulte más difícil. En muchas aplicaciones el soporte de las
consultas declarativas resulta de gran importancia, pero los lenguajes de
programación persistentes no soportan bien actualmente las consultas declarativas (SQL
es un ejemplo).
Persistencia de objetos:
Persistencia de objetos:
Los lenguajes de programación orientados
a objetos ya poseen un concepto de objeto, un sistema de tipos para definir los
tipos de los objetos y constructores para crearlos. Sin embargo, esos objetos
son transitorios; desaparecen en cuanto finaliza el programa, igual que ocurre
con las variables de los programas en C o Pascal. Si se desea transformar uno
de estos lenguajes en un lenguaje para la programación de base de datos, el
primer paso consiste en proporcionar una manera de hacer persistentes los
objetos. Se han propuesto varios enfoques.
o
Persistencia por
clases. El enfoque más sencillo, pero el menos
conveniente, consiste en declarar que una clase es persistente. Todos los
objetos de la clase lo son, por tanto, persistentes de manera predeterminada.
o
Persistencia por
creación. En este enfoque se introducen una
sintaxis nueva para crear los objetos persistentes mediante la extensión de la
sintaxis nueva para la creación de los objetos transitorios. Por tanto, los
objetos son persistentes o transitorios en función de la forma de crearlos.
Varios sistemas de bases de datos orientados a objetos siguen este enfoque.
o
Persistencia por
marcas. Una variante del enfoque anterior es
marcar los objetos como persistentes después de haberlos creado. Todos los
objetos se crean como transitorios pero, si un objeto tiene que persistir más
allá de la ejecución del programa, hay que marcarlo como persistente de manera
explícita antes de que éste concluya.
o
Persistencia por
alcance. Uno o varios objetos se declaran
objetos persistentes (objetos raíz) de manera explícita. Todos los demás
objetos serán persistentes si (y sólo sí) se pueden alcanzar desde algún objeto
raíz mediante una secuencia de una o varias referencias.
Por tanto, todos los objetos a los que se haga referencia desde (es decir, cuyos identificadores de objetos se guarden en) los objetos persistentes raíz serán persistentes. Pero también lo serán todos los objetos a los que se haga referencia desde ellos, y los objetos a los que éstos últimos hagan referencia serán también persistentes, etc.
Una ventaja de este esquema es que resulta sencillo hacer que sean persistentes estructuras de datos complejas con sólo declarar como persistente su raíz. Sin embargo, el sistema de base de datos sufre la carga de tener que seguir las cadenas de referencias para detectar los objetos que son persistentes, y eso puede resultar costoso.
Por tanto, todos los objetos a los que se haga referencia desde (es decir, cuyos identificadores de objetos se guarden en) los objetos persistentes raíz serán persistentes. Pero también lo serán todos los objetos a los que se haga referencia desde ellos, y los objetos a los que éstos últimos hagan referencia serán también persistentes, etc.
Una ventaja de este esquema es que resulta sencillo hacer que sean persistentes estructuras de datos complejas con sólo declarar como persistente su raíz. Sin embargo, el sistema de base de datos sufre la carga de tener que seguir las cadenas de referencias para detectar los objetos que son persistentes, y eso puede resultar costoso.
Sistemas Java persistentes:
En años recientes el lenguaje Java ha
visto un enorme crecimiento en su uso. La demanda de soporte de la persistencia
de los datos en los programas de Java se incrementado de manera acorde. Los
primeros intentos de creación de una norma para la persistencia en Java fueron
liderados por el consorcio ODMG; posteriormente, el consorcio concluyó su
esfuerzo, pero transfirió su diseño al proyecto Java Database Object (JDO), que
coordibaba Sun Microsystems.
Entre sus características se hallan:
o
Persistencia por
alcance. Los objetos no se crean explícitamente
en la base de datos. El registro explícito de un objeto como persistencia hace
que el objeto sea persistente. Además, cualquier objeto alcanzable desde un
objeto persistente pasa a ser persistente.
o
Mejora del código
de bytes. En lugar de declarar en el código Java
que una clase es persistente, se especifica en un archivo de configuración (con
terminación .jdo) las clases cuyos objetos se pueden hacer persistentes. Se
ejecuta un programa mejorador específico de la implementación que
lee el archivo de configuración y lleva a cabo dos tareas. En primer lugar,
puede crear estructuras en la base de datos para almacenar objetos de esa
clase. En segundo lugar, modifica el código de bytes (generado al compilar el
código Java) para que maneje tareas relacionadas con la persistencia.
o
Asignación de base
de datos. JDO no define la manera en que se
almacenan los datos en la base de da datos subyacente. Por ejemplo, una
situación frecuente es que los objetos se almacenen en una base de datos
relacional. Por ejemplo, una situación frecuente es que los objetos se almacenen
en una base de datos relacional. El programa mejorador puede crear en la base
de datos un esquema adecuado para almacenar los objetos de las clases. La
manera exacta en que lo hace depende de la implementación y no está definida
por JDO. Se puede asignar algunos atributos a los atributos relacionales,
mientras que otros se pueden almacenar de forma serializada, que la base de
datos trata como si fuera un objeto binario. Las implementaciones de JDO pueden
permitir que los datos relacionales existentes se vean como objetos mediante la
definición de la asignación correspondiente.
o
Extensiones de
clase. Las extensiones de clase se crear y se
conservan de manera automática para cada clase declarada como persistente.
Todos los objetos que se hacen persistentes se añaden de manera automática a la
extensión de clase correspondiente a su clase. Los programas de JDO pueden
tener acceso a las extensiones de clase e iterar sobre los miembros
seleccionados. La interfaz iteradora ofrecida por Java se puede usar para crear
iteradores sobre las extensiones de clase y avanzar por los miembros de cada
extensión de clase. JDO también permiten que se especifiquen selecciones cuando
se crea una extensión de clase y que sólo se capturen los objetos que
satisfagan la selección.
La norma JDO se halla todavía en una
etapa preliminar y sometida a revisión. Varias empresas ofrecen
implementaciones de JDO.
Sistemas orientados a objetos y sistemas relacionales orientados a objetos
Las extensiones persistentes de los
lenguajes de programación y los sistemas relacionales orientados a objetos se
dirigen a mercados diferentes. La naturaleza declarativa y limitada potencia
(comparada con la de los lenguajes de programación) del lenguaje SQL
proporcionan una buena protección de los datos respecto de los errores de
programación y hacen que las optimizaciones de alto nivel, como la reducción
E/S resulte relativamente sencilla. Los sistemas relacionales orientados a
objetos se dirigen a simplificar la realización de los modelos de datos y de las
consultas mediante el uso de tipos de datos complejos. Entre las aplicaciones
habituales están el almacenamiento y la consulta de datos complejos, incluidos
los datos multimedia.
Los lenguajes declarativos como SQL, sin
embargo, imponen una reducción significativa del rendimiento a ciertos tipos de
aplicaciones que se ejecutan principalmente en memoria principal y realizan
gran número de accesos a la base de datos. Los lenguajes de programación
persistentes se dirigen a las aplicaciones de este tipo que tienen necesidad de
un rendimiento elevado. Proporcionan acceso a los datos persistentes con poca
sobrecarga y eliminan la necesidad de traducir los datos si hay que tratarlos
con un lenguaje de programación. Sin embargo, son más susceptibles a deteriorar
los datos debido a los errores de programación y no suelen disponer de gran
capacidad de consulta. Entre las aplicaciones habituales están las bases de
datos de CAD (Diseño asistido por computadora).
Los puntos fuertes de los diversos tipos
de sistemas de bases de datos pueden resumirse de la manera siguiente:
Sistemas relacionales: tipos de datos sencillos, lenguajes de consultas potentes, protección
elevada.
Bases de datos orientadas a objetos
basadas en lenguajes de programación persistentes: tipos de datos complejos, integración con los lenguajes de
programación, elevado rendimiento.
Sistemas relacionales orientados a
objetos: tipos de datos complejos, lenguajes de
consultas potentes, protección elevada.
Estas descripciones son válidas en
general, pero hay que tener en cuenta que algunos sistemas de bases de datos no
respetan estas fronteras. Por ejemplo, algunos sistemas de base de datos
orientados a objetos construidos alrededor de lenguajes de programación
persistentes se pueden implementar sobre sistemas de bases de datos
relacionales o sobre sistemas de bases de datos relacionales orientados a
objetos. Puede que estos sistemas proporcionen menor rendimiento que los
sistemas de bases de datos orientados a objetos construidos directamente sobre
los sistemas de almacenamiento, pero proporcionan parte de las garantías de
protección más estrictas propias de los sistemas relacionales.
7.4.
HERENCIA DE TABLAS
Herencia
La herencia puede hallarse en el nivel de los tipos o en el nivel de las tablas. En primer lugar se considerara la herencia de los tipos y después en el nivel de las tablas.
La herencia puede hallarse en el nivel de los tipos o en el nivel de las tablas. En primer lugar se considerara la herencia de los tipos y después en el nivel de las tablas.
Cada tabla almacena todos los atributos heredados y definidos localmente.
Cuando se inserta una tupla se almacena solo en la subtabla en la que se
inserta y su presencia se infiere en cada supertabla. El acceso a todos los
atributos de una tupla es más rápido, dado que no se requiere una
reunión.
Ejemplo de herencia
Supóngase que se tiene la siguiente definición de tipo para las personas:
create type Persona
(nombre varchar(20),
direccion varchar(20))
Puede que se desee almacenar en la base de datos información adicional sobre las personas que son estudiantes y sobre las que son
profesores. Dado que los estudiantes y los profesores también son personas, se
puede usar la herencia para definir en SQL los tipos estudiante y profesor:
create type Estudiante
under Persona
(grado varchar(20),
departamento varchar(20))
create type Profesor
under Persona
(sueldo Integer,
departamento varchar(20))
Otro
ejemplo:
Primer Método: Herencia de Tabla Única (Single Table Inheritance)
Una Tabla guarda todos los datos y se define una variable de Tipo.
Segundo Método: Herencia de Tablas Concretas (Concrete Table Inheritance)
Cada Clase utilizable se define en una tabla independiente con todas sus
propiedades heredadas.
Tercer Método: Herencia de Tablas de Clases (Class Table Inheritance)
Se define una tabla para cada clase y no se incluyen sus propiedades
heredadas.
Conclusión:
A lo que se refiere a la herencia de registros atreves de tablas tenemos
que tener una tabla que se le denomina type (tipos) al que se le van a pasar
los registros de otras tablas o subtablas.
Para comprender éste concepto muy interesante y útil para muchos casos
veremos un ejemplo bastante sencillo. Crearemos una tabla llamada ciudades y
otras capitales. Las capitales son también ciudades pero supongamos que
necesitamos recuperar rápidamente los datos de las ciudades, sin pasar por un
índice de tabla que contiene miles o millones de registros. Esa es la mayor
virtud a mi punto de vista de las tablas heredades, si la usamos en los
contextos correctos podríamos mejorar el rendimiento de una BD altamente
concurrida que comience a sufrir de bloqueos y retrasos importantes
en el tiempo de lectura/escritura.
Comenzaremos creando la tabla padre con 3 campos
CREATE TABLE ciudades (
nombre text,
poblacion float,
altura int
);
Ya tenemos el padre, podemos crear un hijo a partir de él. Además le
agregaremos 1 columna más que nos dirá a que departamento o estado pertenece
ésa capital.
CREATE TABLE capitales (
departamento
char(2)
) INHERITS (ciudades);
Procedemos a insertar los datos en las respectivas tablas
insert into ciudades values ('Fernando de la Mora', 24522, 25);
insert into ciudades values ('Lambaré', 34500, 135);
insert into ciudades values ('San Lorenzo', 16852, 120);
insert into capitales values ('Asuncion', 450000, 136, 'CN');
insert
into capitales values ('Encarnacion', 128000, 120, 'EN');
Seleccionando las tablas veremos los resultados y el comportamiento
obtenido. El primer query retornará el siguiente conjunto de resultados.
"Fernando de la Mora";24522;25
"Lambaré";34500;135
"San Lorenzo";16852;120
"Asuncion";450000;136
"Encarnacion";128000;120
Obteniendo los siguiente con el segundo query
"Asuncion";450000;136;"CN"
"Encarnacion";128000;120;"EN"
Con esto obtenemos una reducción en la construcción del índice y ganaremos
velocidad con ello además de un mejor orden conceptual de nuestras tablas. No
sólo se puede heredar de un padre, es posible heredar de varias tablas, así
teniendo la tabla hija todas las columnas de sus padres, y en caso que 2 o más
padres tengan un columna con el mismo nombre éstas se fusionarán en la hija
siempre y cuando sean del mismo tipo de dato.
Al utilizar ésta poderosa característica existen algunas consideraciones
que hay que tener en cuenta para evitarnos sorpresas desagradables e
inesperadas. Al crear tablas heredadas, no todas las características de la
tabla se heredan. Por ejemplo, las claves primarias, foráneas, indices únicos.
Según el roadmap se verá para implementarlo a futuro pero no es de prioridad
alta por eso que viene retrasándose su implementación desde versiones antiguas.
7.5.
TIPOS DE ARREGLOS EN MULTICONJUNTO
en
SQL soporta dos tipos de conjuntos: arrays y
multiconjuntos. Multiconjuntos es un conjunto no ordenado, en el que cada
elemento puede aparecer varias veces. A diferencia de los elementos de los
multiconjuntos, los elementos de los arrays están ordenados Por ejemplo se
ilustra la manera en que se pueden definir en SQL, estos atributos valorados
con arrays y multiconjuntos. create type Editor as (nombre varchar(20) sucursal
vachar(20) create type Libro as (titulo vachar (20), array_autores vachar (20)
array[10], fecha_publicacion date, editor Editor, conjunto_palabras_clave
varchar(20) multiset) create table Los atributos multivalorados de los esquemas
E-R se pueden asignar en SQL atributos valorados como multiconjuntos si el orden
es importante se pueden usar los arrays de SQL en lugar de los multiconjuntos.
• Creación y acceso a los valores de los conjuntos
array[´silberschatz´,´Korth´, ´Sudarshan´] de manera parecida se puede crear un
multiconjunto de palabras clave de la manera siguiente: multiset[´computadora´,
´base de datos´, ´SQL] Consulta de los atributos valorados como conjuntos´
Ahora se considerara la forma de manejar los atributos que se valoran como
conjuntos. Las expresiones que se valoran como conjuntos pueden aparecer en
cualquier parte en la que pueda aparecer el nombre de una relación, como las
clausulas FROM. Al desanidar un arrays la consulta anterior pierde información
sobre el orden de los elementos de consulta. Se pueden usar las clausulas
UNESTED WITH ORDINALITY para obtener esta información. La clausulas WITH
ORDINALITY genera un atributo adicional que se registra la posición del
elemento en el arrays. Se puede usra una consulta parecida. Pero sin la cláusula
WITH ORDINALITY, para generar la relación. Anidamiento y desanidamiento La
transformación de una relación anidada en una forma con menos atributos de
tipos relación (o sin ellos) se denomina desanidamiento.
7.6.
IDENTIDAD DE LOS OBJETOS
Los lenguajes
orientados a objetos ofrecen la posibilidad de hacer referencia a objetos. Los
atributos de un tipo dado pueden servir de referencia para los objetos de un
tipo concreto. Por ejemplo, en SQL se puede definir el tipo Departamento con el
campo nombre y el campo director, que es una referencia al tipo Persona, y la
tabla departamentos del tipo Departamento, de la manera siguiente:
create type
Departamento(
nombre varchar(20),
director
ref(Persona) scope personas)
create table
departamentos of Departamento
En este caso, la
referencia está restringida a las tuplas de la tabla personas. La restricción
del ámbito de referencia a las tuplas de una tabla es obligatoria en SQL, y
hace que las referencias se comporten como las claves externas.
La tabla a la que
hace referencia debe tener un atributo que guarde el identificador para cada
tupla. Ese atributo, denominado atributo autorreferenciable (self-referential
attribute), se declara añadiendo una cláusula ref is a la instrucción create
table:
create table
personas of Persona
ref is id_persona
system generated
En este caso,
id_persona es el nombre del atributo, no una palabra clave, y la instrucción
system generated especifica que la base de datos genera de manera automática el
identificador.
Para inicializar el
atributo de referencia hay que obtener el identificador de la tupla a la que se
va a hacer referencia. Se puede conseguir el valor del identificador de la
tupla mediante una consulta. Por tanto, para crear una tupla con el valor de
referencia, primero se puede crear la tupla con una referencia nula y luego
definir la referencia de manera independiente:
insert into
departamentos
values (‘CS’, null)
update
departamentos set director = (select p.id_persona
from persona as p
where nombre =
‘Martín’)
where nombre = ‘CS’
Una alternativa a
los identificadores generados por el sistema es permitir que los usuarios
generen los identificadores. El tipo del atributo autoreferencial debe
especificarse como parte de la definición de tipos de la tabla a la que se hace
referencia, y la definición de la tabla debe especificar que la referencia está
generada por el usuario (user generated):
create type Persona
(nombre
varchar(20),
direccion
varchar(20))
ref using
varchar(20)
create table
personas of Persona
ref is id_persona
user generated
Al insertar tuplas
en personas hay que proporcionar el valor del identificador:
insert into
personas (id_persona, nombre, direccion) values
(‘01284567’,
‘Martín’, ‘Av del Segura, 23’)
7.7.
IMPLEMENTACIÓN DE LAS CARACTERÍSTICAS
Los sistemas de bases de datos relacionales orientadas
a objetos son básicamente extensiones de los sistemas de bases de datos
relacionales ya existentes. Las modificaciones resultan claramente necesarias
en muchos niveles del sistema de base de datos.
Las interfaces de programas de aplicación como ODBC y
JDBC se han extendido para recuperar y almacenar tipos estructurados; por
ejemplo, JDBC ofrece el método getObject() que devuelve un objeto Java Struct,
a partir del cual se pueden extraer los componentes del tipo estructurado.
También es posible asociar clases de Java con tipos estructurados de SQL, y
JDCB puede realizar conversiones entre los tipos.
La orientación a objetos constituye una nueva forma de
pensar acerca de problemas empleando modelos que se han organizado tomando como
base conceptos del mundo real.
Los modelos orientados a objetos son útiles para
comprender problemas, comunicarse con expertos en esa aplicación, modelar
empresas, preparar documentación y diseñar programas y bases de datos.
El beneficio principal no es un tiempo de desarrollo
más reducido, el desarrollo orientado a objetos puede requerir más tiempo que
el desarrollo convencional porque se pretende que promueva la reutilización
futura y la reducción de los posteriores errores y el futuro mantenimiento.
Las bases de datos orientadas a objetos unen dos
tecnologías:
La de las bases de datos y la de los lenguajes
orientados a objetos. Los LPOO aportan gran capacidad en la manipulación de
datos, pero no implementan el almacenamiento y consulta de grandes volúmenes de
datos.
Por el contrario, las bases de datos convencionales
aportan un dominio de las técnicas de almacenamiento y consulta de grandes
volúmenes de datos, aunque su capacidad de manipulación es limitada.
Las bases de datos orientadas a objetos pretenden unir
la capacidad de manipulación de datos de los LPOO con la capacidad de
almacenamiento y consulta de los SGBD.
Desventajas de la BDOO
La inmadurez del mercado de BDOO constituye una posible fuente de problemas por lo que debe analizarse con detalle la presencia en el mercado del proveedor para adoptar una línea de producción sustantiva.
No hay comentarios:
Publicar un comentario