Skip to content

17. SGBD ve PostgreSQL'in kullanımı

SGBD PostgreSQL ücretsiz olarak kullanılabilir. Bu, MySQL'in 'topluluk' sürümüne bir alternatiftir.

Burada, Python / MySQL komut dosyalarını Python / PostgreSQL komut dosyalarına taşımanın oldukça basit olduğunu göstermek için bu sürümü kullanıyoruz.

SGBD ve MySQL ile komut dosyalarımızın mimarisi şu şekildeydi:

SGBD ve PostgreSQL ile mimari şu şekilde olacaktır:

Image

17.1. SGBD ve PostgreSQL'in kurulumu

SGBD ve PostgreSQL sürümleri, URL ve [https://www.postgresql.org/download/] (Mayıs 2019) sürümlerinde mevcuttur. Burada 64 bit Windows sürümünün kurulumunu gösteriyoruz:

Image

Image

  • [1-4]'te, SGBD kurulum dosyasını indirin;

İndirilen yükleyiciyi çalıştırın:

Image

  • [6]'te bir kurulum klasörü belirtin;

Image

  • [8] adımında, [Stack Builder] seçeneği burada yapmak istediğimiz şey için gereksizdir;
  • [10]'te, size gösterilen değeri olduğu gibi bırakın;

Image

  • [12-13]'te, buraya [root] şifresini girdik. Bu, SGBD adlı [postgres]'in yönetici şifresi olacaktır. PostgreSQL'te buna süper kullanıcı da denir;
  • [15]'te varsayılan değeri bırakın: bu, SGBD'in dinleme portudur;

Image

  • [17]'te varsayılan değeri değiştirmeyin;
  • [19]'te, kurulum yapılandırmasının özeti;

Image

Image

Windows'ta, SGBD PostgreSQL, otomatik olarak başlatılan bir Windows hizmeti olarak kurulur. Çoğu zaman bu istenmeyen bir durumdur. Bu yapılandırmayı değiştireceğiz. Windows arama çubuğuna [services] yazın:

Image

  • [29]'te, SGBD PostgreSQL hizmetinin otomatik modda olduğu görülüyor. Bunu, [30] hizmetinin özelliklerine erişerek değiştiriyoruz:

Image

  • [31-32]'te, başlatma modunu manuel olarak ayarlayın;
  • [33]'te, hizmeti durdurun;

SGBD hizmetini manuel olarak başlatmak istediğinizde, [services] uygulamasına geri dönün, [postgresql] hizmetine sağ tıklayın (34) ve hizmeti başlatın (35).

17.2. PostgreSQL'i [pgAdmin] aracıyla yönetme

SGBD PostgreSQL Windows hizmetini başlatın (önceki paragraf). Ardından, [services] aracını başlattığınız şekilde, SGBD, PostgreSQL ve [1-3]'i yönetmenizi sağlayan [pgadmin] aracını başlatın:

Image

Belirli bir anda sizden süper kullanıcı şifresi istenebilir. Bu şifre [postgres]'tir. Bu şifreyi, SGBD kurulumunda belirlemiştiniz. Bu belgede, kurulum sırasında süper kullanıcıya [root] şifresini vermiştik.

  • [4]'te, [pgAdmin] bir web uygulamasıdır;
  • [5]'te, [pgAdmin] tarafından algılanan PostgreSQL sunucularının listesi, burada 1;
  • [6]'te, bizim başlattığımız PostgreSQL sunucusu;
  • [7]'te, SGBD'in veritabanları, burada 1;
  • [8]'te, [postgresql] veritabanı, [postgres] süper kullanıcısı tarafından yönetilir;

Öncelikle [admpersonnes] adlı bir kullanıcı ve [nobody] şifresini oluşturalım:

Image

Image

  • [17]'te ise [nobody] yazılmıştır;

Image

  • yerine [21] yazdık; SQL kodu, [pgAdmin] aracı tarafından SGBD ve PostgreSQL'e gönderilecek. Bu, PostgreSQL'e ait SQL dilini öğrenmenin bir yoludur;
  • [22]'te, [Save] sihirbazının onaylanmasının ardından [admpersonnes] kullanıcısı oluşturuldu;

Şimdi [dbpersonnes] veritabanını oluşturuyoruz:

Image

[23]'e sağ tıklayıp ardından [24-25]'e tıklayarak yeni bir veritabanı oluşturuyoruz. [26] sekmesinde, [27] veritabanının adını ve sahibi olarak [admpersonnes] [28]'i tanımlıyoruz.

Image

  • [30]'te, veritabanını oluşturma kodu SQL;
  • [31]'e, [Save] sihirbazının onaylanmasının ardından [dbpersonnes] veritabanı oluşturulur;

[dbpersonnes] veritabanını Python komut dosyalarıyla işleyeceğiz.

17.3. SGBD ve PostgreSQL Python bağlayıcısının kurulumu

Image

Yukarıdaki şemada, Python betikleri ile SGBD ve PostgreSQL arasında bağlantı kuran bir konektör gösterilmektedir. Bunların birkaç tanesi mevcuttur. [psycopg2] bağlayıcısını kuruyoruz. Bu işlem bir Python terminalinde gerçekleştirilir (terminalin hangi klasörde açık olduğu önemli değildir). Bağlayıcı, [pip install psycopg2] komutuyla kurulur:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\troiscouches\v01\tests>pip install psycopg2
Collecting psycopg2
  Downloading psycopg2-2.8.5-cp38-cp38-win_amd64.whl (1.1 MB)
     || 1.1 MB 3.2 MB/s
Installing collected packages: psycopg2
Successfully installed psycopg2-2.8.5

17.4. MySQL komut dosyalarının PostgreSQL komut dosyalarına taşınması

Image

  • [1] klasöründeki MySQL komut dosyaları kopyalanır (Ctrl-C / Ctrl-V), ardından dosya adları içeriklerine göre değiştirilir;

17.4.1. [pgres_module] modülü

Bu modül, [mysql_module] modülünün kopyasıdır (bkz. |[mysql-04] komut dosyası: SQL komut dosyasının çalıştırılması| bölümü). İçe aktarmalar şu şekilde değiştirilir:

Şunun yerine:


# içe aktarma
from mysql.connector import DatabaseError, InterfaceError
from mysql.connector.connection import MySQLConnection
from mysql.connector.cursor import MySQLCursor

şunu yazın:


# içe aktarmalar
from psycopg2 import DatabaseError, InterfaceError
from psycopg2.extensions import connection, cursor

[afficher_infos] işlevinin imzası şöyleydi:


def afficher_infos(curseur: MySQLCursor):

Şu hale geliyor:


def afficher_infos(curseur: cursor)

[execute_list_of_commands] işlevinin imzası şöyleydi:


def execute_list_of_commands(connexion: MySQLConnection, sql_commands: list,
                             suivi: bool = False, arrêt: bool = True, with_transaction: bool = True)

Şu hale gelir:


def execute_list_of_commands(connexion: connection, sql_commands: list,
                             suivi: bool = False, arrêt: bool = True, with_transaction: bool = True):

Bunun dışında başka bir değişiklik olmaz.

17.4.2. [pgres_01] komut dosyası

[pgres_01] komut dosyası, [mysql_01] komut dosyasının bir kopyasıdır (bkz. |[mysql-01] komut dosyası: MySQL veritabanına bağlantı - 1| paragrafı). Bu dosyada aşağıdaki değişiklikler yapılır:

Şunun yerine:


# mysql.connector modülünün içe aktarılması
from mysql.connector import connect, DatabaseError, InterfaceError

şunu yazın:


# psycopg2 modülünün içe aktarılması
from psycopg2 import connect, DatabaseError, InterfaceError

Geri kalan kısım değişmez. Sonuçlar, MySQL ile elde edilen sonuçlarla aynıdır.

17.4.3. [pgres_02] komut dosyası

[pgres_02] komut dosyası, [mysql_02] komut dosyasının bir kopyasıdır (bkz. |[mysql-02] komut dosyası: MySQL veritabanına bağlantı - 2| paragrafı). Burada aşağıdaki değişiklikler yapılır:

Şunun yerine:


# mysql.connector modülünün içe aktarılması
from mysql.connector import DatabaseError, InterfaceError, connect

şunu yazın:


# psycopg2 modülünün içe aktarılması
from psycopg2 import DatabaseError, InterfaceError, connect

Sonuçlar, [mysql_02] komut dosyasının sonuçlarıyla aynı değildir:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_02.py
Connexion MySQL réussie à la base database=dbpersonnes, host=localhost sous l'identité user=admpersonnes, passwd=nobody
Déconnexion MySQL réussie

Process finished with exit code 0

[pgres_02] komut dosyası şöyledir:


# mysql.connector modülünün içe aktarılması
from psycopg2 import DatabaseError, InterfaceError, connect


# ---------------------------------------------------------------------------------
def connexion(host: str, database: str, login: str, pwd: str):
    # [database] veritabanına bağlanır ve ardından bağlantıyı keser (kullanıcı adı, şifre) [host] sunucusundan
    # sorun olması durumunda DatabaseError istisnasını tetikler
    connexion = None
    try:
        # bağlantı
        connexion = connect(host=host, user=login, password=pwd, database=database)
        print(
            f"Connexion réussie à la base database={database}, host={host} sous l'identité user={login}, passwd={pwd}")
    finally:
        # Bağlantı açılmışsa kapatılır
        if connexion:
            connexion.close()
            print("Déconnexion réussie\n")


# ---------------------------------------------- ana
# bağlantı kimlik bilgileri
USER = "admpersonnes"
PASSWD = "nobody"
HOST = "localhost"
DATABASE = "dbpersonnes"

# mevcut bir kullanıcının oturumu
try:
    connexion(host=HOST, login=USER, pwd=PASSWD, database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # hata görüntülenir
    print(erreur)

# mevcut olmayan bir kullanıcıya ait oturum açma
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # hata mesajı görüntüleniyor
    print(erreur)

Oysa 36-41. satırlarda, SGBD'e bağlantının başarısız olduğunu belirten bir hata mesajı görüntülenmesi gerekirken, hiçbir şey görüntülenmiyor. Aslında konuyu derinlemesine incelediğimizde, 35-37. satırlarda [except]'e geçiş yapıldığı, ancak [erreur] değişkeninin değerinin [None] olduğu görülmektedir. Bu durum, [psycopg2] konektörünün 2.8.4 sürümünde görülmektedir.

Bu sorunu, daha genel ancak daha az kesin bir mesaj yazarak aşabiliriz:


# mevcut olmayan bir kullanıcı oturumu açılıyor
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # hata mesajı görüntüleniyor
    print(f"Erreur de connexion à la base [{DATABASE}] par l'utilisateur [xx/yy]")

Bu durumda sonuçlar şu şekildedir:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_02.py
Connexion réussie à la base database=dbpersonnes, host=localhost sous l'identité user=admpersonnes, passwd=nobody
Déconnexion réussie

Erreur de connexion à la base [dbpersonnes] par l'utilisateur [xx/yy]

Process finished with exit code 0

17.4.4. [pgres_03] komut dosyası

[pgres_03] komut dosyası, [mysql_03] komut dosyasının bir kopyasıdır (bkz. |[mysql-03] komut dosyası: MySQL tablosunun oluşturulması| bölümü). Bu dosyada aşağıdaki değişiklikler yapılır:

Şunun yerine:


from mysql.connector import DatabaseError, InterfaceError, connect
from mysql.connector.connection import MySQLConnection

şöyle yazılır:


from psycopg2 import DatabaseError, InterfaceError, connect
from psycopg2.extensions import connection

Ayrıca, [execute_sql] işlevinin imzası, eski haliyle:


def execute_sql(connexion: MySQLConnection, update: str):

şu şekilde değişir:


def execute_sql(connexion: connection, update: str):

Geri kalan kısımda değişiklik yok. Sonuç şu şekildedir:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_03.py
create table personnes (id int PRIMARY KEY, prenom varchar(30) NOT NULL, nom varchar(30) NOT NULL, age integer NOT NULL, unique(nom,prenom))  : requête réussie

Process finished with exit code 0

[personnes] tablosunun varlığını [pgAdmin] yönetim aracıyla kontrol edebiliriz:

Image

17.4.5. [pgres_04] komut dosyası

[pgres_04] komut dosyası, [mysql_04] komut dosyasının bir kopyasıdır (bkz. |[mysql-04] komut dosyası: SQL komut dosyasının çalıştırılması| bölümü). [pgres_module] modülünü kullanır:


# uygulama yapılandırması alınıyor
import config_04

config = config_04.configure()

# syspath yapılandırıldı - içe aktarmalar yapılabilir
import sys
from pgres_module import execute_file_of_commands
from psycopg2 import connect, DatabaseError, InterfaceError

Geri kalan kısım değişmez.

|script [mysql-04]: SQL komut dosyasının çalıştırılması| paragrafında yapıldığı gibi bir [pgres pgres-04 without_transaction] yapılandırması oluşturulur. Aynı şekilde bir [pgres pgres-04 with_transaction] yapılandırması da oluşturulur.

[pgres pgres-04 without_transaction] yapılandırmasının çalıştırılması aşağıdaki sonuçları verir:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_04.py false
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\postgresql/data/commandes.sql sans transaction
--------------------------------------------------------------------
[drop table if exists personnes] : Exécution réussie
nombre de lignes modifiées : -1
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : -1
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
[insert into personnes(id, prenom, nom, age) values (3, 'Pierre','Nicazou',35)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (4, 'Geraldine','Colou',26)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (5, 'Paulette','Girond',56)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
('Pierre', 'Nicazou', 35)
('Geraldine', 'Colou', 26)
('Paulette', 'Girond', 56)
*****************
[select nom,prenom from personnes order by nom asc, prenom desc] : Exécution réussie
nom, prenom,
************
('Colou', 'Geraldine')
('Girond', 'Paulette')
('Langevin', 'Paul')
('Lefur', 'Sylvie')
('Nicazou', 'Pierre')
************
[select nom,prenom,age from personnes where age between 20 and 40 order by age desc, nom asc, prenom asc] : Exécution réussie
nom, prenom, age,
*****************
('Nicazou', 'Pierre', 35)
('Colou', 'Geraldine', 26)
*****************
[insert into personnes(id, prenom, nom, age) values(6, 'Josette','Bruneau',46)] : Exécution réussie
nombre de lignes modifiées : 1
[update personnes set age=47 where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
('Bruneau', 'Josette', 47)
*****************
[delete from personnes where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
*****************
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)

Process finished with exit code 0
    1. satır: [personnes] tablosunu silme komutunda değişiklik yapılması gerekti. MySQL konektörünün aksine, PostgreSQL konektörü, silinecek tablo mevcut değilse bir istisna oluşturur. [drop table] komutunun, tablo mevcut değilse istisna oluşturmayan [drop table if exists] adlı bir varyantı vardır. Burada bunu kullandık. Bu, benzer durumlarda iki SGBD komutunun aynı şekilde davranmadığı bir örnektir;

[pgAdmin] aracındaki [personnes] tablosu şöyledir:

Image

[pgres pgres_04 with_transaction] yapılandırmasının çalıştırılması şu sonuçları verir:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_04.py true
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\postgresql/data/commandes.sql avec transaction
--------------------------------------------------------------------
[drop table if exists personnes] : Exécution réussie
nombre de lignes modifiées : -1
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : -1
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)

Process finished with exit code 0

[pgAdmin] aracındaki [personnes] tablosu şu şekildedir:

Image

Burada sonuç, MySQL ile elde edilen sonuçtan farklıdır. Komut dosyalarını aynı koşullarda, yani işlem olmadan komut dosyasını çalıştırdıktan sonra çalıştırırsak, şu sonuçlar elde edilir:

  • MySQL ile [personnes] tablosu boştur;
  • PostgreSQL ile [personnes] tablosu boş değildir;

Aradaki fark, bu iki SGBD komutunun işlemi geri alma yöntemlerindeki farklılıktan kaynaklanmaktadır:

  • MySQL, [drop table] ve [create table] emirlerini iptal etmez. Sonuç olarak [personnes] tablosu boş kalır;
  • PostgreSQL, [drop table] ve [create table] emirlerini geri alır. Tablo, işlem içeren komut dosyasının çalıştırılmasından önceki durumuna geri döner;

17.4.6. [pgres_05] komut dosyası

[pgres_05] komut dosyası, [mysql_05] komut dosyasının bir kopyasıdır (bkz. |[mysql-05] komut dosyası: parametreli sorguların kullanımı| bölümü). Komut dosyası şu şekilde değiştirilmiştir:

Şunun yerine:


# içe aktarmalar
from mysql.connector import connect, DatabaseError, InterfaceError

şöyle yazılır:


# içe aktarmalar
from psycopg2 import connect, DatabaseError, InterfaceError

Geri kalan kısım değişmez.

[pgAdmin]'te elde edilen sonuçlar şunlardır:

Image

17.5. Sonuç

MySQL komut dosyalarının PostgreSQL komut dosyalarına taşınması oldukça kolay gerçekleşti. Bu bir istisnadır. İki SGBD, SQL nesnelerinin (veritabanları, tablolar, sütunlar, kısıtlamalar, veri türleri…) aynı adlandırma kurallarını desteklemiyor ve uyumsuz SQL uzantılarına sahip… Kolay bir taşıma sağlamak için, her iki durumda da SQL standardına bağlı kalmak ve SGBD'in özel uzantılarını kullanmaya çalışmamak gerekir. Ancak bu, performansın düşmesine neden olur.