抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

为什么不用sqlite3

新建一个项目默认使用的是sqlite3。可从setting.py里看到,DATABASES定义使用的数据库。

image.png

sqlite3的数据库使用简单,配合django.db的models方法也是美滋滋,本身是嵌入式关系型数据库,比较轻便,熟悉安卓测试同学可能会发现,在一些app安装目录下有 sqlite数据库文件,用以存储该应用的一些本地信息。该数据库没有用户名密码,也不好远程连接(我没试过),这也限制了他的使用场景。

再加上按照 django的模式,是先定义model,它帮你做好映射关系,然后执行makemigrations生成sql脚本再执行migrate执行脚本对数据库做操作。总体来讲不安全,风险较大,且按照目前项目组规则,都是通过SQL语句做变更,也便于做权限控制,每一次变动也都能追溯到提交人,而不必每次都要去改代码。

安装Mysql-Server

安装

为了方便本地开发,可以在本地安装mysql-server。

https://dev.mysql.com/downloads/mysql/ 下载安装包,通常下载社区版(Community)就好

image.png

配置

下载后安装,然后配置Path环境变量。

以win10为例,假设安装路径是 D:\Program Files\MySQL\bin

image.png

然后新增配置文件 D:\Program Files\MySQL\my.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[mysql]

# 设置MySQL客户端默认字符集
default-character-set = utf8mb4

[mysqld]
# 设置3306端口
port = 3306

# 密码认证插件
default_authentication_plugin=mysql_native_password

# 设置MySQL安装目录
basedir = "D:\Program Files\MySQL"

# 设置MySQL数据库数据存放目录
datadir = "D:\Program Files\MySQL\data"

# 允许最大连接数
max_connections = 200

# 服务端使用的字符集
character-set-server = utf8

# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

初始化数据库,打开cmd执行下面命令

1
2
#初始化
mysqld --initialize --console

安装mysql服务并启动

1
2
3
4
5
#安装MySQL服务,这里会打印初始的root密码
mysqld --install

#启动MySQL服务
net start mysql

更改root密码

1
2
3
4
5
#用户登录
mysql -u root -p # 输入密码

#修改root密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'admin';

服务指令

| 启动MySQL服务 | net start mysql |

| — | — |

| 停止MySQL服务 | net stop mysql |

| 卸载MySQL服务 | sc delete MySQL/mysqld -remove |

mysql命令行操作

| 创建新用户 | CREATE USER ‘用户名‘@’%’ IDENTIFIED BY ‘密码’; |

| — | — |

| 用户授权 | GRANT ALL PRIVILEGES ON . TO ‘用户名‘@’%’; |

(用户授权,可以限制用户操作权限是表一级别还是库级别,也可限制用户远程登陆,这里不展开讲。)

创建第一个数据库

也可以通过navicat连接后在界面创建

启动服务后,使用命令行登陆

1
CREATE DATABASE database_name DEFAULT CHARACTER SET utf8mbp4 COLLATE utf8mbp4_bin;

character设置字符集格式 collate设置排序规则,会影响排序和比较 国内使用通常分别设置为utf8mbp4和utf8mbp4_bin

模块选择

操作Mysql, django推荐的是使用MySQLdb,但我个人认为这个模块有毒,我个人推荐使用pymysql,简单好用。

首先,开头说了 setting了定义了数据库类型,这边修改下配置。

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 固定
'NAME': 'myblog', # 数据库名
'USER': 'root', # 登陆用户,这里图省事,项目中需建专门用户且明确权限
'PASSWORD': '', # 密码
'HOST': '127.0.0.1', # 因为装在本地了,如果你有云服务器且开了外网可以写远程地址
'PORT': '3306', # 端口,跟前面my.ini中一样,一般为3306
}
}

现在到了选择模块的时候了,分别说下两种情况。

使用pymysql

使用pymysql比较简单,首先pip安装下(安装完记得cmd中输入python,然后import pymysql看看是否成功)

1
pip install pymysql

安装好了之后,由于 Django默认用MySQLdb,需要引入到项目里去。

在项目目录下的init.py文件中写(跟setting.py在同一层)

1
2
import pymysql
pymysql.install_as_MySQLdb()

这样就算是配置完成了。

使用MySQLdb

(PS: 以下是windows平台安装方法,如果是linux或者osx,自求多福吧,不能只让我一个人蛋疼…..)

先下载安装下mysql-connector

https://dev.mysql.com/downloads/connector/python/

下载windows平台下第一个安装好。

手动安装MySQL-python

https://pypi.org/project/MySQL-python/](https://pypi.org/project/MySQL-python/)

下载最新版本

解压,然后进入解压后的目录

1
python setup.py install

安装完成后记得打开cmd, import MySQLdb试试有没有报错。

Mysql使用

生成auth模块依赖表

如要使用auth模块,得先生成相关的表。由于模块已经写好了语句,直接执行migrate即可。(如果是要将你自定义的model在mysql生成,得先执行makemigrations)

1
python manage.py migrate

可以看到结果

image.png

再去看数据库

image.png

可以看到表均已生成,接下来照常使用即可。

后续若有新增表或更改表结构的方式,通过执行SQL语句来完成,就不要在创建和修改model了。

在代码中使用

虽然前面说了两个模块,不过这都跟你在代码里使用无关,只是因为如果你有model需要生成table,涉及到移植或者要使用auth模块的,那么第三步准备工作你是必须要做好的。

如果仅仅是代码里使用,就随你了,也有其他模块可以使用,这里说说pymysql。

例如查询和增删改操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# coding: utf8
import pymysql

class OperateMysql:
def __init__(self, conf):
self.conn = self.create_conn(conf)

def create_conn(self, section):
try:
conn = pymysql.connect(section['host'], section['username'], section['password'], section['database'])
except Exception as e:
raise Exception("Connect Error %d: %s" % (e.args[0], e.args[1]))
return conn

def choose_database_info(self, env):
if env == 'test':
key = 'testEnv'
elif env == 'trail':
key = 'trailEnv'
elif env == 'prod':
key = 'prodEnv'
else:
raise 'No this environment as %s' % env
getconfig = GetConfig('database.ini') # 自己写一个读取ini格式的方法
section = getconfig.getsection(key)
return section

def close(self, cur, conn):
cur.close()
conn.close()

"""查找语句"""

def select(self, sql):
sql = str(sql)
cur = self.conn.cursor()
try:
cur.execute(sql)
results = cur.fetchall()
except Exception as e:
self.close(cur, self.conn)
raise Exception("Mysql Error %d: %s" % (e.args[0], e.args[1]))
self.close(cur, self.conn)
return results

"""增删改都是调用excute写在一个里面"""

def modifiy(self, sql):
sql = str(sql)
cur = self.conn.cursor()
try:
cur.execute(sql)
self.conn.commit()
except Exception as e:
# 发生错误先回滚,再抛出异常
self.conn.rollback()
self.conn.commit()
self.close(cur, self.conn)
raise Exception("Mysql Error %d: %s" % (e.args[0], e.args[1]))
self.close(cur, self.conn)


if __name__ == '__main__':
conf = {"host": "", "port": "", "username": "", "password": "", "database": ""}
OP = OperateMysql(conf)
res = OP.select('SELECT * from ts_storage_partinfo_order_batch LIMIT 1')
print(res)

使用线程池

在上面的基础上,我们使用线程池,作用是为了让线程吃来统一管理线程数,把一些失效或超时线程关闭,节约线程数的使用,释放资源。

安装DBUtils

1
pip install DBUtils

使用PooledDB管理pymysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# coding: utf-8
import pymysql
from DBUtils.PooledDB import PooledDB

class OperateSqlite:

def __init__(self, conf):
self.pool = PooledDB(pymysql, maxcached=50, maxconnections=1000, maxusage=1000, **conf)

def select(self, sql, dict_mark=False):
result = []
conn = self.pool.connection()
cur = conn.cursor()
try:
if dict_mark:
cur.execute(sql)

fields = [desc[0] for desc in cur.description]
rst = cur.fetchall()
if rst:
result = [dict(zip(fields, row)) for row in rst]
else:
cur.execute(sql)
result = cur.fetchall()
except Exception as e:
raise Exception("Mysql Error %d: %s" % (e.args[0], e.args[1]))
finally:
cur.close()
conn.close()
return result

def excute(self, sql):
result = []
conn = self.pool.connection()
cur = conn.cursor()
try:
cur.execute(sql)
result = cur.row_factory()
except Exception as e:
raise Exception("Mysql Error %d: %s" % (e.args[0], e.args[1]))
finally:
cur.close()
conn.close()
return result


conf = {"host": "127.0.0.1", "port": "3306", "user": "root", "passwd": "", "db": ""}
op = OperateSqlite(conf)


if __name__ == "__main__":
sql = "select * from table limit 1"
res = op.select(sql)
print(res)

PooledDB的参数:

mincached,最少的空闲连接数,如果空闲连接数小于这个数, pool会创建一个新的连接 maxcached,最大的空闲连接数,如果空闲连接数大于这个数,pool会关闭空闲连接maxconnections,最大连接数 blocking,当连接数达到最大的连接数时,在请求连接的时候,如果这个值是True,请求连接的程序会一直等待,直到当前连接数小于最大连接数,如果这个值是False,会报错。 maxshared 当连接数达到这个数,新请求的连接会分享已经分配出去的连接

使用ORM

上面操作数据库都是执行的sql,这样语句多了以后,是不太好管理的,且存在被sql注入的风险,sql和代码在一个py文件中,修改sql有误也不大能看出错误,综上引入 orm的概念,把数据库的表结构映射为代码可以识别的对象,像写代码一样来操作数据库。 首先按照setting.py配置好要连接的mysql数据库,执行

1
python manage.py inspectdb

将会打印即将要生成的类文件

image.png

简单检查下,若全都无误,再写入到models.py文件去。

1
python manage.py inspectdb > models.py

后续的使用就跟初学django教导的操作model一样,想注册到admin也可以注册。

评论