数据库编程

数据库

数据库(Database)是计算机系统中用于存储、管理和访问数据的核心组件,也被称为数据存储库(Data Store)。以下是对数据库的详细解释:

一、定义与基本概念

  • 定义:数据库是指存储数据的容器,它能够存储大量结构化和非结构化的数据,包括文本、数字、图像、音频等各种类型的数据。
  • 基本概念:数据库由若干个相关数据的集合组成,这些数据被组织在表格、集合或其他数据结构中,以便于进行高效的管理、处理和访问。

二、数据库的类型

  1. 关系型数据库:使用表格(二维结构)来组织和存储数据,通过结构化查询语言(SQL)进行数据管理和查询。常见的关系型数据库包括MySQL、Oracle Database、Microsoft SQL Server、PostgreSQL等。
  2. 非关系型数据库(NoSQL) :不使用传统的关系型数据库模型,而是采用其他数据模型(如键值对、文档、图形、列族等)来组织和管理数据。常见的非关系型数据库有MongoDB、Cassandra、Redis、Elasticsearch等。
    • 文档数据库:如MongoDB,存储数据为文档形式,每个文档都是一个JSON或类似JSON的对象。
    • 键值数据库:如Redis,使用简单的键值对来存储数据。
    • 列族数据库:如Apache Cassandra,将数据存储在列族中,每个列族包含多个列,列可以动态地增减。
    • 图形数据库:如Neo4j,基于图的数据模型,使用节点和边来表示实体和关系,适用于社交网络分析等领域。

三、数据库的结构与设计

  • 数据建模:数据库设计的核心部分,将业务需求转化为数据库的数据结构和关系,一般采用E-R图(实体-关系图)来表示。
  • 数据库设计:将数据模型转化为数据库的实际结构,包括数据库表格的设计、字段的定义、数据类型的选择、主键和外键的定义等。
  • 数据库实现:将数据库设计转化为实际的数据库系统,包括数据库软件的安装、数据库表格的创建、数据的导入和检验等。

四、数据库管理

  • 广义定义:包括数据库设计以后的一切数据库管理活动,如数据库模型创建、数据加载、数据库系统日常维护活动等。
  • 狭义定义:特指数据库系统运行期间采取的活动,如数据服务、性能监督、数据库重组、数据库重构、数据库完整性控制和安全性控制、数据库恢复等。
  • 数据库管理员(DBA):负责数据库的日常管理和维护工作,确保数据库的稳定性和安全性。

五、数据库的应用

数据库在现代社会中有着极其广泛的应用,几乎涵盖了所有需要数据存储、管理和分析的行业和领域。例如:

  • 企业应用:用于存储、管理和访问业务数据,如客户信息、销售数据和生产数据等。
  • 金融行业:用于存储、管理和分析金融数据,如账户余额、交易历史和股票价格等。
  • 医疗行业:用于存储、管理和分析患者病历、医疗图像和药物信息等。
  • 教育行业:用于存储、管理和分析学生信息、课程内容和教育资源等。
  • 互联网应用:如社交媒体、电子商务等,需要存储大量的用户信息、网站内容和交易数据。

六、数据库的优势

  • 数据共享:数据库系统允许多用户、多应用共享数据,减少了数据的冗余度,节约了存储空间。
  • 数据独立性:数据库系统提供了数据的物理独立性和逻辑独立性,使得应用程序与数据库中的数据相互独立。
  • 数据安全性和完整性:数据库系统通过统一的数据管理和控制,保证了数据的安全性和完整性。
  • 高效的数据处理:数据库系统提供了高效的数据查询、更新和删除等操作,支持复杂的数据分析和处理。

数据必须以某种方式存储起来才有价值,数据库实际上是一组相关数据的集合。数据库编程的相关技术有很多,涉及具体的数据库安装、配置和管理,还要掌握SQL语句,最后才能编写程序访问数据库。

数据持久化技术概述

凡是将数据保存到存储介质中,需要时能再找出来,并能够对数据进行修改,就属于数据持久化。例如:把数据保存到数据库中。而在Python中关于数据持久化的技术有很多,其中比较常用的有:

文本文件:通过Python文件操作和管理技术将数据保存到文本文件中,然后进行读写操作,这些文件一般是结构化的文档,如XML文档和JSON等文件。结构化文档是指在文件内部采取某种方式将数据组织起来的文件。

数据库:将数据保存在数据库中之后可以通过数据库管理系统(DBMS)来对数据进行管理,该系统支持事务处理、并发访问、高级查询和SQL。Python中将数据保存到数据库中的技术有很多,但主要分为两类:遵循 Python DB-API 规范技术 和 ORM(Object-Relational Mapping 对象关系映射) 技术(它能将对象保存到数据库表中)。Python DB-API 规范通过在Python中编写SQL语句访问数据库。

Python DB-API 规范一定会依托某个数据库管理系统。可以点击我的主页查看我之前发过的 MySQL数据库教程一文。

Python DB-API

在有Python DB-API 规范之前,各个数据库编程接口非常混乱,实现方式差别很大,更换数据库工作量非常大。Python DB-API 规范要求各个数据库厂商和第三方开发商,遵循统一的编程接口,这使得Python开发数据库变得统一而简单,更新数据库工作量很小。

Python DB-API 只是一个规范,没有访问数据库的具体实现,规范是用来约束数据库厂商的,要求数据库厂商为开发人员提供访问数据库的标准接口。

  • Python官方制定了Python DB-API 规范,这个规范包括全局变量、连接、游标、数据类型和异常等内容。
  • 数据库厂商为了支持Python语言访问自己的数据库,根据这些Python DB-API 规范提供了具体的实现类,如连接和游标对象具体实现方式。当然针对某种数据库也可能有其他第三方实现。
  • 对于开发人员而言,Python DB-API 规范提供了一致的API接口,开发人员不用关心实现接口的细节。

建立数据库连接

数据库访问的第一步是进行数据库连接。建立数据库连接可以通过connect(parameters...)函数实现,该函数根据parameters参数连接数据库,连接成功返回Connection对象。连接数据库代码如下:

import pymysql    #导入模块

connectio = pymysql.connect(host='数据库主机名或IP地址',
                            user='访问数据库账号',
                            password='访问数据库密码',
                            databse='数据库中的库名',
                            port='连接数据库的端口号',
                            charset='数据库编码格式')

其中password也可以改为passwd,database也可以改为db,charset参数中输入"utf8"是配置数据库串集 UTF-8 编码。

注意:连接参数虽然主要包括数据库主机名或IP地址、用户名、密码等内容,但是不同数据库厂商(或第三方开发商)提供的开发模块会有所不同,具体使用时需要查询开发文档。此外,在使用前需要先下载 PyMySQL库,通过命令"pip install PyMySQL"即可。

|------------|-----------------------------|
| 方法名 | 说明 |
| close() | 关闭数据库连接,若数据库已经关闭连接再使用则会引发异常 |
| commit() | 提交数据库事务 |
| rollback() | 回滚数据库事务 |
| cursor() | 获得 Cursor 游标对象 |
[Connection对象的部分重要方法]

注意:数据库事务通常包含了多个对数据库的读/写操作,这些操作是有序的。若事务被提交给了数据库管理系统,则数据库管理系统需要确保该事务中的所有操作都完成成功,结果被永久保存在数据库中。如果事务中有的操作没有完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态。同时,该事务对数据库或者其他事务的执行无影响,所有的事务都看似在独立地运行。

创建游标

一个Cursor游标对象表示一个数据库游标,游标暂时保存了SQL操作所影响到的数据。在数据库事务管理中游标非常重要,游标是通知数据库连接创建的,相同数据库连接创建的游标所引起的数据变化,会马上反映到同一连接中的其他游标对象。但是不同数据库连接中的游标,是否能及时反映出来,则与数据库事务管理有关。

游标Cursor对象有很多属性和方法,其中基本SQL操作方法如下:

(1)execute(operation[,parameters])

执行一条SQL语句,operation是SQL语句,parameters是为SQL提供的参数,可以是序列或字典类型。返回值是整数,表示执行SQL语句影响的行数。

(2)executemany(operation[,seq_of_params])

批量执行SQL语句,operation是SQL语句,seq_of_params是为SQL提供的参数,seq_of_params是序列。返回值是整数,表示执行SQL语句影响的行数。

(3)callproc(procname[,parameters])

执行存储过程,procname是存储过程名,parameters是为存储过程提供的参数。

执行SQL查询语句也是通过 execute() 和 executemany() 方法实现的,但是这两个方法返回的都是整数,对于查询没有意义。因此使用 execute() 和 executemany() 方法实现后,还要通过提取方法提取结果集

方法名 说明
fetchone() 从结果集中返回一条记录的序列,如果没有数据则返回None
fetchmany([size=cursor.arraysize]) 从结果集返回小于或等于size的记录数序列,如果没有数据返回空序列,size默认情况下是整个游标的行数
fetchall() 从结果集返回所有数据
[相关提取方法]

示例:对User表进行CRUD操作

对数据库表中的数据可以进行四类操作:数据插入(Create)、数据删除(Delete)、数据更新(Update)和数据查询(Read),也就是"增删改查"。

PyMySQL遵从Python DA-API2 规范,其中包含了纯Python实现的MySQL客户端。PyMySQL兼容MySQLdb,MySQLdb是Python2中使用的数据库开发模块。

安装PyMySQL库

打开命令提示符,输入下面代码

pip install PyMySQL

pip 是Python 官方提供的包管理工具,Python默认安装就会安装 pip 工具。(pip 服务器在国外,有的库下载安装很慢,甚至有的库无法安装。此时可以使用国内的镜像服务器,需要在 pip 指令后面加 -i 参数后面跟镜像服务器网址)

修改指令如下(此处镜像服务器由清华大学提供,也可以使用其他镜像服务器)

pip install PyMySQL -i https://pypi.tuna.tsinghua.edu.cn/simple

数据库编程一般过程(如下图)

其中查询(Read)和修改(C插入、U更新、D删除)过程都是最多需要6个步骤。查询过程中需要提取数据结果集,这是修改过程中没有的步骤。而修改过程中如果成功执行SQL操作则提交数据库事务,如果失败则回滚事务。最后需要释放资源,即关闭游标和数据库。

为了执行CRUD操作,首先需要使用数据库创建表,此处我使用的是MySQL数据库,如果有不知道的可以参考下文:

MySQL数据库教程-CSDN博客https://blog.csdn.net/2302_76708905/article/details/140368123首先打开MySQL客户端,然后输入密码进入后再输入下面命令(用于创建数据库MyDB)

CREATE DATABASE IF NOT EXISTS MyDB;

按回车键执行后看到下图则为成功

接下来输入下面命令选择数据库

use MyDB;

按回车键执行后看到下图则为成功

接下来输入下面命令创建用户表,此处用户表假设为两个字段(用户id、用户密码)

CREATE TABLE IF NOT EXISTS user(
    name varchar(20),
    userid int,
    PRIMARY KEY(userid));

按回车键执行后看到下图则为成功

接下来输入下面命令插入原始数据

INSERT INTO user VALUES("Tom",1);
INSERT INTO user VALUES("Ben",2);
INSERT INTO user VALUES("张三",3);

按回车键执行后看到下图则为成功

数据库查询操作

接下来查询上面建立的MyDB数据库

(1)有条件查询

输入下面示例代码

import pymysql

# 1.建立数据库连接
connection = pymysql.connect(host='localhost',#代表本地主机
                            user='用户名',
                            password='密码',
                            database='MyDB',
                            charset='utf8')# MySQL数据库默认安装以及默认创建的数据库都是UTF-8编码
try:
    # 2.创建游标对象
    with connection.cursor() as cursor:
        # 3.执行SQL操作
        sql = 'select name,userid from user where userid>%(id)s'# %(id)s是命名占位符
        cursor.execute(sql,{'id':0})# 执行sql语句并绑定参数
        # 4.提取结果集
        result_set = cursor.fetchall()
        for row in result_set:
            print('id:{0}-name:{1}'.format(row[1],row[0]))
    # 5.关闭游标
finally:
    # 6.关闭数据库连接
    connection.close()

代码运行结果如下

可能看到代码时大家会有疑问:为什么数据库连接不使用类似于游标的with代码块管理资源呢?因为数据库连接如果出现异常,程序再往后执行数据库操作已经没有任何意义了,因此数据库连接不需要放到try-except语句中,也不需要with代码块管理。

注意:提交字段时,字段的顺序是select语句中列出的字段顺序,不是数据表中字段的顺序,除非使用select*语句。

(2)无条件查询

输入下面示例代码

import pymysql

# 1.建立数据库连接
connection = pymysql.connect(host='localhost',
                            user='root',
                            password='123456',
                            database='MyDB',
                            charset='utf8')
try:
    # 2.创建游标对象
    with connection.cursor() as cursor:
        # 3.执行SQL操作
        sql = 'select max(userid) from user'# 使用max等函数
        cursor.execute(sql)
        # 4.提取结果集
        row = cursor.fetchone()
        if row is not None:
           print("最大用户id:{0}".format(row[0]))
    # 5.关闭游标
finally:
    # 6.关闭数据库连接
    connection.close()

代码执行结果如下

最大用户id:3

Process finished with exit code 0

数据库修改操作

1.数据插入

输入下面示例代码

import pymysql

# 查询最大用户id
def read_max_userid():
    # 1.建立数据库连接
    connection = pymysql.connect(host='localhost',
                                 user='root',
                                 password='123456',
                                 database='MyDB',
                                 charset='utf8')
    try:
        # 2.创建游标对象
        with connection.cursor() as cursor:
            # 3.执行SQL操作
            sql = 'select max(userid) from user'  # 使用max等函数
            cursor.execute(sql)
            # 4.提取结果集
            row = cursor.fetchone()
            return row[0]
        # 5.关闭游标
    finally:
        # 6.关闭数据库连接
        connection.close()

# 1.建立数据库连接
connection = pymysql.connect(host='localhost',
                            user='root',
                            password='123456',
                            database='MyDB',
                            charset='utf8')

# 查询最大值
maxid = read_max_userid()

try:
    # 2.创建游标对象
    with connection.cursor() as cursor:
        # 3.执行SQL操作
        sql = 'insert into user(userid,name) values(%s,%s)'
        nextid = maxid+1
        name = 'Tony'+str(nextid)
        cursor.execute(sql,(nextid,name))
        
        print('影响的行数:{0}'.format(cursor.rowcount))
        # 4.提交数据库事务
        connection.commit()

    # 5.关闭游标
except pymysql.DatabaseError:
    # 4.回滚数据库事务
    connection.rollback()
finally:
    # 6.关闭数据库连接
    connection.close()

代码执行结果

影响的行数:1

Process finished with exit code 0

此时可以看到上面这段代码不够完美,有许多重复的代码,可以进一步进行优化,代码优化的目标是提高可读性、可维护性,并确保资源的正确管理。优化可以使用上下文管理器(with语句) 来确保数据库连接在使用后能够正确关闭。封装数据库操作 到函数中,避免代码重复。异常处理确保在出现错误时能够回滚事务并关闭数据库连接等。

2.数据更新

示例代码如下

import pymysql

# 1.建立数据库连接
connection = pymysql.connect(host='localhost',
                            user='root',
                            password='123456',
                            database='MyDB',
                            charset='utf8')
try:
    # 2.创建游标对象
    with connection.cursor() as cursor:
        # 3.执行SQL操作
        sql = 'update user set name= %s where userid > %s'
        affectedcount = cursor.execute(sql,('Tom',3))
        print('影响的行数:{0}'.format(affectedcount))
        # 4.提交数据库事务
        connection.commit()

    # 5.关闭游标
except pymysql.DatabaseError as e:
    # 4.回滚数据库事务
    connection.rollback()
    print(e)
finally:
    # 6.关闭数据库连接
    connection.close()

代码运行结果

影响的行数:1

Process finished with exit code 0

3.数据删除

示例代码如下

import pymysql

# 查询最大用户id
def read_max_userid():
    # 1.建立数据库连接
    connection = pymysql.connect(host='localhost',
                                 user='root',
                                 password='123456',
                                 database='MyDB',
                                 charset='utf8')
    try:
        # 2.创建游标对象
        with connection.cursor() as cursor:
            # 3.执行SQL操作
            sql = 'select max(userid) from user'  # 使用max等函数
            cursor.execute(sql)
            # 4.提取结果集
            row = cursor.fetchone()
            return row[0]
        # 5.关闭游标
    finally:
        # 6.关闭数据库连接
        connection.close()


# 1.建立数据库连接
connection = pymysql.connect(host='localhost',
                             user='root',
                             password='123456',
                             database='MyDB',
                             charset='utf8')

# 查询最大值
maxid = read_max_userid()

try:
    # 2.创建游标对象
    with connection.cursor() as cursor:
        # 3.执行SQL操作
        sql = 'delete from user where userid = %s'
        affectcount = cursor.execute(sql, (maxid))
        print('影响的行数:{0}'.format(affectcount))
        # 4.提交数据库事务
        connection.commit()

    # 5.关闭游标
except pymysql.DatabaseError:
    # 4.回滚数据库事务
    connection.rollback()
finally:
    # 6.关闭数据库连接
    connection.close()

代码运行结果

影响的行数:1

Process finished with exit code 0

从上述案例中不难看出:数据更新、数据删除和数据插入在程序结构上非常相似,差别主要在于SQL语句和绑定的参数不同。

NoSQL数据库存储

目前大部分数据库都是关系型的,通过SQL语句操作数据库。但也有一些数据库是非关系型的,不通过SQL语句操作数据库,这些数据库称为NoSQL是数据库。dbm(data base manager)数据库是最简单的NoSQL数据库,它不需要安装,直接通过键值对数据存储。

dbm数据库的打开和关闭

与关系型数据库类似,dbm数据库使用前需要打开,使用完成需要关闭。打开数据库使用open()函数,它的语法如下:

dbm.open(file,flag='r')

参数file是数据库文件名,包含路径;参数flag是文件打开方式,flag取值说明如下:

r:以只读方式打开现有数据库,这是默认值

w:以读写方式打开现有数据库

c:以读写方式打开现有数据库,如果数据库不存在则创建

n:始终创建一个新的空数据库,打开方式为读写

关闭数据库使用close()函数,该函数没有参数;此外也可以使用with语句,此时则不需要使用close语句来释放资源。示例代码如下

with dbm.open(filename,'r') as db:
    pass

dbm数据存储

dbm数据存储方式类似于字典数据结构,通过键写入或读取数据。但需要注意dbm数据库保存的数据是字符串类型或字节(bytes)类型。

dbm数据存储相关语句如下:

(1)写入数据

d[key] = data

d是打开的数据库对象,key是键,data是要保存的数据。如果key不存在则创建key-data数据项,如果key已经存在则使用data覆盖旧数据。

(2)读取数据

data = d[key]  或 data = d.get(key,defaultvalue)

使用 data = d[key] 读取数据时,如果没有key对应的数据则会抛出KeyError异常。为了防止这种情况的发生,可以使用 data = d.get(key,defaultvalue) 语句,如果没有key对应的数据,则会放回默认值defaultvalue。

(3)删除数据

del d[key]

按照key删除数据,如果没有key对应的数据则会抛出KeyError异常。

(4)查找数据

flag = key in d

按照key在数据库中查找数据,示例代码如下

import dbm
with dbm.open('mydb_name','c') as db:
    db['name'] = 'tony'    # 更新数据
    print(db['name'].decode())    # 取出数据
    
    age = int(db.get('age',b'18').decode())    # 取出数据
    print(age)
    if 'age' in db:    # 判断是否存在age数据
        db['age'] = '20'    # 或者b'20'

    del db['name']    #删除name数据

db['name']表达式取出的数据是字节序列,如果需要的是字符串则需要使用decode()方法将字节序列转换为字符串。

参考书籍:《python从小白到大牛》(第2版)关东升 编著


文章创作不易,本文10000+字,为了大家能理解,写的很详细,这也让我花了很多时间。最后,如果觉得本文对大家有帮助的话,还请给我点个赞和关注,谢谢大家!!!

相关推荐
清水白石00830 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
Python私教5 小时前
model中能定义字段声明不存储到数据库吗
数据库·oracle
BestandW1shEs8 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师8 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球8 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...8 小时前
表的操作(MySQL)
数据库·mysql·表的操作
哥谭居民00018 小时前
MySQL的权限管理机制--授权表
数据库
wqq_9922502778 小时前
ssm旅游推荐系统的设计与开发
数据库·旅游
难以触及的高度9 小时前
mysql中between and怎么用
数据库·mysql