# Python PostgreSQL 教程

> 原文： [http://zetcode.com/python/psycopg2/](http://zetcode.com/python/psycopg2/)

带有`psycopg2`模块的 Python PostgreSQL 教程展示了如何使用`psycopg2`模块在 Python 中编程 PostgreSQL 数据库。

## PostgreSQL

PostgreSQL 是一个功能强大的开源对象关系数据库系统。 它是一个多用户数据库管理系统。 它可以在包括 Linux，FreeBSD，Solaris，Microsoft Windows 和 Mac OS X 在内的多个平台上运行。PostgreSQL 由 PostgreSQL 全球开发小组开发。

## `psycopg2`模块

PostgreSQL 有几个 Python 库。 语言。 在本教程中，我们使用`psycopg2`模块。 它是用于 Python 编程语言的 PostgreSQL 数据库适配器。 它主要在 C 中作为`libpq`包装器实现。

```py
$ pip install psycopg2

```

我们安装`psycopg2`模块。

## Python psycopg2 版本示例

在第一个代码示例中，我们获得 PostgreSQL 数据库的版本。

`version.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

con = None

try:

    con = psycopg2.connect(database='testdb', user='postgres',
        password='s$cret')

    cur = con.cursor()
    cur.execute('SELECT version()')

    version = cur.fetchone()[0]
    print(version)

except psycopg2.DatabaseError as e:

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

```

在程序中，我们连接到先前创建的`testdb`数据库。 我们执行一条 SQL 语句，该语句返回 PostgreSQL 数据库的版本。

```py
import psycopg2

```

`psycopg2`是一个 Python 模块，用于与 PostgreSQL 数据库一起使用。

```py
con = None

```

我们将`con`变量初始化为`None`。 如果无法创建与数据库的连接（例如磁盘已满），则不会定义连接变量。 这将导致`finally`子句中的错误。

```py
con = psycopg2.connect(database='testdb', user='postgres',
    password='s$cret')

```

`connect()`方法创建一个新的数据库会话并返回一个连接对象。 用户创建时没有密码。 在 localhost 上，我们可以省略`password`选项。 否则，必须指定它。

```py
cur = con.cursor()
cur.execute('SELECT version()')

```

从连接中，我们得到游标对象。 游标用于遍历结果集中的记录。 我们调用游标的`execute()`方法并执行 SQL 语句。

```py
version = cur.fetchone()[0]

```

我们获取数据。 由于只检索一条记录，因此我们称为`fetchone()`方法。

```py
print(version)

```

我们将检索到的数据打印到控制台。

```py
except psycopg2.DatabaseError as e:

    print(f'Error {e}')
    sys.exit(1)

```

如果发生异常，我们将输出一条错误消息并以错误代码 1 退出程序。

```py
finally:

    if con:
        con.close())

```

在最后一步，我们释放资源。

```py
$ version.py
PostgreSQL 11.1, compiled by Visual C++ build 1914, 64-bit

```

这是输出。

在第二个示例中，我们再次获得 PostgreSQL 数据库的版本。 这次我们使用`with`关键字。

`version2.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
    password='s$cret')

with con:

    cur = con.cursor()
    cur.execute('SELECT version()')

    version = cur.fetchone()[0]
    print(version)

```

程序返回 PostgreSQL 数据库的当前版本。 与`with`关键字一起使用。 代码更紧凑。

```py
with con:

```

使用`with`关键字，Python 自动释放资源。 它还提供错误处理。

## Python psycopg2 `execute`

我们创建`cars`表并在其中插入几行。 `execute()`执行数据库操作（查询或命令）。

`create_table.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                       password='s$cret')

with con:

    cur = con.cursor()

    cur.execute("DROP TABLE IF EXISTS cars")
    cur.execute("CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Audi', 52642)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Mercedes', 57127)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Skoda', 9000)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Volvo', 29000)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Bentley', 350000)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Citroen', 21000)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Hummer', 41400)")
    cur.execute("INSERT INTO cars(name, price) VALUES('Volkswagen', 21600)")

```

该程序将创建`cars`表，并将八行插入到该表中。

```py
cur.execute("CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(20), price INT)")

```

该 SQL 语句创建一个新的`cars`表。 该表有三列。

```py
cur.execute("INSERT INTO cars(name, price) VALUES('Audi', 52642)")
cur.execute("INSERT INTO cars(name, price) VALUES('Mercedes', 57127)")

```

这两行将两辆车插入表。

```py
$ psql -U postgres testdb
psql (11.1)
Type "help" for help.

testdb=# SELECT * FROM cars;
    id |    name    | price
----+------------+--------
    1 | Audi       |  52642
    2 | Mercedes   |  57127
    3 | Skoda      |   9000
    4 | Volvo      |  29000
    5 | Bentley    | 350000
    6 | Citroen    |  21000
    7 | Hummer     |  41400
    8 | Volkswagen |  21600
(8 rows)

```

我们使用`psql`工具验证写入的数据。

## Python Psycopg2 `executemany`

`executemany()`方法是一种方便的方法，用于针对在提供的序列中找到的所有参数元组或映射启动数据库操作（查询或命令）。 该函数对更新数据库的命令最有用：查询返回的任何结果集都将被丢弃。

`execute_many.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

cars = (
    (1, 'Audi', 52642),
    (2, 'Mercedes', 57127),
    (3, 'Skoda', 9000),
    (4, 'Volvo', 29000),
    (5, 'Bentley', 350000),
    (6, 'Citroen', 21000),
    (7, 'Hummer', 41400),
    (8, 'Volkswagen', 21600)
)

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()

    cur.execute("DROP TABLE IF EXISTS cars")
    cur.execute("CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT)")

    query = "INSERT INTO cars (id, name, price) VALUES (%s, %s, %s)"
    cur.executemany(query, cars)

    con.commit()

```

本示例删除`cars`表（如果存在）并（重新）创建它。

```py
cur.execute("DROP TABLE IF EXISTS cars")
cur.execute("CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT)")

```

第一个 SQL 语句删除`cars`表（如果存在）。 第二条 SQL 语句创建`cars`表。

```py
query = "INSERT INTO cars (id, name, price) VALUES (%s, %s, %s)"

```

这是我们使用的查询。

```py
cur.executemany(query, cars)

```

我们使用便捷的`executemany()`方法将八行插入到表中。 此方法的第一个参数是参数化的 SQL 语句。 第二个参数是数据，以元组的形式显示。

## Python `psycopg2`最后插入的行 ID

`psycopg2`不支持`lastrowid`属性。 要返回最后插入的行的 ID，我们必须使用 PostgreSQL 的`RETURNING id`子句。

`lastrowid.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                       password='s$cret')

with con:

    cur = con.cursor()

    cur.execute("DROP TABLE IF EXISTS words")
    cur.execute("CREATE TABLE words(id SERIAL PRIMARY KEY, word VARCHAR(255))")
    cur.execute("INSERT INTO words(word) VALUES('forest') RETURNING id")
    cur.execute("INSERT INTO words(word) VALUES('cloud') RETURNING id")
    cur.execute("INSERT INTO words(word) VALUES('valley') RETURNING id")

    last_row_id = cur.fetchone()[0]

    print(f"The last Id of the inserted row is {last_row_id}")

```

该程序将创建一个新的`words`表并打印最后插入的行的 ID。

```py
$ lastrowid.py
The last Id of the inserted row is 3

```

这是输出。

## Python Psycopg2 `fetchall`

`fetchall()`获取查询结果的所有（剩余）行，并将它们作为元组列表返回。 如果没有更多记录可获取，则返回一个空列表。

`fetch_all.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()
    cur.execute("SELECT * FROM cars")

    rows = cur.fetchall()

    for row in rows:
        print(f"{row[0]} {row[1]} {row[2]}")

```

在此示例中，我们从`cars`表中检索所有数据。

```py
cur.execute("SELECT * FROM cars")

```

该 SQL 语句从`cars`表中选择所有数据。

```py
rows = cur.fetchall()

```

`fetchall()`方法获取所有记录。 它返回一个结果集。 从技术上讲，它是一个元组的元组。 每个内部元组代表表中的一行。

```py
for row in rows:
    print(f"{row[0]} {row[1]} {row[2]}")

```

我们将数据逐行打印到控制台。

```py
$ fetch_all.py
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600

```

这是示例的输出。

## Python Psycopg2 `fetchone`

`fetchone()`返回查询结果集的下一行，返回单个元组，或者在没有更多数据可用时返回`None`。

`fetchone.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()
    cur.execute("SELECT * FROM cars")

    while True:

        row = cur.fetchone()

        if row == None:
            break

        print(f"{row[0]} {row[1]} {row[2]}")

```

在此示例中，我们连接到数据库并一张一张地获取`cars`表的行。

```py
while True:

```

我们从`while`循环访问数据。 当我们读取最后一行时，循环终止。

```py
row = cur.fetchone()

if row == None:
    break

```

`fetchone()`方法返回表的下一行。 如果没有剩余数据，则返回`None`。 在这种情况下，我们打破了循环。

```py
print(f"{row[0]} {row[1]} {row[2]}")

```

数据以元组的形式返回。 在这里，我们从元组中选择记录。 第一个是 ID，第二个是汽车名称，第三个是汽车的价格。

## Python `psycopg2`字典游标

默认游标检索元组中的数据。 使用字典游标，数据以 Python 字典的形式发送。 然后，我们可以通过列名称来引用数据。

`dictionary_cursor`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import psycopg2.extras

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cursor = con.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cursor.execute("SELECT * FROM cars")

    rows = cursor.fetchall()

    for row in rows:
        print(f"{row['id']} {row['name']} {row['price']}")

```

在此示例中，我们使用字典游标打印`cars`表的内容。

```py
import psycopg2.extras

```

字典游标位于`extras`模块中。

```py
cursor = con.cursor(cursor_factory=psycopg2.extras.DictCursor)

```

我们创建一个`DictCursor`。

```py
for row in rows:
    print(f"{row['id']} {row['name']} {row['price']}")

```

通过列名访问数据。 列名在 PostgreSQL 中（除非加引号）被折叠成小写并且区分大小写。 因此，我们必须以小写形式提供列名称。

## Python `psycopg2`参数化查询

当使用参数化查询时，我们使用占位符，而不是直接将值写入语句。 参数化查询可提高安全性和性能。

Python `psycopg2`模块支持两种类型的占位符：ANSI C `printf`格式和 Python 扩展格式。

`parameterized_query.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

uId = 1
uPrice = 62300

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()
    cur.execute("UPDATE cars SET price=%s WHERE id=%s", (uPrice, uId))

    print(f"Number of rows updated: {cur.rowcount}")

```

我们更新了一辆车的价格。 在此代码示例中，我们使用问号占位符。

```py
cur.execute("UPDATE cars SET price=%s WHERE id=%s", (uPrice, uId))

```

字符（`%s`）是值的占位符。 这些值将添加到占位符。

```py
print(f"Number of rows updated: {cur.rowcount}")

```

`rowcount`属性返回更新的行数。 在我们的情况下，一行已更新。

```py
$ parameterized_query.py
Number of rows updated: 1

testdb=> SELECT * FROM cars WHERE id=1;
 id | name | price
----+------+-------
  1 | Audi | 62300
(1 row)

```

汽车的价格已更新。 我们使用`psql`工具检查更改。

第二个示例使用 Python 扩展格式的参数化语句。

`parameterized_query2.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

uid = 3

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()

    cur.execute("SELECT * FROM cars WHERE id=%(id)s", {'id': uid } )

    row = cur.fetchone()

    print(f'{row[0]} {row[1]} {row[2]}')

```

我们使用`pyformat`参数化语句选择汽车的名称和价格。

```py
cur.execute("SELECT * FROM cars WHERE id=%(id)s", {'id': uid } )

```

命名的占位符以冒号开头。

```py
$ parameterized_query2.py
3 Skoda 9000

```

这是输出。

## Python `psycopg2`迁移

`mogrify`是 Python DB API 的`psycopg2`扩展，在参数绑定后返回查询字符串。 返回的字符串恰好是将发送到运行`execute()`方法或类似方法的数据库的字符串。

`mogrify.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')
cur = None

with con:

    cur = con.cursor()     

    print(cur.mogrify("SELECT name, price FROM cars WHERE id=%s", (2,)))

    # cur.execute("SELECT name, price FROM cars WHERE id=%s", (2,) )
    # row = cur.fetchone()
    # print(f"{row[0]} {row[1]}")

```

在将参数与`mogrify()`绑定后，程序显示`SELECT`查询字符串。

```py
$ mogrify.py
b'SELECT name, price FROM cars WHERE id=2'

```

这是输出。

## Python `psycopg2`插入图像

在本节中，我们将图像插入 PostgreSQL 数据库。

```py
testdb=> CREATE TABLE images(id SERIAL PRIMARY KEY, data BYTEA);

```

对于此示例，我们创建一个名为`images`的新表。 对于图像，我们使用`BYTEA`数据类型。 它允许存储二进制字符串。

`insert_image.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

def readImage():

    fin = None

    try:
        fin = open("sid.jpg", "rb")
        img = fin.read()
        return img

    except IOError as e:

        print(f'Error {e.args[0]}, {e.args[1]}')
        sys.exit(1)

    finally:

        if fin:
            fin.close()

con = None

try:
    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    cur = con.cursor()
    data = readImage()
    binary = psycopg2.Binary(data)
    cur.execute("INSERT INTO images(data) VALUES (%s)", (binary,))

    con.commit()

except psycopg2.DatabaseError as e:

    if con:
        con.rollback()

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

```

在程序中，我们从当前工作目录中读取图像，并将其写入 PostgreSQL `testdb`数据库的`images`表中。

```py
try:
    fin = open("sid.jpg", "rb")
    img = fin.read()
    return img

```

我们从文件系统读取二进制数据。 我们有一个名为`sid.jpg`的 JPEG 图像。

```py
binary = psycopg2.Binary(data)

```

使用`psycopg2` `Binary`对象对数据进行编码。

```py
cur.execute("INSERT INTO images(data) VALUES (%s)", (binary,))

```

该 SQL 语句用于将映像插入数据库。

## Python `psycopg2`读取图像

在本节中，我们将执行相反的操作。 我们从数据库表中读取图像。

`read_image.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

def writeImage(data):

    fout = None

    try:
        fout = open('sid2.jpg', 'wb')
        fout.write(data)

    except IOError as e:

        print(f"Error {0}")
        sys.exit(1)

    finally:

        if fout:
            fout.close()

try:
    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    cur = con.cursor()
    cur.execute("SELECT data FROM images LIMIT 1")
    data = cur.fetchone()[0]

    writeImage(data)

except psycopg2.DatabaseError as e:

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

```

我们从图像表中读取图像数据并将其写入另一个文件，我们称为`sid2.jpg`。

```py
try:
    fout = open('sid2.jpg', 'wb')
    fout.write(data)

```

我们以写入模式打开一个二进制文件。 来自数据库的数据被写入文件。

```py
cur.execute("SELECT data FROM images LIMIT 1")
data = cur.fetchone()[0]

```

这两行从`images`表中选择并获取数据。 我们从第一行获取二进制数据。

## Python PostgreSQL 元数据

元数据是有关数据库中数据的信息。 PostgreSQL 数据库中的元数据包含有关表和列的信息，我们在其中存储数据。 受 SQL 语句影响的行数是元数据。 结果集中返回的行数和列数也属于元数据。

可以使用游标对象的`description`属性或`information_schema`表获取 PostgreSQL 中的元数据。

接下来，我们打印`cars`表中的所有行及其列名。

`column_names.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                       password='s$cret')

with con:

    cur = con.cursor()

    cur.execute('SELECT * FROM cars')

    col_names = [cn[0] for cn in cur.description]
    rows = cur.fetchall()

    print(f'{col_names[0]} {col_names[1]} {col_names[2]}')

```

我们将`cars`表的内容打印到控制台。 现在，我们也包括列的名称。

```py
col_names = [cn[0] for cn in cur.description]

```

我们从游标对象的`description`属性获得列名。

```py
print(f'{col_names[0]} {col_names[1]} {col_names[2]}')

```

此行打印`cars`表的三个列名。

我们使用`for`循环打印行。 数据与列名对齐。

```py
$ column_names.py
id name price

```

这是输出。

在下面的示例中，我们列出了`testdb`数据库中的所有表。

`list_tables.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2

con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

with con:

    cur = con.cursor()
    cur.execute("""SELECT table_name FROM information_schema.tables
        WHERE table_schema = 'public'""")

    rows = cur.fetchall()

    for row in rows:
        print(row[0])

```

该代码示例将当前数据库中的所有可用表打印到终端。

```py
cur.execute("""SELECT table_name FROM information_schema.tables
    WHERE table_schema = 'public'""")

```

表名存储在系统`information_schema`表中。

```py
$ list_tables.py
cars
countries
projects
employees
users
tasks
images

```

这些是我们系统上的表。

## Python `psycopg2`导出和导入数据

我们可以使用`copy_to()`和`copy_from()`导出和导入数据。

`copy_to.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

con = None
fout = None

try:

    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    cur = con.cursor()
    fout = open('cars.csv', 'w')
    cur.copy_to(fout, 'cars', sep="|")

except psycopg2.DatabaseError as e:

    print(f'Error {e}')
    sys.exit(1)

except IOError as e:

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

    if fout:
        fout.close()

```

该代码示例将数据从`cars`表复制到`cars.csv`文件中。

```py
fout = open('cars.csv', 'w')

```

我们打开一个文件，在其中写入`cars`表中的数据。

```py
cur.copy_to(fout, 'cars', sep="|")

```

`copy_to`方法将数据从`cars`表复制到打开的文件。 这些列用`|`字符分隔。

```py
$ cat cars.csv
2|Mercedes|57127
3|Skoda|9000
4|Volvo|29000
5|Bentley|350000
6|Citroen|21000
7|Hummer|41400
8|Volkswagen|21600
1|Audi|62300

```

这些是`cars`文件的内容。

现在，我们将执行反向操作。 我们将转储的表重新导入数据库表。

```py
testdb=> DELETE FROM cars;
DELETE 8

```

我们从`cars`表中删除数据。

`copy_from.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

con = None
f = None

try:

    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    cur = con.cursor()
    f = open('cars.csv', 'r')

    cur.copy_from(f, 'cars', sep="|")
    con.commit()

except psycopg2.DatabaseError as e:

    if con:
        con.rollback()

    print(f'Error {e}')
    sys.exit(1)

except IOError as e:

    if con:
        con.rollback()

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

    if f:
        f.close()

```

在程序中，我们读取`cars`文件的内容，并将其复制回`cars`表。

```py
f = open('cars.csv', 'r')
cur.copy_from(f, 'cars', sep="|")
con.commit()

```

我们打开`cars.csv`文件进行读取，然后将内容复制到`cars`表中。 所做的更改已提交。

```py
SELECT * FROM cars;
 id |    name    | price
----+------------+--------
  2 | Mercedes   |  57127
  3 | Skoda      |   9000
  4 | Volvo      |  29000
  5 | Bentley    | 350000
  6 | Citroen    |  21000
  7 | Hummer     |  41400
  8 | Volkswagen |  21600
  1 | Audi       |  62300
(8 rows)

```

输出显示我们已经成功地重新创建了已保存的`cars`表。

## Python `psycopg2`事务

事务是针对一个或多个数据库中数据的数据库操作的基本单位。 事务中所有 SQL 语句的影响可以全部提交给数据库，也可以全部回滚。

在`psycopg2`模块中，事务由连接类处理。 连接游标的第一个命令启动事务。 （我们不需要用`BEGIN`和`END`语句来封装 SQL 命令来创建事务。这将由`psycopg2`自动处理。）以下命令在此新事务的上下文中执行。 发生错误时，事务将中止，并且直到`rollback()`方法都不再执行其他命令。

`psycopg2`模块的文档说，该连接负责终止其事务，并调用`commit()`或`rollback()`方法。 提交的更改将立即持久化到数据库中。 使用`close()`方法关闭连接或破坏连接对象（使用`del`或使其超出范围）将导致隐式的`rollback()`调用。

`psycopg2`模块还支持自动提交模式，其中对表的所有更改均立即生效。 为了在自动提交模式下运行，我们将连接对象的`autocommit`属性设置为`True`。

`no_commit.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

con = None

try:

    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    cur = con.cursor()

    cur.execute("DROP TABLE IF EXISTS friends")
    cur.execute("CREATE TABLE friends(id SERIAL PRIMARY KEY, name VARCHAR(255))")
    cur.execute("INSERT INTO friends(name) VALUES ('Tom')")
    cur.execute("INSERT INTO friends(name) VALUES ('Rebecca')")
    cur.execute("INSERT INTO friends(name) VALUES ('Jim')")
    cur.execute("INSERT INTO friends(name) VALUES ('Robert')")

    con.commit()

except psycopg2.DatabaseError as e:

    if con:
        con.rollback()

    print('Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

```

我们创建`friends`表，并尝试用数据填充它。 但是，正如我们将看到的，数据不会被提交。

```py
#con.commit()

```

注释`commit()`方法。 如果我们取消注释该行，则数据将被写入表中。

```py
finally:

    if con:
        con.close()

```

`finally`块始终执行。 如果我们尚未提交更改，并且没有发生错误（会回滚更改），则该事务仍将打开。 使用`close()`方法关闭连接，并通过隐式调用`rollback()`方法终止事务。

```py
testdb=# \dt
        List of relations
Schema |   Name    | Type  |  Owner
--------+-----------+-------+----------
public | cars      | table | postgres
public | countries | table | postgres
public | employees | table | postgres
public | images    | table | postgres
public | projects  | table | postgres
public | tasks     | table | postgres
public | users     | table | postgres
(7 rows)

```

仅在取消注释该行之后，才创建`friends`表。

### Python `psycopg2`自动提交

在自动提交模式下，将立即执行一条 SQL 语句。

`autocommit.py`

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import psycopg2
import sys

con = None

try:

    con = psycopg2.connect(database='testdb', user='postgres',
                    password='s$cret')

    con.autocommit = True

    cur = con.cursor()

    cur.execute("DROP TABLE IF EXISTS friends")
    cur.execute("CREATE TABLE friends(id serial PRIMARY KEY, name VARCHAR(10))")
    cur.execute("INSERT INTO friends(name) VALUES ('Jane')")
    cur.execute("INSERT INTO friends(name) VALUES ('Tom')")
    cur.execute("INSERT INTO friends(name) VALUES ('Rebecca')")
    cur.execute("INSERT INTO friends(name) VALUES ('Jim')")
    cur.execute("INSERT INTO friends(name) VALUES ('Robert')")
    cur.execute("INSERT INTO friends(name) VALUES ('Patrick')")

except psycopg2.DatabaseError as e:

    print(f'Error {e}')
    sys.exit(1)

finally:

    if con:
        con.close()

```

在此示例中，我们以自动提交模式连接到数据库。 我们既不调用`commit()`，也不调用`rollback()`方法。

```py
con.autocommit = True

```

我们将连接设置为自动提交模式。

```py
$ autocommit.py

testdb=# select * from friends;
 id |  name
----+---------
  1 | Jane
  2 | Tom
  3 | Rebecca
  4 | Jim
  5 | Robert
  6 | Patrick
(6 rows)

```

数据已成功提交到`friends`表。

这是 PostgreSQL Python 教程。 您可能也对 [SQLite Python 教程](/python/sqlite/)和 [MySQL Python 教程](/python/pymysql/)感兴趣