使用数据库的正确姿势(一)

96
程序员在深圳
2017.03.01 15:49* 字数 2397
题图

这是我在慕课网上分享的一个关于数据库操作的逐字讲稿,主要分两部分,第一部分为数据库的基本使用,第二部分为用面向对象的方法来使用数据库,及分布式数据库的基本介绍。

大家好,今天我给大家分享的主题是《使用数据库的正确姿势》,首先我会对数据库做一个简要的介绍,然后我会从三个方面来讲解如何使用数据库,下面我们正式开始。

数据库的重要性

众所周知,数据库是互联网公司最宝贵的资源,我们可以从两个角度来看它的重要性:

从用户角度看,它保存了用户的数据,任何数据的丢失都会影响产品体验,更为严重者,数据库的使用问题还会导致用户的财产损失,例如某个用户进行了两笔支付操作,但在数据库中只生成了一笔订单,此为常见的数据一致性问题。

从公司角度,数据库是公司的财富,也是公司间竞争的壁垒,拥有更大数据规模的公司,相应的也会更有优势,尤其是在大数据时代,更多的数据意味着有更多的可能性,以及更好的用户体验,同时也更难被超越,例如国内的腾讯、阿里巴巴、百度,及国外的Google、Facebook等公司就是典型的例子。

数据库领域

所以说任何公司或者开发者,都要用好数据库(我们这里说的数据库指的是关系型数据库),由于数据库足够复杂,在计算机领域,它已经发展成了一个独立的方向。而作为一个开发者,能不能用好数据库,也成了衡量他是否有价值的指标,在招聘中,我经常会问面试者一个关于数据库的问题:

对于MySQL,你认为它的瓶颈在哪里?

这个问题看似简单,但得到的答案可以用千差万别来形容,答案大致分这么几种:

1. 数据库的容量是它的瓶颈
2. 大量的读或写操作是它的瓶颈
3. 复杂的SQL语句是它的瓶颈,例如大量没有经过优化的SQL语句
4. 索引越来越大是它瓶颈

这个问题看似是一个数据库问题,实际上它还是一个操作系统问题,因为数据库和操作系统一样,也要使用内存,磁盘,网络,同时还要对缓存进行高效的利用和管理,并且它比操作系统还要擅长于存储和管理数据。说到这里,我倒要反过来问你一个问题:

如果你的电脑变慢了,你会怎么做?

大多数人第一时间会想到加条内存,或换个SSD硬盘,这个问题很少有人会回答错误,那么为什么我们回答同样的问题,只是把操作系统换成数据库,就回答不上来了呢?

所以,能不能举一反三,及清楚的认识操作系统和数据库的组成原理,直接反映了这个人的基本功是否扎实,以及他以后能不能写出高质量的代码。

数据库的应用

在数据库的应用方面,一般又分为两种角色:

  • 一种是应用开发者,在公司里一般被称为“服务器工程师”或“web开发工程师”
  • 一种是数据库管理者,在公司一般被称为“DBA”(DataBase Administrator)或“运维”

这两种角色的视角和侧重点是不一样的,前者一般侧重于在应用程序中使用数据库,他们的日常操作即我们常说的CRUD操作(分别是create、read、update和delete);而后者则更侧重于数据库的维护和管理,例如安全性、扩展性、性能、及易用性等。这次的分享主要会围绕第一个角色展开。

虽然一般公司常会把这两种角色分配在不同的岗位,但任何一种角色最好能拥有另外一种角色的思维,这样才能更高效的使用数据库,增强组织间的协作,从而提升整体的开发和维护效率。

下面会以Python语言和MySQL数据库为例,从数据库的应用方面讲一下在工作中,如何更好的使用数据库。

使用Python的原因是因为Python语言比较简洁,在业内使用非常广泛,且它的数据库方面的资源比较完善;而MySQL基本是最为常用的数据库。

在我看来,数据库的使用方面分为三个层次

  1. 数据库的基本使用
  2. 利用面向对象的思维使用数据库
  3. 在项目中应用分布式数据库

在我经历的大多数项目中,我发现很多项目仅仅停留在第一个层次,尤其是,小的团队对数据库的使用都比较初级,他们可能更关注数据库的设计三范式、数据库的基本操作,及设计出来的数据库能否满足应用的需求,对于应用的可维护性和扩展性可能会关注的比较少。

但我认为在数据库的使用方面,起码要从第二个层次开始(具体原因后面会详细介绍),即小团队、小项目使用面向对象的思维使用数据库,等到项目变大了,再由第二个层次扩展到第三个层次。

数据库的环境搭建

下面我们进入数据库的基本使用,不过在此之前,我们首先需要搭建开发环境,我当前的演示环境是macOS,对于其他操作系统,我将提供以下页面供大家参考:

下面我来演示一下操作步骤

# 1. 安装pip
$ wget https://bootstrap.pypa.io/get-pip.py
$ python ./get-pip.py
# 2. 配置pip源
$ echo "[global]" > ~/.pip/pip.conf
$ echo "index-url = https://pypi.tuna.tsinghua.edu.cn/simple" >> ~/.pip/pip.conf
# 3. 检查pip源文件
$ cat ~/.pip/pip.conf
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
# 4. 安装MySQL
$ brew install mysql
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/mysql-5.7.17.sierra.bottle.tar.gz
Already downloaded: /Users/fengyajie/Library/Caches/Homebrew/mysql-5.7.17.sierra.bottle.tar.gz
==> Pouring mysql-5.7.17.sierra.bottle.tar.gz
==> Using the sandbox
==> Caveats
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
==> Summary
🍺  /usr/local/Cellar/mysql/5.7.17: 14,226 files, 444.4M
# 5. mysql在mac上的初始用户是root,没有密码,你可以通过命令行`mysql -uroot`启动MySQL,如果没问题,键入quit退出
$ mysql -uroot
# 6. 安装MySQL-python
$ pip install MySQL-python
# 7. 安装SQLAlchemy
$ pip install SQLAlchemy

完成以上7步,你的python-mysql开发环境就搭建好了

数据库的基本使用

下面我们正式进入数据库的基本使用环节,数据库的基本使用主要包括DDL(Data Definition Language)和DML(Data Manipulation Language),我们用具体的操作来理解这两个概念:

  • 常用的DDL操作为创建数据库(create database)、创建表(create table)和修改表(alter table)
  • 常用的DML操作为CRUD,包括新增(Create)、查找(Read)、修改(Update)及删除(Delete)四种基本操作,对应到数据库的命令为Insert、Select、Update和Delete

创建数据库

首先,我们来看一下创建数据库的代码

def getURL(user, passwd, host, port, database="", driver="mysql"):
    mysql_db = {'drivername': driver,
                'username': user,
                'password': passwd,
                'host': host,
                'port': port,
                'database': database}
    return URL(**mysql_db)

def createDatabase(user, passwd, host, port, db):
    db_uri = getURL(user, passwd, host, port) # 步骤1
    engine = create_engine(db_uri) # 步骤2
    engine.execute("create database if not exists %s" % db) # 步骤3

createDatabase("root", "", "localhost", 3306, "mydb")

createDatabase这个函数实现了创建数据库的三个步骤:

步骤1 - 获取数据库的地址
步骤2 - 连接数据库
步骤3 - 执行创建数据库的命令

运行这段代码后,我们通过命令行(输入mysql -uroot)打开数据库,执行show databases;命令,这时你便可以看到我们刚创建的数据库mydb了。

$ mysql -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.7.17 Homebrew

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database         |
+--------------------+
| mydb                |
+--------------------+
5 rows in set (0.00 sec)

创建表

接着我们来看一下创建表的代码

def testCreateTable():
    db_uri = getURL("root", "", "localhost", 3306, "mydb")
    engine = create_engine(db_uri) # 步骤1
    metadata = MetaData(engine) 
    table = Table('EX1', metadata,
                  Column('id', Integer, primary_key=True, autoincrement=True),
                  Column('name', String(255), nullable=False)) # 步骤2
    table.create()  # 步骤3

testCreateTable()

testCreateTable这个函数实现了创建表,同样分为三个步骤:

步骤1 - 连接数据库
步骤2 - 定义表的元数据
步骤3 - 创建数据表

步骤2中指定了表名为EX1,该表有2个字段,一个字段为id,另一个为name。运行该程序后,你会发现,数据库mydb中多了一个表EX1

CRUD

最后,我们再来看一下CRUD的代码,这段代码在testCRUD函数中

def testCRUD():
    db_uri = getURL("root", "", "localhost", 3306, "mydb")
    engine = create_engine(db_uri)

    # 第1步 Create 
    engine.execute('INSERT INTO EX1 '
                   '(name) '
                   'VALUES ("raw1")')

    # 第2步 Read
    result = engine.execute('SELECT * FROM EX1')
    for _r in result:
        print _r

    # 第3步 Update
    engine.execute('UPDATE EX1 set name="raw" '
                   'WHERE name="raw1"')
    result = engine.execute('SELECT * FROM EX1')
    for _r in result:
        print _r

    # 第4步 Delete
    engine.execute('DELETE from EX1 where name="raw"')
    result = engine.execute('SELECT * FROM EX1')
    print result.fetchall()

testCRUD()

第1步 - 我们执行Insert语句,向数据库中插入一条数据,这条数据的nameraw1
第2步 - 我们执行Select语句,将这条数据读取出来
第3步 - 我们执行Update语句,用另外一个名字raw,来替换raw1
第4步 - 我们执行Delete语句,把这条记录删除

运行后,你可以看到在第2步中我们把插入的数据查询出来,它的nameraw1,第3步我们把name修改为了raw,第4步,我们把记录删除后,打印出来的是空的记录

(2L, 'raw1')
[(2L, 'raw')]
[]

了解以上几个基本的操作,你便可以开始使用数据库,这就是我们前面提到的数据库应用的第一个层次。

以上代码均可以在github上下载

本文是《使用数据库的正确姿势》系列文章的第一篇,你可以打开《使用数据库的正确姿势(二)》继续阅读

全栈工程师