终于把基本的数据库组织结构学的差不多啦,上午拖着需要补充的市场数据,测试导入数据!
python3使用pymysql模块连接InnoDB数据库,连接过程中需要用户名密码,可是明文密码再上传github这是找死,决定研究下简单的加密解密过程,从外部读取密文,再decode后给入。
加密算法分对称加密和非对称加密。对称加密很好理解,就是经典的凯撒密码的套路,采用同样的密钥加密和解密(字幕平移法则)。
DES是经典的对称加密算法,64bits为单位然后套轮函数循环,但是DES目前已经被攻破,三重DES(密钥1加密,密钥2解密,密钥3加密)还有应用价值。 AES是取代DES的算法,具体步骤为替换(SubBytes),ShiftRows(平移),MixColumns(混列),最后AddRoundKey(与原数据异或)。此为一轮AES。 如果采用对称加密,推荐AES算法。
公钥加密是密码学领域非常牛逼的技术,即加密密钥和解密密钥可以不同,这样可以避免密钥配送过程中的风险。公钥丢失也不怕,神不神奇?
比如用户浏览器和server之间非对称加密过程可以是这样:server给公钥,用户用公钥加密,将密文给server(公钥、密文都被窃取也无法获得明文),server将密文用私钥解密。 经典非对称加密算法RSA。其数学原理在阮一峰的网站有介绍。不再赘述。
以我们的应用情景来说,因为不涉及通讯,直接AES对称加密即可。
构建如下类解决:
class AESCipher(object):
def __init__(self, key):
self.bs = 32
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s)-1:])]
Updated 2018-03-12
今天打算创建Mercurius的数据库,神奇的是,输入create database后报错
ERROR 1006 (HY000): Can’t create database ‘mercurius’ (errno: 28)
换了root账户也不行,查到的信息都是说mysql的数据库权限问题,检查后的确木有问题呀。 注意到google出的关键词errno号不同,很多13号,而我是28号,深度搜索了一番,找到了答案:
This error means that your mysql server does not have enough free space. You need to check the file system size and please remove unwanted software(s) or installers or files.
我去,坑我?磁盘满额?df查看一下,果然/根目录满额。奇怪~
利用find找大文件:
find / -size +800M
发现除了最早丢过来的安装包,就是gdm的log最大,cd过去一看,可了不得,13G的log,应该是图形界面出错后一直在写error,写到了3月5日,果断删掉~并且把安装包移走。目前解决,后面看是否还继续写log。
慎重起见,将mysql的数据库路径进行迁移,然后发现进了个大坑。无论怎样按照网上的步骤调整,都会遇到mysqld服务无法打开的结果。甚至rsync数据库然后做链接都不行。 折腾了一下午,突然想到,不就是把mercurius数据库拿出来么,不动mysql本身的账户库还不行。好吧,最后给mercurius做了链接搞定,要注意所在的上层目录必须有root用户和用户组的读写权限。
Updated 2018-03-11
常用命令
show databases;
create database test;
use test;
select database(); # show what is the selected database
drop database if exists test;
建立好数据库之后,则可以开始建立tables啦,这个过程中需要有一些数据库的设计思路,大概是列出各种table,如下图:
然后我们仿照视频教程建立一个存储学生数据的table
mysql> create table student(
-> first_name varchar(30) not null,
-> last_name varchar(30) not null,
-> email varchar(60) null,
-> street varchar(50) not null,
-> city varchar(40) not null,
-> state char(2) not null default "PA",
-> zip mediumint unsigned not null,
-> phone varchar(20) not null,
-> birth_date date not null,
-> sex enum('M', 'F') not null,
-> date_entered timestamp,
-> lunch_cost float null,
-> student_id int unsigned not null auto_increment primary key);
解释一下各关键词:
varchar代表可变长度的string,not null表示不能是空值;
state因为只有两个字母,所以,强制要求char(2),并且给了default值为PA。mediumint有意思,查了一下,发现mysql提供非常多种类的数据类型,估计是考虑到数据库的空间利用效率的原因。 我们总结一下数据类型:
CHAR fixed length character string
VARCHAR a character string with a length that is variable
BLOB contain 2^16 bytes of data
BIGINT 2^63 to -2^63-1
FLOAT decimal spaces 1.1e38 to -1.1e38
DOUBLE decimal spaces, 1.7e308 to -1.7e308
ENUM A character stirng that has a limited number of total values, which you must define
SET (Seldom used) A set of legal possible character strings. Unlike ENUM, a SET can contain a multiple values in comparason to the one legal value with ENUM.
DATE YYYY-MM-DD
TIME HH:MM:SS
DATETIME YYYY-MM-DD HH:MM:SS
TIMESTAMP YYYYMMDDHHMMSS
YEAR YYYY
unsigned 表示非负值。
sex的enum非常清楚了,只有两个选项。
注意入学时间,用的timestamp类型,可以看到数据库软件本身提供了非常体贴的类型,不需要自己parser date string啦。
最后一个student id,被定义为主键。
然后我们看一下student中的情况
describe student;
+--------------+-----------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+-------------------+-----------------------------+
| first_name | varchar(30) | NO | | NULL | |
| last_name | varchar(30) | NO | | NULL | |
| email | varchar(60) | YES | | NULL | |
| street | varchar(50) | NO | | NULL | |
| city | varchar(40) | NO | | NULL | |
| state | char(2) | NO | | PA | |
| zip | mediumint(8) unsigned | NO | | NULL | |
| phone | varchar(20) | NO | | NULL | |
| birth_date | date | NO | | NULL | |
| sex | enum('M','F') | NO | | NULL | |
| date_entered | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| lunch_cost | float | YES | | NULL | |
| student_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+--------------+-----------------------+------+-----+-------------------+-----------------------------+
查看table中field值的方法:
select first_name from student;
可以用逗号隔开多个fields。 清空数据表
truncate student;
注意truncate和drop的区别,drop直接将table从database拿掉,truncate仅仅是清空field的content。 我们总结一下层级关系
databases
tabels
fields
field rows (contents)
向student table中插入一条数据记录
mysql> insert into student value
-> ('Dennis', 'Lee', 'dcooper@aol.com', '123 Main St', 'Yakima', 'WA', 95294, '510-365-0383', '1995-2-22', 'M', now(), 3.50, null);
查看加入的数据记录
slect * from student;
Foreign Key的概念
表A中的Primary Key,出现在表B中,则为Foreign Key,可为空值,可重复出现。
如果要对已有的表增加一条数据属性,使用alter table语句
mysql> alter table test
-> add maxscore int not null after type;
describe test;
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| date | date | NO | | NULL | |
| type | enum('T','Q') | NO | | NULL | |
| maxscore | int(11) | NO | | NULL | |
| class_id | int(10) unsigned | NO | | NULL | |
| test_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+----------+------------------+------+-----+---------+----------------+
改变已有的数据表中的Field名,
mysql> alter table score change event_id test_id
-> int unsigned not null;
Updated 2018-03-08