Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 14

FACULTAD DE INGENIERÍA

CARRERA DE INGENIERÍA DE SISTEMAS E INFORMATICA

Tarea Académica 2:
Clases persistentes con base de datos. Python, C# y Scala

AUTORES
 Gonzales Salas Nazly
 Salazar de Paz Massimo

Docente

Curso:
Programación Orientada a Objetos

Ciudad de Lima - Perú


2022

1
ÍNDICE

I. INTRODUCCIÓN
II. DESARROLLO
a. Clases persistentes con base de datos
b. Clases persistentes con base de datos en Python
c. Clases persistentes con base de datos en C#
d. Clases persistentes con base de datos en Scala
III. CONCLUSIONES
IV. REFERENCIA

2
I. INTRODUCCIÓN

Persistencia de datos, es la capacidad de guardar información de un programa para volver


a utilizarla en otro momento; en programación, significa involucrar un proceso de
serialización de los datos a un archivo o a una base de datos o a algún otro medio similar,
y el proceso inverso de recuperar los datos a partir de la información serializada.
Las Clases persistentes, no es precisamente una clase, sino que los objetos son
instanciados de tal forma que la información sea almacenada y no se pierda. La
persistencia, es la propiedad que tiene un objeto de permanecer en el tiempo; la
información del objeto se almacena de forma permanente para luego recuperarse y
reutilizarse. La persistencia en la programación orientada a objetos, es un mecanismo
usado con la finalidad de hacer persistir la información en el tiempo. La persistencia de
objetos puede clasificarse en objetos transitorios y objetos persistentes. Los objetos
transitorios, son aquellos datos u objetos que tiene la capacidad de almacenarse en
memoria y seguir existiendo tras varias operaciones; sin embargo, cuando se cierra el
programa esta información almacenada en memoria se pierde. Usualmente, esos casos
son los definidos en arreglos o vectores, en los que se almacenaran los datos y se podrá
interactuar con estos mientras este activo el programa en memoria. Los objetos
persistentes, son los datos u objetos que se almacenan en un medio secundario para su
posterior uso, su tiempo de vida es independiente del proceso que lo originó.
Generalmente son los almacenados en una base de datos mediante un valor de clave
primaria que servirá para su posterior recuperación. La mayoría de las aplicaciones de
software que se desarrollan en el mundo requieren del almacenamiento y gestión de
grandes volúmenes de información. Con el auge del paradigma de la orientación a objetos,
este proceso ha tomado nuevas dimensiones porque la persistencia es de objetos no solo
de datos. En este trabajo se sistematizan los pasos para el diseño de la base de datos, a
partir del análisis de un problema utilizando este enfoque. Se incluyen recomendaciones
que permiten obtener el comportamiento estático y dinámico de los objetos; así como el
procedimiento a seguir para interpretar toda la información, representada visual y
textualmente, en función de este diseño. Se propone una estructura de una capa
persistente de clases que incluye dos subcapas que responden al modelo de persistencia
propuesto y que aíslan a las clases del dominio de la forma en que se almacenan y
recuperan los objetos.

3
II. DESARROLLO
a) Clases persistentes con base de datos
Implementar un constructor sin argumentos, todas las clases persistentes deben tener un
constructor predeterminado (el cual puede ser no-público) de modo que pueda
instanciarlas usando Constructor.newInstance().
Proporcionar una propiedad identificadora o id, que relaciona la llave principal con la tabla
de la base de datos. Esta propiedad mapea a la columna de la llave principal de la tabla de
la base de datos. La propiedad podría llamarse de cualquier manera y su tipo podría haber
sido cualquier tipo primitivo, java.lang.String o java.util.Date. Si su tabla de
base de datos heredada tiene claves compuestas, puede utilizar una clase definida por el
usuario con propiedades de estos tipos. Declarar métodos de acceso y de modificación
para los campos persistentes, se puede implementar interfaces donde se declaren
métodos públicos; así mismo, se pueden declarar métodos de acceso y de modificación,
métodos getter y setter. Se puede implementar herencia, equals() y hascode(); garantiza la
equivalencia de identidad persistente y de identidad Java, dentro del ámbito de una sesión
en particular de modo que en el momento en que mezcla instancias recuperadas en
sesiones diferentes, tiene que implementar equals() y hashCode()
Soporta modelos dinámicos, usando mapeos en tiempo de ejecución; las entidades
persistentes no necesariamente tienen que estar representadas como clases POJO o
como objetos JavaBean en tiempo de ejecución. Soporta modelos dinámicos (utilizando
mapeos tiempo de ejecución). Una de las ventajas principales de un mapeo dinámico es el
rápido tiempo de entrega del prototipado sin la necesidad de implementar clases de
entidad, el esquema de base de datos se puede normalizar y volver sólido, permitiendo
añadir una implementación apropiada del modelo de dominio más adelante.

b) Clases persistentes con base de datos en Python


El uso de clases persistentes en Python tiene dos aspectos: la conversión de los datos
entre el objeto en la memoria y el formato de almacenamiento, y trabajar con el
almacenamiento de los datos convertidos. La biblioteca estándar incluye una variedad de
módulos que manejan ambos aspectos en diferentes situaciones. Cuando queremos
realizar la tarea de almacenar información y luego recuperarla para un uso posterior,
hacemos uso de la persistencia cuya acción es la de conservar la información de un objeto
de forma permanente; para esto existe algo conocido como serialización de objetos. La
serialización de un objeto consiste en generar una secuencia de bytes
para su almacenamiento. Esto es posible hacerlo en Python con las librerías Pickle y
Shelve. Es más común usar pickle para persistencia, ya que está integrado con algunos
módulos de biblioteca estándar que almacenan datos serializados. Un simple archivo plano
con objetos serializados escritos uno después del otro funciona para datos que no
necesitan ser indexados; Python incluye una colección de módulos para almacenar pares
clave-valor en una base de datos simple utilizando una de las variantes de formato de DBM
cuando se necesita una búsqueda indexada, La forma más directa de aprovechar el
formato de DBM es shelve. Shelve, abre el archivo y accede a él a través de una interfaz
tipo diccionario. Los objetos guardados en la base de datos son conservados
automáticamente y guardados sin ningún trabajo adicional. Esta librería permite almacenar
objetos como un diccionario. Es muy útil cuando queremos guardar muchos objetos y
posteriormente acceder solo a algunos de ellos. Shelve es un módulo de Python que se
utiliza para almacenar objetos en un archivo. El módulo de almacenamiento implementa el
almacenamiento persistente para objetos Python arbitrarios que pueden ser eliminados,
utilizando una API similar a un diccionario. El módulo de almacenamiento puede usarse
como una opción de almacenamiento persistente simple para objetos de Python
cuando una base de datos relacional es excesiva. Se accede a la estantería mediante
llaves, igual que con un diccionario. Los valores se eliminan y se escriben en una base de
datos creada y administrada por anydbm.

4
Debido, a que el módulo shelve está respaldado por pickle , es inseguro para cargar un
estante de una fuente no fiable. Al igual que con Pickle, cargar un estante puede ejecutar
código arbitrario. Una desventaja de shelve, es que cuando se utiliza el valor interfaz por
defecto no hay manera de predecir qué formato DBM se utilizará, ya que selecciona uno
basado en las bibliotecas disponibles en el sistema donde se crea la base de datos. El
formato no importa si la aplicación no necesitará compartir los archivos de la base de datos
entre hosts con diferentes bibliotecas, pero si la portabilidad es un requisito, usa una de las
clases en el módulo para asegurar que se seleccione un formato específico. Sin embargo,
json es otra librería y se usa con más frecuencia para aplicaciones Web, ya que se integra
mejor con herramientas existentes de almacenamiento de servicios web. Para las
aplicaciones web que ya trabajan con datos en JSON, utilizar json y dbm proporciona otro
mecanismo de persistencia. Usar dbm directamente es un poco más de trabajo que shelve
porque las claves y los valores de la base de datos deben ser cadenas, y los objetos no se
volverán a crear automáticamente cuando el valor sea accedido en la base de datos.

Restricciones

La elección del paquete de base de datos que se utilizará (como dbm.ndbm o dbm.gnu)
depende de la interfaz disponible. Por lo tanto, no es seguro abrir la base de datos
directamente usando dbm. La base de datos también está sujeta a las limitaciones de dbm,
si esto se usa, significa que los objetos almacenados en la base de datos deberían ser
bastante pequeños, y en casos raros, las colisiones de claves pueden hacer que la base
de datos rechace actualizaciones. El módulo de archivado no admite el acceso simultáneo
de lectura / escritura a objetos archivados. (Múltiples accesos de lectura simultáneos son
seguros.) Cuando un programa tiene un estante abierto para escribir, ningún otro programa
debería tenerlo abierto para leer o escribir. El bloqueo de archivos de Unix se puede usar
para resolver esto, pero esto difiere entre las versiones de Unix y requiere conocimiento
sobre la implementación de la base de datos utilizada

Ejercicios en Python

Ejemplos usando la librería shelve

Ejem 1.1 import


shelve

d = {'var1':'desperados'} d2
= {'var2':'coronita'}
# Escribimos los datos asociandoles una llave
with shelve.open('file.data', 'c') as shelf:
shelf["uno"] = d
shelf["dos"] = d1
# Leemos los datos y los mostramos with
shelve.open('file.data', 'r') as shelf: for
key in shelf.keys():
print(repr(shelf[key])))

5
Ejem 1.2 import
shelve

d = shelve.open(filename) # open - el archivo puede tener el sufijo agregado por bajo nivel
# library

d[key] = data # almacenar datos en la tecla (sobrescribe los datos antiguos si


# usando una clave existente)
data = d[key] # recuperar una COPIA de datos en la clave (generar KeyError
# si no hay tal clave)
del d[key] # eliminar los datos almacenados en la tecla (genera KeyError
# si no hay tal clave)

flag = key in d # verdadero si la clave existe


klist = list(d.keys()) # una lista de todas las claves existentes (¡lento!)

# como d se abrió SIN reescritura = Verdadero, tenga cuidado: d['xx']


= [0, 1, 2] # esto funciona como se esperaba, pero ...
d['xx'].append(3) # * ¡esto no! * - d ['xx'] es TODAVÍA [0, 1, 2]!

# habiendo abierto d sin writeback = True, necesita codificar con cuidado:


temp = d['xx'] # extrae la copia
temp.append(5) # muta la copia d['xx'] =
temp # almacena la copia de nuevo, para
conservarla

# o, d = shelve.open (nombre de archivo, writeback = True) solo le permitiría codificar


# d ['xx']. append (5) y haga que funcione como se espera, PERO también # consume
más memoria y hace que la operación d.close () sea más lenta.

d.close() # cierralo

Ejem 1.3 import

shelve

T='Hiya' val= [1,2,3]

filename='/tmp/shelve.out'
my_shelf = shelve.open(filename,'n') # 'n' for new

for key in dir():


try:
my_shelf[key] = globals() [key]
except TypeError:
#
# __builtins__, my_shelf, and imported modules can not be shelved.
#

6
print('ERROR shelving: {0}'.format(key)) my_shelf.close()

Para restaurar:

my_shelf = shelve. open(filename) for


key in my_shelf: globals ()
[key]=my_shelf[key] my_shelf. close
()

print(T) # Hiya print(val) # [1, 2, 3] Ejercicio usando la librería

cPickle /
pickle
Ejem 2.1
import
cPickle
as pickle
#o
import
pickle
d = {'var1':'desperados','var2':'coronita'}
# Abrimos el archivo donde almacenaremos el
# resultado de la serialización
with open('file.data', 'w') as f:
# Almacenamos el diccionario en el fichero con
dump() pickle.dump(d, f) f.close()
# Con load leemos el contenido almacenado
en el # archivo donde almacenamos la
información. with pickle.load(open('file.data',
'r')) as spd: print spd

Ejem 2.2

import pickle

class Persona: def __init__(self,


nombre, genero, edad):
self.nombre = nombre
self.genero = genero
self.edad = edad
print("Se ha creado una persona nueva con el nombre de", self.nombre)

def __str__(self):
return "{} {} {}".format(self.nombre, self.genero, self.edad)

class ListaPersonas:
personas = []

7
def __init__(self):
fichero = open ("lista_de_personas", "ab+”)
fichero.seek(0) # Desplazamos cursor al principio

try:

self. personas = pickle. load(fichero) # Cargamos


información print ("Se cargaron {} personas.”. format (len
(self. personas))) except EOFError: print ("El fichero
está vacío.") # Para la primera vez que abrimos finally:

fichero. close
() del fichero

def agregar_personas (self, persona):


self. personas. append(persona)
self.guardar_personas()

def mostrar_personas(self):
for persona in self. personas:
print(persona.__str__())

def guardar_personas(self):
fichero = open("lista_de_personas", "wb")
pickle.dump(self.personas, fichero)
fichero.close()
del fichero

def mostrar_informacion(self):
print("La información del fichero externo es la
siguiente:") for persona in self.personas:
print(persona.__str__())

Ejem 2.3

import pickle

def guardar_puntajes(nombre_archivo, puntajes):


""" Guarda la lista de puntajes en el archivo. Pre:
nombre_archivo corresponde a un archivo válido,
puntajes corresponde a los valores a guardar Post: se
guardaron los valores en el archivo en formato pickle.
"""

archivo = open(nombre_archivo, "w")


pickle.dump(puntajes, archivo)
archivo.close()

def recuperar_puntajes(nombre_archivo):

8
""" Recupera los puntajes a partir del archivo provisto.
Devuelve una lista con los valores de los puntajes.

Pre: el archivo contiene los puntajes en formato


pickle Post: la lista devuelta contiene los puntajes
en el mismo formato que se los almacenó.
"""

archivo = open(nombre_archivo, "r")


puntajes = pickle.load(archivo)
archivo.close()
return puntajes

-CLASES PERSISTENTES CON BASE DE DATOS EN PYTHON

Lo primero que debemos hacer es crear una conexión a la base de datos utilizando el método de
conexión. Después de eso, se necesitará un cursor que operará con esa conexión.

Se utiliza el método de ejecución del cursor para interactuar con la base de datos y, de vez en
cuando, confirme los cambios utilizando el método de confirmación del objeto de conexión.

Una vez hecho todo, se cierra el cursor y la conexión.

Ejemplo de clase Dbconnect:

import MySQLdb class

Dbconnect(object):

def __init__(self):

self.dbconection = MySQLdb.connect(host='host_example',
port=int('port_example'),
user='user_example',
passwd='pass_example',
db='schema_example') self.dbcursor = self.dbconection.cursor()

def commit_db(self):
self.dbconection.commit()

def close_db(self):
self.dbcursor.close()
self.dbconection.close()
Interactuar con la base de datos es simple. Después de crear el objeto, simplemente use el
método de ejecución.

9
db = Dbconnect() db.dbcursor.execute('SELECT * FROM %s' %
'table_example')

Para llamar a un procedimiento almacenado, use la siguiente sintaxis:

db = Dbconnect() db.callproc('stored_procedure_name',
[parameters] )

Una vez que se realiza la consulta, puede acceder a los resultados de varias maneras. El objeto del
cursor es un generador que puede obtener todos los resultados o ser enlazado.

results = db.dbcursor.fetchall() for


individual_row in results:
first_field = individual_row[0]

Para confirmar los cambios en la base de datos:

db. commit_db ()

Si quieres cerrar el cursor y la conexión:

db.close_db()

10
c) Clases persistentes con base de datos en C#

Es un lenguaje de programación identificado como el más humano, debido a que puede


entender un ordenador. Su nombre viene de evolucionar un lenguaje anterior “Lenguaje de
programación C”, que se creó en los Laboratorios Bell, desarrollado originariamente por
Dennis Ritchie, entre 1969 y 1972. Su característica principal es la eficiencia del código, y
es empleado para crear sistemas operativos, aplicaciones e incluso juegos.
Las clases en C# se definen de forma parecida a los registros (struct), sólo que ahora,
además de variables (que representan sus detalles internos, y que llamaremos sus
"atributos"), también incluirán funciones que son las acciones que puede realizar ese
objeto, que son identificadas como métodos. Atributos y métodos formarán parte de "un
todo", en vez de estar separados en distintas partes del programa. Esto es lo que se
conoce como "Encapsulación".

11
Clase Persistente. Una clase persistente en C# abarca las mismas funciones que
en Python solo tomando el detalle de que se implementaría los atributos,
declaración de los get y set y finalmente implementación del constructor en dicha
clase. Además, se debe tomar en cuenta que estas clases en este lenguaje de
programación viene a aplicar las cuatro reglas esenciales ya mencionadas
anteriormente:

- Implementación de un constructor sin argumentos, esto en base de ser un


constructor predeterminado en cual puede ser no público.
- Una propiedad identificadora o en otras palabras un id, esto vendría a ser
opcional, aunque no afecte las clases.
- Clases no finales, aunque estas van a depender mucho de la declaración de
los métodos públicos, también vendría a ser opcional.
- Declaración de métodos, también vendría a ser opcional.

Ventajas y Desventajas al aplicar una Clase Persistente en C#. Una de las


ventajas que podemos obtener en estas clases son; Declaraciones en el espacio de
nombres, Atributos, son miembro de una clase tiene un atributo de acceso del tipo
público, protegido, interno, interno protegido y privado. Inicializador, un inicializador
es como una propiedad, con la diferencia de que, en lugar de un nombre de
propiedad, un valor de índice entre corchetes se utiliza en forma anónima para
hacer referencia al miembro de una clase. Por otra parte, la desventaja que se
presentan es; los atributos son privados mayormente, en las cual para poder ser
invocados por otra clase tendrán que ser inicializados posteriormente.

El operador new (palabra clave C#) proporciona espacio de almacenamiento persistente,


similar pero superior a la función de Librería Estándar malloc. Este operador permite crear
un objeto de cualquier tipo, incluyendo tipos definidos por el usuario, y devuelve un puntero
(del tipo adecuado) al objeto creado. Su utilización exige que el usuario declarare un
puntero del tipo adecuado; a continuación, debe ser inicializado con el valor devuelto por el
operador. Si el objeto creado es tipo T, sería algo así:

T* puntero = valor-devuelto-por-el-operador;

Los objetos creados con new son persistentes, es decir, la vida del nuevo objeto es desde
el punto de creación hasta el final del programa o hasta que el programador lo destruya
explícitamente con el operador delete. Este último desasigna la zona de memoria ocupada
por el objeto, de forma que queda disponible para nuevo uso. Las sucesivas invocaciones
de este operador van reservando zonas de memoria en el montón para los objetos
sucesivamente creados. El gestor de memoria del compilador se encarga de mantener una
tabla con los sitios ocupados y libres sin que haya conflictos hasta que la memoria se ha
agota, o no existe espacio contiguo suficiente para el nuevo objeto. En cuyo caso se lanza
una excepción como indicativo del error.

Peligros La persistencia de los objetos creados con new y su independencia del ámbito
desde el que han sido creados, es muy importante y de tener en cuenta, pues suele ser

12
motivo de pérdidas de memoria en el programa si olvidamos destruirlos cuando ya no son
necesarios. Hay que prestar especial atención, porque en una sentencia como:

voidfunc() {
...
tipoX* Xptr = new tipoX;
...
}

el área de almacenamiento señalada por el puntero es persistente, pero Xptr que es una
variable local automática no lo es. Si olvidamos destruir el objeto creado (con delete) antes
de salir del ámbito, el área de almacenamiento permanecerá ocupando espacio en el
montón y no podrá ser recuperada nunca, pues el puntero Xptr habrá desaparecido. La
cuestión de pérdida de memoria no es solo cuestión de que el programador "recuerde"
utilizar delete antes de salir del ámbito del puntero. También puede producirse por otras
circunstancias. Por ejemplo, el mecanismo de lanzamiento y captura de excepciones C++
puede funcionar como un salto, goto o break multinivel, que saque abruptamente de
ámbito al puntero con la consiguiente pérdida irreparable. La situación puede ser
esquematiza como sigue (la figura adjunta muestra el estado de la pila y el alcance del
desmontaje -"Stack unwinding"- caso de producirse un error).
fun1() { try {
fun2(); }
catch (...) {
...
} }
fun2() {
A* aptr = new A; // crear objeto
foo();
...
delete aptr; // Ok. destruir el objeto }
// antes de salir de ámbito foo() { ...
if (x) throw "Error";
...
}

La situación anterior es de gran peligro potencial. Si se produce la condición x, y se lanza


la excepción en foo, la pila será desmontada hasta el punto de la sentencia catch en fun1
que recibirá el control. La secuencia de ejecución no pasará nunca por el delete de fun2,
con lo que el espacio del objeto A se perderá irremediablemente. Conscientes del
deficiente maridaje entre el operador new y el sistema C++ de excepciones, los
diseñadores de la Librería Estándar, han incluido en esta un puntero "inteligente" auto_ptr,
que resuelve este tipo de problemas.

Ventajas:

La persistencia permite al programador el almacenar, transferir y recuperar el estado de los


objetos.

Desventajas:

13
La persistencia es muy difícil de implementar puesto que es muy compleja ya que le exige
al programador el manejo de Puntero. Todo objeto creado de forma persistente debe de
ser destruido cuando ya no se lo necesita puesto que ocasiona pérdidas de memoria en el
programa si olvidamos destruirlos.
Ejemplo en C++:

#include<conio.h>
#include<iostream.h>
#include <vcl.h>
#pragma hdrstop #include <fstream.h> class persona { private:
String nombre; public:

III.

14

También podría gustarte