Python 是一種高級、通用的解釋型編程語言,以其優雅、準確、 簡單的語言特性,在雲計算、Web 開發、自動化運維、數據科學以及機器學習等人工智能領域獲得了廣泛應用。
Python 定義了連接和操作數據庫的標準接口 Python DB API。不同的數據庫在此基礎上實現了特定的驅動,這些驅動都實現了標準接口。
對於 PostgreSQL 數據庫,最常見的 Python 驅動程序就是 psycopg,它完全實現了 Python DB-API 2.0 接口規範。接下來我們介紹如何通過 psycopg 連接和操作 PostgreSQL 數據庫。
連接數據庫
首先,我們需要安裝 Python 和 psycopg 驅動。Python 可以通過官方網站下載,安裝之後可以通過以下命令查看版本信息:
PS C:\Users\dongx> python -V
Python 3.8.3
然後通過 pip 安裝最新的 psycopg:
PS C:\Users\dongx> pip install --upgrade psycopg2
Collecting psycopg2
Using cached psycopg2-2.8.5-cp38-cp38-win_amd64.whl (1.1 MB)
Installing collected packages: psycopg2
Successfully installed psycopg2-2.8.5
爲了方便開發,我們安裝一個 IDE(集成開發環境):JetBrains 出品的 Pycharm Community Edition。在 Pycharm 中新建一個項目 PythonPostgreSQL,然後創建一個數據庫連接的配置文件 dbconfig.ini,添加以下內容:
[postgresql]
host = 192.168.56.104
port = 5432
database = hrdb
user = tony
password = tony
配置文件中存儲了數據庫的連接信息:主機、端口、數據庫、用戶以及密碼;我們需要按照自己的環境進行配置。
然後,新建一個測試數據庫連接的 Python 文件 postgresql_connection.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 獲取 PostgreSQL 版本號
cur.execute('SELECT version()')
db_version = cur.fetchone()
# 輸出 PostgreSQL 版本
print("連接成功,PostgreSQL 服務器版本:", db_version)`在這裏插入代碼片`
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("連接 PostgreSQL 失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
print("PostgreSQL 數據庫連接已關閉。")
- 首先,我們導入了 psycopg2 驅動和解析配置文件的 configparser 模塊;
- 然後,創建一個讀取配置文件的 read_db_config 函數;
- 接下來調用 psycopg2.connect 函數創建一個新的數據庫連接;
- 然後通過連接對象的 cursor 函數創建一個新的遊標,並且執行查詢語句返回數據庫的版本;
- 在此之後,調用遊標對象的 fetchone() 方法獲取返回結果並打印信息;
- 最後,調用 close() 方法關閉遊標資源和數據庫連接對象。
執行以上腳本,返回的信息如下:
連接成功,PostgreSQL 服務器版本: ('PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit',)
PostgreSQL 數據庫連接已關閉。
創建和刪除表
建立數據庫連接之後,通過執行 CREATE TABLE 和 DROP TABLE 語句可以創建和刪除數據表。我們創建一個新的 Python 文件 postgresql_ddl.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ create table users (
id serial primary key,
name character varying(10) not null unique,
created_at timestamp not null
) """
# 執行 SQL 命令
cur.execute(sql)
# 關閉遊標
cur.close()
# 提交事務
connection.commit()
print("操作成功!")
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
print("PostgreSQL 數據庫連接已關閉。")
同樣是先連接數據庫;然後利用遊標對象的 execute() 方法執行 SQL 命令創建表;commit 方法用於提交事務修改,如果不執行該操作不會真正創建表,因爲 psycopg2 連接 PostgreSQL 默認不會自動提交(autocommit)。執行該腳本的結果如下:
操作成功!
PostgreSQL 數據庫連接已關閉。
如果 user 表已經存在,將會返回以下錯誤:
操作失敗: relation "users" already exists
我們可以將文件中的 sql 語句修改成“drop table users”,刪除 users 表並重建創建。
插入數據
PostgreSQL 使用 INSERT 語句插入數據;Python 中游標對象的 execute() 方法用於執行 SQL 語句,該方法可以接收參數實現預編譯語句。
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ insert into users(name, created_at)
values (%s, %s) RETURNING id
"""
# 執行 SQL 命令
cur.execute(sql, ('tony', '2020-06-08 11:00:00'))
# 獲取 id
id = cur.fetchone()[0]
# 提交事務
connection.commit()
print("操作成功! 用戶 id:", id)
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
print("PostgreSQL 數據庫連接已關閉。")
sql 變量中的百分號(%)是佔位符,這些佔位符的值在 execute() 方法中進行替換;遊標對象的 fetchone 方法用於返回一行結果,這裏用於獲取 RETURNING id 返回的用戶 id。執行以上腳本返回的結果如下:
操作成功! 用戶 id: 1
PostgreSQL 數據庫連接已關閉。
如果想要查看插入 users 表中的數據,可以執行查詢操作。
查詢數據
遊標對象提供了三種獲取返回結果的方法:fetchone() 獲取下一行數據,fetchmany(size=cursor.arraysize) 獲取下一組數據行,fetchall() 返回全部數據行。
我們創建一個新的文件 postgresql_query.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ select id, name, created_at
from users
"""
# 執行 SQL 命令
cur.execute(sql)
print("用戶數量:", cur.rowcount)
# 獲取結果
user = cur.fetchone()
while user is not None:
print(user)
user = cur.fetchone()
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
遊標對象的 rowcount 屬性代表了返回的數據行數,fetchone() 方法返回一行數據或者 None,while 循環用於遍歷和打印查詢結果。由於 users 表中目前只有一行數據,執行以上文件的結果如下:
用戶數量: 1
(1, 'tony', datetime.datetime(2020, 6, 8, 11, 0))
修改數據
修改數據的流程與插入數據相同,只是需要將 INSERT 語句替換成 UPDATE 語句。我們創建一個新的文件 postgresql_update.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ update users
set name = %s
where id = %s
"""
# 執行 SQL 命令
cur.execute(sql, ('tom', 1))
# 獲取 id
rows = cur.rowcount
# 提交事務
connection.commit()
print("操作成功! 更新行數:", rows)
# 再次查詢數據
sql = """ select id, name, created_at
from users where id = 1
"""
cur.execute(sql)
user = cur.fetchone()
print(user)
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
更新數據之後,再次執行了查詢語句,返回更新後的用戶信息。執行該文件的結果如下:
操作成功! 更新行數: 1
(1, 'tom', datetime.datetime(2020, 6, 8, 11, 0))
刪除數據
將 UPDATE 語句替換成 DELETE 語句,就可以刪除表中的數據。我們創建一個新的文件 postgresql_delete.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ delete from users where id = %s
"""
# 執行 SQL 命令
cur.execute(sql, (1,))
rows = cur.rowcount
# 提交事務
connection.commit()
print("操作成功! 刪除行數:", rows)
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
執行該文件,返回以下結果:
操作成功! 刪除行數:1
管理事務
在前面的示例中,需要使用 connection.commit() 提交對 PostgreSQL 數據庫執行的修改,這是因爲 psycopg2 默認沒有打開自動提交功能。我們也可以利用連接對象的 autocommit 屬性設置是否自動提交。
將上文中的 postgresql_insert.py 修改如下:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 psycopg2.connect 方法連接 PostgreSQL 數據庫
connection = psycopg2.connect(**db_config)
# 打印和設置自動提交
print('默認 autocommit:', connection.autocommit)
connection.autocommit = True
print('新的 autocommit:', connection.autocommit)
# 創建一個遊標
cur = connection.cursor()
# 定義 SQL 語句
sql = """ insert into users(name, created_at)
values (%s, %s) RETURNING id
"""
# 執行 SQL 命令
cur.execute(sql, ('tony', '2020-06-08 11:00:00'))
# 獲取 id
id = cur.fetchone()[0]
print("操作成功! 用戶 id:", id)
# 關閉遊標
cur.close()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
print("PostgreSQL 數據庫連接已關閉。")
通過 connection.autocommit 設置了自動提交,所以 INSERT 語句插入數據之後不需要再執行 commit 操作。
默認 autocommit: False
新的 autocommit: True
操作成功! 用戶 id: 2
PostgreSQL 數據庫連接已關閉。
如果一個事務中包含多個數據庫操作,還是應該在事務的最後統一執行提交,並且在異常處理部分通過連接對象的 rollback() 方法回滾部分完成的事務。
另一種管理事務的方法是使用 with 語句,這樣可以避免手動的資源管理和事務操作。我們創建一個新的文件 postgresql_transaction.py:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 with 語句管理事務
with psycopg2.connect(**db_config) as connection:
# 創建一個遊標
with connection.cursor() as cur:
# 插入數據
sql = """ insert into users(name, created_at)
values (%s, %s)
"""
cur.execute(sql, ('Jason', '2020-06-08 15:30:00'))
# 更新數據
sql = """ update users
set created_at = %s
where name = %s
"""
cur.execute(sql, ('2020-06-08 16:00:00', 'tony'))
sql = """ select id, name, created_at
from users
"""
# 查詢數據
cur.execute(sql)
# 獲取結果
user = cur.fetchone()
while user is not None:
print(user)
user = cur.fetchone()
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
整個事務包含插入數據、更新數據以及查詢數據三個操作。執行該腳本的結果如下:
(3, 'Jason', datetime.datetime(2020, 6, 8, 15, 30))
(2, 'tony', datetime.datetime(2020, 6, 8, 16, 0))
調用存儲函數
遊標對象的 callproc() 方法可以用於執行存儲函數。我們先創建一個返回用戶數量的函數 get_user_count:
CREATE OR REPLACE FUNCTION get_user_count()
returns int
AS $$
DECLARE
ln_count int;
BEGIN
select count(*) into ln_count
from users;
return ln_count;
END; $$
LANGUAGE plpgsql;
接下來創建一個新的文件 postgresql_func:
# 導入 psycopg2 模塊和 Error 對象
import psycopg2
from psycopg2 import DatabaseError
from configparser import ConfigParser
def read_db_config(filename='dbconfig.ini', section='postgresql'):
""" 讀取數據庫配置文件,返回一個字典對象
"""
# 創建解析器,讀取配置文件
parser = ConfigParser()
parser.read(filename)
# 獲取 postgresql 部分的配置
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('文件 {1} 中未找到 {0} 配置信息!'.format(section, filename))
return db
db_config = read_db_config()
connection = None
try:
# 使用 with 語句管理事務
with psycopg2.connect(**db_config) as connection:
# 創建一個遊標
with connection.cursor() as cur:
# 調用存儲函數
cur.callproc('get_user_count')
row = cur.fetchone()[0]
print('用戶總數:', row)
except (Exception, DatabaseError) as e:
print("操作失敗:", e)
finally:
# 釋放數據庫連接
if connection is not None:
connection.close()
callproc() 方法調用存儲函數也可以寫成以下等價的形式:
cur.execute('select * from get_user_count()')
執行以上腳本返回的結果如下:
用戶總數: 2
callproc() 方法不支持存儲過程,可以使用 execute() 方法調用 PostgreSQL 中的 CALL 命令執行存儲過程。更多關於[Psycopg 接口的使用和配置,可以參考 Psycopg 文檔。