scs.kpi.uascs.kpi.ua/sites/default/files/pryklad._yanechko_andriy_… · web...
TRANSCRIPT
Міністерство освіти і науки УкраїниНаціональний технічний університет України
“Київський політехнічний інститут ім. Ігоря Сікорського”
Факультет прикладної математикиКафедра спеціалізованих комп’ютерних систем
Лабораторна робота № 3з дисципліни «Бази даних і засоби управління»
«Ознайомлення з базовими операціями СУБД PostgreSQL»
Виконав:студент групи КВ-71 Янечко Андрій Сергійович
Перевірив:___________________________________________________
Завдання
Завдання роботи полягає у наступному:1.Перетворити модуль “Модель” з шаблону MVC лабораторної роботи №2
у вигляд об’єктно-реляційної проекції (ORM).2.Створити та проаналізувати різні типи індексів у PostgreSQL.3.Розробити тригер бази даних PostgreSQL.4.Навести приклади та проаналізувати рівні ізоляції транзакцій
уPostgreSQL.Порядок виконання роботи
В ході роботи розроблено:1. Логічну модель БД та Діаграму класів;2. Функціонал програмного додатку;3. ОО програмний додаток роботи з БД " … ". Для взаємодії з БД
використано ORM модуль SQLAlchemy.
Логічна модель бази даних наведена на Рисунок 1
Рисунок 1 - Логічна модель бази даних
Сутнісні класи програми наведені на Рисунок 2
Рисунок 2 – Фрагмент UML діаграми сутнісних класів
Зв’язки між сутнісними класами, сгенеровані за допомогою SqlAlchemy, наведені на Рисунок 3
Рисунок 3 - Зв’язки між сутнісними класами
Примітка. Наведена вище діаграма класів не повністю відповідає стандарту. Для прикладу нижче наводиться діаграма класів додатку "Автопарк", яка побудована за допомогою додатку Enterprise Architect. Однак остаточний вигляд цієї діаграми залишається на вибір автора звіту з ЛР №3.
Рисунок 4 – – Логічна модель БД "Автопарк"
а) - Зв'язуюча таблиця БД без властивостей
б) - Зв'язуюча таблиця БД з властивостямиРисунок 5 – Діаграма класів-сутностей ІС "Автопарк"
Меню програми наведене на Рисунок 4
Рисунок 4 - Меню програми
Навігатор по коду програми наведено нижче:1. Controller
1.1. Функція початкового меню;1.2. Функція меню таблиці;
2. Model2.1. Функція, яка повертає назви усіх таблиць в БД;2.2. Функція, яка повертає об’єкт конкретної таблиці в БД;2.3. Фнукція SELECT ALL;2.4. Функція SELECT;2.5. Функція для заповнення об’єкта з БД;2.6. Фнукція INSERT;2.7. Функція UPDATE;2.8. Функція DELETE;2.9 Функція для коміта транзакції;
3. View3.1. Функція, для отримання об’єктів від користувача;3.2. Функція, для отримування значення від користувача;
3.3. Функція, для друкування головного меню;3.4 Функція, для друкування меню таблиці;
4. BaseDao4.1. Функція, для формування динамічного WHERE; 4.2. Функція, для формування динамічного UPDATE;4.3. Функція SELECT ALL;4.4. Функція SELECT;4.5. Функція DELETE;4.6. Функція UPDATE;4.7. Функція INSERT;
5. Data ba seHelper 5.1. Реалізація паттерну SINGLETONE для об’єкту який дає доступ до БД; 5.2. Функція, яка створює об’єкт типу engine ; 5.3. Функція, яка створює сесію;5.4. Функція, яка повертає інспектор;5.5. Функція, яка повертає назву всіх таблиць в БД;5.6. Фнукція, яка повертає назви колонок в таблиці;5.7. Фнукція, яка повертає список первинних ключів;5.8. Функція, яка повертає список зовнішніх ключів;5.9. Функція, яка комітить поточну сесію;
6. Utils6.1. Функція для повернення об’єкта з інпуту користувача;6.2. Функція, яка повертає значення типу Boolean для PostgreSQL;
7. Launcher8. Models
8.1. Reader;8.2. Subscription;8.3. Phone;8.4. Book;8.5. Author;8.6. Bookshelf;8.7. Archive;
9. Credentials
Код програми
BaseDao.pyfrom database_helper import DatabaseHelperfrom sqlalchemy.orm.exc import NoResultFound
class BaseDao(object):
def __init__(self, model): self.database = DatabaseHelper() self.model = model
def __get_filters(self, query, columns, values): if not isinstance(columns, list) and not isinstance(values, list): # single params, such as Book.table_name, 'Kotlin Coroutines' return query.filter(columns == values) else: if isinstance(columns, list) and isinstance(values, list): # having list of params and values if columns.__len__() != values.__len__(): print("Aborting! Columns and values have different size, WTF?!") return None index = 0 for column in columns: query = query.filter(column == values[index]) index += 1 return query else: print("Aborting! Columns and values have different types, WTF?!") return None
def __get_update_query(self, query, columns, values): if not isinstance(columns, list) and not isinstance(values, list): # single params, such as Book.table_name, 'Kotlin Coroutines' return query.update({columns: values}) else: if isinstance(columns, list) and isinstance(values, list): # having list of params and values if columns.__len__() != values.__len__(): print("Aborting! Columns and values have different size, WTF?!") return None index = 0 obj = {} for column in columns: obj[column] = values[index] index += 1 query = query.update(obj) return query else: print("Aborting! Columns and values have different types, WTF?!") return None
def select_all(self): session = self.database.get_session() result = session.query(self.model).all() return result
def select(self, columns, values): session = self.database.get_session() query = session.query(self.model) return self.__get_filters(query, columns, values).all()
def delete(self, columns, values): session = self.database.get_session() result = self.select(columns, values)
if result is None: print("Aborting! result is None, WTF?!")
if isinstance(result, list): # we have list of objects for obj in result: try: session.delete(obj) session.commit() print("Deleted - SUCCESSFUL") except NoResultFound: session.rollback() print("Object NOT FOUND, WTF?!")
else: # we have only one object try: session.delete(result) # session.commit() print("Deleted - SUCCESSFUL") except NoResultFound: session.rollback() print("Object NOT FOUND, WTF?!")
def update(self, columnsFind, valuesFind, columnsNew, valuesNew): session = self.database.get_session() query = session.query(self.model) query = self.__get_filters(query, columnsFind, valuesFind)
if query is None: print("Aborting! query is None, WTF?!")
query = self.__get_update_query(query, columnsNew, valuesNew)
if query is None: print("Aborting! query is None, WTF?!")
# session.commit() print("Updated - SUCCESSFUL")
def insert(self, obj): session = self.database.get_session() try: session.add(obj) # session.commit() except BaseException as exception: session.rollback() print(exception)
Controller.pyclass Controller(object):
def __init__(self, view, model): self.view = view self.model = model
def start(self): tables_names = self.model.getTablesNames() length = int(len(tables_names)) self.view.print_main_menu(tables_names) input_number = self.view.request_input() try: num = int(input_number) - 1 if num > length + 1 or num < 0: print("Wrong choice, make another...")
print() self.start() else: if num == length: return self.show_table_menu(tables_names[num]) except TypeError as error: print("Wrong choice, make another...") print() self.start()
…
Credentials.py#private datahost = "localhost"port = "5432"database = "postgres"user = "postgres"password = ""db_name="postgres"
DatabaseHelper.pyfrom models import *import sqlalchemy as dbimport credentials as credentialsfrom sqlalchemy.orm import *from sqlalchemy import inspectfrom sqlalchemy import Boolean, BOOLEANfrom sqlalchemy.exc import NoInspectionAvailableimport utils
class DatabaseHelper(object): # params __session = None __engine = None
…Launcher.py
from database_helper import DatabaseHelperfrom controller import Controllerfrom view import Viewfrom model import Modelimport class_generator
def main(): if is_need_generate(): class_generator.generate_classes()
controller = Controller(View(), Model()) controller.start() DatabaseHelper.close()
…Model.py
from base_dao import BaseDaofrom database_helper import DatabaseHelperimport utils
class Model(object):
def getTablesNames(self): return DatabaseHelper.getListOfTables()
def getTableObject(self, table_name): return DatabaseHelper.getTableObject(table_name)
…Utils.py
def map_keys_and_values_from_obect(obj): if not isinstance(obj, object): print("Aborting! U pass not objects, WTF?!") return None
columns = [] values = []
…View.py
import pandas as pd
class View(object):
def request_input(self): print("It's time to make your choice: ") return input()
…
Models.pyfrom sqlalchemy import Column, Integer, String, Date, Boolean, ForeignKeyfrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import relationship
Base = declarative_base()
class Reader(Base): __tablename__ = "Reader"
r_id = Column("r_id", Integer, primary_key=True) r_name = Column("r_name", String) r_visit_count = Column("r_visit_count", Integer) s_id = Column("s_id", Integer, ForeignKey('Subscription.s_id'))
subscription = relationship("Subscription", backref="reader") phones = relationship("Phone", backref="reader")
def __str__(self): return "r_id={id}, r_name={name}, r_visit_count={visit_count}, s_id={subs_id}" \ "\n\tsubcription={subs}" \ "\n\tphones={phs}".format(id=self.r_id, name=self.r_name, visit_count=self.r_visit_count, subs_id={self.s_id}, subs={str(self.subscription)}, phs={str(self.phones)})
ТригерТригер, який у разі якщо при додаванні запису в таблицю test_table рядка
зі значенням атрибута m_test, який містить слово test, додає до всіх інших записів ‘1’. Також, якщо це значення не містить слово test, то такий запис не вставляється в таблицю.
Тригер:
Дослідження рівнів ізоляціїДослід проводився з двома паралельними запитами UPDATE на один і
той самий об’єкт (запис):
1. READ COMMITTED
Клієнт, який почав операцію UPDATE пізніше чекав, поки інший клієнт закомітить транзакцію.
2. SEREALIZABLE та REPEATABLE READ