Python操作三大數(shù)據(jù)庫 - MySQL數(shù)據(jù)庫(Part2)

1. MySQL的基本操作

1.1 介紹

  1. 數(shù)據(jù)添加
    INSERT語法猜欺、INSERT方言語法涧黄、INSERT子查詢、IGNORE關(guān)鍵字春宣。
  2. 數(shù)據(jù)修改
    UPDATE語法、UPDATE表連接
  3. 數(shù)據(jù)刪除
    DELETE語法、DELETE表連接

1.2 數(shù)據(jù)插入操作

  1. INSERT語句
    INSERT語句可以向數(shù)據(jù)表寫入記錄簸搞,可以是一條記錄,也可以是多條記錄。
    INSERT INTO 表名(字段1,字段2, ...) VALUES(值1,值2,...);
    INSERT INTO 表名(字段1,字段2, ...) VALUES(值1,值2,...), (值1,值2,...);
    例如:向部門表插入新的部門
INSERT INTO t_dept(deptno, dname, loc)
VALUES(50, "技術(shù)部", "北京");

INSERT INTO t_dept(deptno, dname, loc)
VALUES(60, "后勤部", "北京"), (70, "保安部", "北京");

注意:不聲明字段名稱也可以寫入數(shù)據(jù)沽讹,不過會(huì)降低寫入效率。

  1. INSERT插入字段可以有子查詢,但子查詢的結(jié)果必須是單行記錄乘盖,并且子查詢返回的字段必須只有一個(gè)。
    例如:向技術(shù)部添加一名員工記錄
INSERT INTO t_emp
(empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES(8081, "劉娜", "SALESMAN", 8000, "1988-12-21", 2000, NULL, 
(SELECT deptno FROM t_dept  WHERE dname = "技術(shù)部"));
  1. INSERT語句方言
    方言:只能在MySQL數(shù)據(jù)庫上執(zhí)行的SQL語法,不具備通用性衩侥。
    INSERT [INTO] 表名 SET 字段1=值1, 字段2=值2, ...;
    其中,INTO關(guān)鍵字可以省略峦萎。
INSERT INTO t_emp 
SET empno=8002, ename="Jake", job="SALESMAN", mgr=8000,
hiredate="1985-12-21",sal=2500,comm=NULL, deptno=50;
  1. IGNORE關(guān)鍵字
    插入多條數(shù)據(jù)時(shí)雄卷,如果與現(xiàn)有的記錄產(chǎn)生主鍵沖突或唯一值沖突,寫入報(bào)錯(cuò)揣钦,導(dǎo)致一條記錄也寫不進(jìn)去。使用IGNORE關(guān)鍵字會(huì)讓INSERT忽略沖突的數(shù)據(jù),只插入沒有沖突的數(shù)據(jù)。
    INSERT [IGNORE] INTO 表名 ...;
INSERT INTO t_dept(deptno, dname, loc)
VALUES(60, "A", "北京"), (80, "B", "上海");
-- 1062 - Duplicate entry '60' for key 'PRIMARY', Time: 0.012000s

INSERT IGNORE INTO t_dept(deptno, dname, loc)
VALUES(60, "A", "北京"), (80, "B", "上海");
-- Affected rows: 1, Time: 0.036000s

1.3 數(shù)據(jù)更新操作

  1. UPDATE語句
    UPDATE [IGNORE] 表名 SET 字段1=值1, 字段2=值2,...
    [WHERE 條件1 ...] [ORDER BY ...] [LIMIT ...];
    注意:UPDATE中的LIMIT子句只能寫一個(gè)參數(shù)LIMIT N鸽扁。不可以寫LIMIT N M巩那。
  2. 數(shù)據(jù)更新練習(xí)
    (1) 把每個(gè)員工的編號(hào)和上司的編號(hào)+1,使用ORDER BY子句完成
UPDATE t_emp 
SET empno=empno+1, mgr=mgr+1 
ORDER BY empno DESC;

注意:需要使用ORDER BY子句降序,否則在+1的時(shí)候可能發(fā)生主鍵沖突。
(2) 把月收入前3名的員工底薪減100元璃吧,用LIMIT子句完成

UPDATE t_emp 
SET sal = sal - 100
ORDER BY sal + IFNULL(comm,0) DESC
LIMIT 3;

(3) 把10部門中巴元,工齡超過20年的員工修己,底薪增加200戴涝。

UPDATE t_emp 
SET sal = sal + 200
WHERE deptno = 10 AND DATEDIFF(NOW(),hiredate) / 365 > 20;
  1. UPDATE語句的表連接
    例如:把ALLEN調(diào)往RESEARCH部門奸鸯,職務(wù)調(diào)整為ANALYST

(1) 相關(guān)子查詢寫法,效率非常低扬虚。

UPDATE t_emp
SET deptno = (SELECT deptno FROM t_dept WHERE dname = 'RESEARCH'),
job = 'ANALYST'
WHERE ename = 'ALLEN';

(2) 使用表連接來改造UPDATE語句
語法1:UPDATE 表1 JOIN 表2 ON 條件 SET 字段1=值1, 字段2=值2, ...;
語法2:UPDATE 表1, 表2 WHERE 條件 SET 字段1=值1, 字段2=值2, ...;
表連接的UPDATE語句可以修改多張表的記錄。

UPDATE t_emp e 
JOIN t_dept d
SET e.deptno  = d.deptno, e.job = 'ANALYST', d.loc='北京'
WHERE e.ename = 'ALLEN' AND d.dname = 'RESEARCH';

注釋:①JOIN表連接并沒有寫ON連接條件。②同時(shí)修改了兩張表的數(shù)據(jù)。

  1. 數(shù)據(jù)更新和數(shù)據(jù)刪除時(shí)不推薦使用子查詢的原因
    (1) 子查詢效率低
    (2) 不允許對(duì)要更新或刪除的數(shù)據(jù)做子查詢
  2. 把底薪低于公司平均底薪的員工坎匿,帶薪增加150
UPDATE t_emp e1 
JOIN (SELECT AVG(sal) avg FROM t_emp) s
ON e1.sal < s.avg
SET e1.sal = e1.sal + 150;
  1. UPDATE語句的表連接既可以是內(nèi)連接侥锦,又可以是外連接
    例如:把沒有部門的員工,或者SALES部門低于2000元底薪的員工,都調(diào)到20部門玄柏。
UPDATE t_emp e
LEFT JOIN t_dept d
ON e.deptno = d.deptno   
SET e.deptno = 20
WHERE e.deptno IS NULL OR (d.dname = 'SALES' AND e.sal < 2000);

注釋:① 判斷是否是NULL-IS NULL绍坝。② 如果不使用LEFT JOIN椎咧,則取不到?jīng)]有部門的員工蟋座。

1.4 數(shù)據(jù)刪除

  1. DELETE語句用于刪除記錄
    DELETE [IGNORE] FROM 表名 [WHERE 條件1, 條件2...] [ORDER BY ...] [LIMIT ...];
    子句執(zhí)行順序:FROM > WHERE > ORDER BY > LIMIT > DELETE
  2. DELETE語句練習(xí)
    (1) 刪除10部門中莫矗,工齡超過20年的員工記錄
DELETE FROM t_emp
WHERE deptno = 10 AND DATEDIFF(NOW(),hiredate) / 365 >= 20;

(2) 刪除20部門中工資最高的員工記錄

DELETE FROM t_emp 
WHERE deptno = 20 
ORDER BY sal + IFNULL(comm,0) DESC 
LIMIT 1;
  1. DELETE語句的表連接
    WHERE語句中寫子查詢的效率很低三娩,我們可以使用表連接改造DELETE語句眨唬。
    DELETE 表1, ... FROM 表1 JOIN 表2 ON 條件
    [WHERE 條件1, 條件2...] [ORDER BY ...] [LIMIT ...];
  2. DELETE語句表連接聯(lián)系
    (1) 刪除SALES部門和該部門的全體員工記錄
DELETE e, d FROM t_emp e JOIN t_dept d 
ON e.deptno = d.deptno
WHERE d.dname = 'SALES';

(2) 刪除每個(gè)低于部門平均底薪的員工記錄

DELETE e FROM t_emp e
JOIN (SELECT deptno, AVG(sal) sal FROM t_emp GROUP BY deptno) g
ON e.deptno = g.deptno
WHERE e.sal < g.sal;

(3) 刪除員工KING和他直接下屬的員工記錄瓦宜,用表連接實(shí)現(xiàn)

-- 表連接寫法1
DELETE e1, e2 FROM t_emp e1 JOIN t_emp e2
ON e1.ename = 'KING' AND e1.empno = e2.mgr;

--表連接寫法2
DELETE e1 FROM t_emp e1
JOIN (SELECT empno FROM t_emp WHERE ename = 'KING') e2
ON e1.mgr = e2.empno OR e1.ename = 'KING';
  1. DELETE語句的表連接既可以是內(nèi)連接昵慌,又可以是外連接
    例如:刪除SALES部門的員工以及沒有部門的員工
DELETE e FROM t_emp e 
LEFT JOIN t_dept d
ON e.deptno = d.deptno
WHERE d.dname = 'SALES' OR e.deptno IS NULL;
  1. 快速清空數(shù)據(jù)表中所有記錄
    DELETE語句是在事務(wù)機(jī)制下刪除記錄已卷,刪除記錄之前鹉梨,先把將要?jiǎng)h除的記錄保存到日志文件里析桥,然后再刪除記錄埋虹。
    TRUNCATE語句在事務(wù)機(jī)制之外刪除記錄截亦,速度遠(yuǎn)超DELETE語句却桶。
    語法:TRUNCATE TABLE 表名;
TRUNCATE TABLE t_emp;

1.5 總結(jié)

  1. 技能清單
    掌握INSERT語法
    掌握UPDATE語法
    掌握DELETE語法
    掌握數(shù)據(jù)更新和刪除中的表連接語法
  2. 知識(shí)體系
    初識(shí)數(shù)據(jù)庫:MySQL安裝與使用
    DDL階段:管理數(shù)據(jù)庫與數(shù)據(jù)表
    DML階段:數(shù)據(jù)的增刪改查

2. MySQL基本函數(shù)的使用

2.1 介紹

  1. 學(xué)習(xí)目標(biāo)
    (1) 數(shù)字函數(shù)
    FORMAT颖系、ABS嗅剖、MODCEIL嘁扼、FLOOR信粮、ROUND趁啸、EXP...
    (2) 字符函數(shù)
    UPPER强缘、LOWERCHAR_LRNGTH莲绰、CONCATINSTR...
    (3) 日期函數(shù)&條件函數(shù)
    NOW姑丑、DATE_FORMAT蛤签、DATE_ADDDATEDIFF栅哀、IF震肮、IFNULL...

2.2 MySQL基本函數(shù)

  1. MySQL的函數(shù)
    數(shù)字函數(shù)、字符函數(shù)留拾、日期函數(shù)戳晌、條件函數(shù)
  2. 數(shù)字函數(shù)
函數(shù) 功能 用例
ABS 絕對(duì)值 ABS(-100)
ROUND 四舍五入 ROUND(4.62)
FLOOR 向下取整 FLOOR(9.9)
CEIL 向上取整 CEIL(3.2)
POWER 冪函數(shù) POWER(2,3)
LOG 對(duì)數(shù)函數(shù) LOG(7, 3)
LN 求對(duì)數(shù)函數(shù)(以e為底數(shù)) LN(10)
SELECT ABS(-100); # 100
SELECT ROUND(4.6288 * 100) / 100; # 4.6300
SELECT FLOOR(9.9); # 9
SELECT CEIL(3.2); # 4
SELECT POWER(2, 3); # 8
SELECT LOG(7, 3); # 0.5645750340535797
SELECT LN(10); # 2.302585092994046
函數(shù) 功能 用例
SQRT 開平方 SQRT(9)
PI 圓周率 PI()
SIN 正弦 SIN(1)
COS 余弦 COS(1)
TAN 正切 TAN(1)
COT 余切 COT(1)
RADIANS 角度轉(zhuǎn)換弧度 RADIANS(30)
DEGREES 弧度轉(zhuǎn)換角度 DEGREES(1)
SELECT SQRT(9); # 3
SELECT PI(); # 3.141593
SELECT SIN(RADIANS(30)); # 0.49999999999999994
SELECT COS(RADIANS(45)); # 0.7071067811865476
SELECT TAN(RADIANS(35)); # 0.7002075382097097
SELECT COT(RADIANS(45)); # 1.0000000000000002
SELECT DEGREES(1); # 57.29577951308232
  1. 獲取系統(tǒng)時(shí)間函數(shù)
    NOW()- 獲取當(dāng)前系統(tǒng)日期和時(shí)間,格式為yyyy-MM-dd hh:mm:ss
    CURDATE()- 獲取當(dāng)前系統(tǒng)日期痴柔,格式為yyyy-MM-dd
    CURTIME() - 獲取當(dāng)前系統(tǒng)時(shí)間沦偎,格式為hh:mm:ss
SELECT NOW(), CURDATE(), CURTIME();
2020-01-01 10:59:43  2020-01-01     10:59:43
  1. 日期格式化函數(shù)
    DATE_FORMAT() - 用于格式化日期
占位符 作用 占位符 作用
%Y 年份 %m 月份
%d 日期 %w 星期(數(shù)字)
%W 星期(名稱) %j 本年第幾天
%U 本年第幾周 %H 小時(shí)(24)
%h 小時(shí)(12) %i 分鐘
%s %r 時(shí)間(24)
%T 時(shí)間(12)
-- 查詢明天你的生日是星期幾。
SELECT DATE_FORMAT('2020-04-05', '%w - %W') #0 - Sunday

-- 查詢1981年上半年入職的員工有多少人
SELECT COUNT(*) FROM t_emp
WHERE DATE_FORMAT(hiredate, "%Y") = 1981
AND DATE_FORMAT(hiredate, "%m") <=6; # 5

注釋:數(shù)據(jù)庫中支持的最小的時(shí)間單位是秒,而不是毫秒豪嚎。

  1. 日期偏移計(jì)算
    DATE_ADD() - 可以實(shí)現(xiàn)日期偏移計(jì)算搔驼。
    格式:DATE_ADD(日期, INTERVAL 偏移量 時(shí)間單位)
SELECT 
NOW(),
DATE_ADD(NOW(),INTERVAL 15 DAY) d1,
DATE_ADD(NOW(),INTERVAL -300 MINUTE) d2,
DATE_ADD(DATE_ADD(NOW(), INTERVAL -2 MONTH), INTERVAL -3 DAY) d3;
# 2020-01-01 11:31:28   2020-01-16 11:31:28 2020-01-01 06:31:28 2019-10-29 11:31:28

注釋:在MySQL數(shù)據(jù)庫中,兩個(gè)日期不能直接加減侈询,日期也不能與數(shù)字加減舌涨。

  1. 日期差值
    DATEDIFF() - 計(jì)算兩個(gè)日期之間相差的天數(shù)。
SELECT DATEDIFF(NOW(),DATE_ADD(NOW(),INTERVAL -1 MONTH)); # 31
  1. 字符函數(shù)
函數(shù) 功能 用例
LOWER 轉(zhuǎn)換為小寫 LOWER(ename)
UPPER 轉(zhuǎn)換為大寫 UPPER(ename)
LENGTH 字符數(shù)量 LENGTH(ename)
CONCAT 連接字符串 CONCAT(sal, "$")
INSTR 字符出現(xiàn)的位置 INSTR(ename, "A")
INSERT 插入/替換字符串 INSERT("你好", 1, 0, "先生")
REPLACE 替換字符 REPLACE("你好先生", "先生", "女士")
SELECT LOWER(ename), UPPER(ename), LENGTH(ename), 
CONCAT(sal, '$'), INSTR(ename,'A') FROM t_emp;
-- ...
-- allen    ALLEN   5   1600.00$    1

SELECT INSERT('你好', 1, 0, '先生'); # 先生你好
SELECT INSERT('你好', 1, 1, '先生'); # 先生好
SELECT REPLACE('你好先生', '先生', '女士'); # 你好女士
函數(shù) 功能 用例
SUNSTR 截取字符串 SUNSTR('你好世界', 3, 4)
SUNSTRING 截取字符串 SUNSTRING('你好世界', 3, 2)
LPAD 左側(cè)填充字符 LPAD('Hello', 10, '*')
RPAD 右側(cè)填充字符 RPAD('Hello', 10, '*')
TRIM 去除首尾空格 TRIM(' 你好先生 ')
SELECT SUBSTR('你還世界',3, 4); # 世界
SELECT SUBSTRING('你好世界', 3, 2); # 世界
SELECT LPAD(SUBSTRING('12345678901',8,4),11,'*'); # *******8901
SELECT RPAD(SUBSTRING('李曉娜', 1, 1),LENGTH('李曉娜') / 3,'*'); # 李**
SELECT TRIM('    Hello World!  ') #Hello World!
  1. 條件函數(shù)
    SQL語句中可以利用條件函數(shù)來實(shí)現(xiàn)編程語言里的條件判斷扔字。
    IFNULL(表達(dá)式, 值)
    IF(表達(dá)式, 值1, 值2)
    例如:中秋節(jié)公司員工發(fā)放禮品囊嘉,SALES部門發(fā)放禮品A, 其余部門發(fā)放禮品B, 打印每個(gè)員工獲得的禮品。
SELECT e.ename, d.dname,  IF(d.dname = 'SALES', '禮品A', '禮品B')
FROM t_emp e 
JOIN t_dept d 
ON e.deptno = d.deptno;
  1. 復(fù)雜條件判斷
    公司年慶決定組織員工集體旅游革为,每個(gè)部門旅游目的地不同扭粱。SALES部門去P1地點(diǎn),ACCOUNTING部門去P2地點(diǎn)篷角,RESEARCH部門去P3地點(diǎn)焊刹,查詢每名員工的旅行地點(diǎn)。
SELECT 
e.ename, d.dname,
CASE d.dname
    WHEN 'SALES' THEN 'P1'
    WHEN 'ACCOUNTING' THEN 'P2'
    WHEN 'RESEARCH' THEN 'P3'
END AS place
FROM t_emp e
JOIN t_dept d
ON e.deptno = d.deptno
  1. 薪資調(diào)整方案
    (1) SALES部門中工齡超過20年恳蹲,漲10%虐块。
    (2) SALES部門中工齡不滿20年,漲5%嘉蕾。
    (3) ACCOUNTING部門贺奠,漲300
    (4) RESEARCH部門里低于部門平均底薪错忱,漲200儡率。
    (5) 沒有部門的員工,漲100以清。
UPDATE t_emp e LEFT JOIN t_dept d ON e.deptno = d.deptno
LEFT JOIN (SELECT deptno, AVG(sal) avg FROM t_emp GROUP BY deptno) g
ON e.deptno = g.deptno
SET e.sal = (
    CASE
      WHEN d.dname = 'SALES' AND DATEDIFF(NOW(),e.hiredate) / 365 >= 20 THEN e.sal * 1.1
        WHEN d.dname = 'SALES' AND DATEDIFF(NOW(),e.hiredate) / 365 < 20 THEN e.sal * 1.05
        WHEN d.dname = 'ACCOUNTING' THEN e.sal + 300
        WHEN d.dname = 'RESEARCH' AND e.sal < g.avg THEN e.sal + 200
        WHEN e.deptno IS NULL THEN e.sal + 100
        ELSE e.sal
    END
);

2.3 總結(jié)

  1. 技能清單
    熟練運(yùn)用數(shù)字函數(shù)儿普。
    熟練運(yùn)用字符函數(shù)。
    熟練運(yùn)用日期函數(shù)掷倔。
    熟練運(yùn)用條件函數(shù)眉孩。

3. MySQL的綜合應(yīng)用

3.1 介紹

  1. 數(shù)據(jù)庫事務(wù)機(jī)制
    undoredo日志、開啟事務(wù)勒葱、提交事務(wù)浪汪、回滾事務(wù)
  2. 數(shù)據(jù)的導(dǎo)出和導(dǎo)入
    SQL文件的導(dǎo)入和導(dǎo)出、TXT文檔的導(dǎo)入與導(dǎo)出
  3. 綜合案例:設(shè)計(jì)數(shù)據(jù)表
    設(shè)計(jì)新聞管理系統(tǒng)的數(shù)據(jù)表凛虽。

3.2 MySQL數(shù)據(jù)庫的事務(wù)機(jī)制

  1. 事務(wù)概念
    SQL語句直接操作數(shù)據(jù)文件是很危險(xiǎn)的死遭。
    MySQL5種日志,其中redo日志和undo地址與事務(wù)有關(guān)凯旋。
    image.png
  2. 事務(wù)機(jī)制(Transaction)
    RDBMS(關(guān)系數(shù)據(jù)庫) = SQL語句 + 事務(wù)(ACID)
    事務(wù)是一個(gè)或者多個(gè)SQL語句組成的整體呀潭,要么全部執(zhí)行成功钉迷,要么全部執(zhí)行失敗。
  3. 管理事務(wù)
    默認(rèn)情況下蜗侈,MySQL執(zhí)行每條SQL語句都會(huì)自動(dòng)開啟和提交事務(wù)篷牌。
    我們可以手動(dòng)管理事務(wù),讓多條SQL語句納入到一個(gè)事務(wù)之中踏幻。
START TRANSACTION;
SQL語句
[COMMIT | ROLLBACK];
START TRANSACTION;
DELETE FROM t_emp;
DELETE FROM t_dept;
SELECT COUNT(*) FROM t_emp; # 0
SELECT COUNT(*) FROM t_dept; # 0
COMMIT;
-- ROLLBACK;

注意:COMMIT語句執(zhí)行之前雖然查到的數(shù)據(jù)集合數(shù)目為0枷颊。但此時(shí)是在redo文件中查到的結(jié)果,真實(shí)數(shù)據(jù)庫里數(shù)據(jù)還沒有被刪除该面,直到執(zhí)行COMMIT語句夭苗。

  1. 事務(wù)的ACID屬性
    (1) 原子性
    一個(gè)事務(wù)中的所有操作要么全部完成,要么全部失敗隔缀。事務(wù)執(zhí)行后题造,不允許停留在中間某個(gè)狀態(tài)。
    (2) 一致性
    不管在任何給定的時(shí)間猾瘸、并發(fā)事務(wù)有多少界赔,事務(wù)必須保證運(yùn)行結(jié)果的一致性。
    (3) 隔離性
    隔離性要求事務(wù)不受其他并發(fā)事務(wù)的影響牵触,如同在給定的時(shí)間內(nèi)淮悼,該事務(wù)是數(shù)據(jù)庫唯一運(yùn)行的事務(wù)。
    例如:默認(rèn)情況下揽思,A事務(wù)只能看到日志中該事務(wù)的相關(guān)數(shù)據(jù)袜腥。
    (4) 持久性
    事務(wù)一旦提交,結(jié)果便是永久性的钉汗。即便發(fā)生宕機(jī)羹令,仍然可以依靠事務(wù)日志完成數(shù)據(jù)的持久化。
  2. 事務(wù)的四個(gè)隔離級(jí)別
序號(hào) 隔離級(jí)別 功能
1 read uncommitted 讀取未提交數(shù)據(jù)
2 read committed 讀取已提交數(shù)據(jù)
3 repeatable read 重復(fù)讀取
4 serializable 序列化

注釋:默認(rèn)隔離級(jí)別為repeatable read损痰。

  1. 買票事務(wù)案例


    image.png
-- 查詢面板1 
START TRANSACTION;
UPDATE t_emp SET sal = 1;
-- 查詢面板2
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 設(shè)置當(dāng)前會(huì)話事務(wù)隔離級(jí)別:允許讀取其他事務(wù)未提交數(shù)據(jù)福侈。
START TRANSACTION;
SELECT empno, ename, sal FROM t_emp;
COMMIT;
-- 7369 SMITH   1.00
-- 7499 ALLEN   1.00
-- 7521 WARD    1.00

注釋:①一個(gè)查詢面板就是一個(gè)SESSION會(huì)話。②isolation隔離卢未。

  1. 轉(zhuǎn)賬事務(wù)案例


    image.png
-- 查詢面板1
START TRANSACTION;
UPDATE t_emp SET sal = 1;
-- 查詢面板2
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 設(shè)置當(dāng)前會(huì)話事務(wù)隔離級(jí)別:允許讀取其他事務(wù)已提交數(shù)據(jù)
START TRANSACTION;
SELECT empno, ename, sal FROM t_emp;
COMMIT;
-- 7369 SMITH   800.00
-- 7499 ALLEN   1600.00
-- 7521 WARD    1250.00
  1. 購物案例
    image.png

    REPEATABLE READ代表事務(wù)在執(zhí)行中反復(fù)讀取數(shù)據(jù)肪凛,得到的結(jié)果是一致的,不受其他事務(wù)的影響尝丐。
-- 查詢面板1
START TRANSACTION;
UPDATE t_emp SET sal = 1;
COMMIT;
--查詢面板2
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT empno, ename, sal FROM t_emp;
COMMIT;

注意:事務(wù)執(zhí)行SELECT語句之后显拜,數(shù)據(jù)才會(huì)保存到undo日志衡奥,之后的查詢結(jié)果才不受其他事務(wù)對(duì)數(shù)據(jù)的修改影響爹袁。

  1. 事務(wù)的序列化
    由于事務(wù)并發(fā)執(zhí)行所帶來的的各種問題,前三種隔離級(jí)別只適用于某些業(yè)務(wù)場(chǎng)景中矮固。序列化隔離失息,讓事務(wù)逐一執(zhí)行譬淳,就不會(huì)產(chǎn)生上述問題了。
    該隔離級(jí)別犧牲了事務(wù)的并發(fā)性盹兢,很少使用邻梆。
-- 查詢面板1
START TRANSACTION;
UPDATE t_emp SET sal = 1;
COMMIT;
--查詢面板2
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT empno, ename, sal FROM t_emp;
COMMIT;

3.3 數(shù)據(jù)的持久化

  1. 數(shù)據(jù)導(dǎo)出與備份的區(qū)別
    數(shù)據(jù)導(dǎo)出:導(dǎo)出的只是數(shù)據(jù)文件。
    數(shù)據(jù)備份:備份的是數(shù)據(jù)文件绎秒、日志文件浦妄、索引文件等。
  2. 數(shù)據(jù)導(dǎo)出分類
    SQL文件见芹、文本文件
  3. 導(dǎo)出SQL文件

(1) 命令行語法
mysqldump -uroot -p [no-data] 邏輯庫 > 路徑

?  ~ mysqldump -uroot -p demo > /Users/nimengwei/downloads/demo.sql 
Enter password: 
?  ~ 

(2) 圖形化界面


image.png

注釋:當(dāng)數(shù)據(jù)導(dǎo)出為SQL文件時(shí)剂娄,MySQL會(huì)生成可以創(chuàng)建這些數(shù)據(jù)的SQL語句,效率低玄呛。

  1. 導(dǎo)入SQL文件

(1) 命令行語法
USE demo;
SOURCE demo.sql;

?  ~ cd /Users/nimengwei/Downloads/sql_file 
?  sql_file mysql -uroot -p
Enter password: 
mysql> USE demo;
Database changed
mysql> SOURCE demo.sql;
Query OK, 0 rows affected (0.00 sec)
mysql> 

(2) 圖形化界面


image.png
  1. 圖形化界面導(dǎo)出為文本文件

(1) 導(dǎo)出數(shù)據(jù)結(jié)構(gòu)

image.png

(2) 導(dǎo)出向?qū)?數(shù)據(jù))

image.png

注釋:當(dāng)數(shù)據(jù)導(dǎo)出為文本文件時(shí)阅懦,由于文本文件中沒有SQL語句,MySQL導(dǎo)出時(shí)不執(zhí)行詞法分析和語法優(yōu)化徘铝,效率高耳胎。

  1. 圖形化界面導(dǎo)入文本文件

(1) 導(dǎo)入數(shù)據(jù)結(jié)構(gòu)


image.png

(2) 導(dǎo)入向?qū)?數(shù)據(jù))


導(dǎo)入向?qū)?/div>

設(shè)置數(shù)據(jù)起始行數(shù)

映射字段

3.4 綜合案例:新聞管理系統(tǒng)數(shù)據(jù)庫設(shè)計(jì)

  1. 新聞管理系統(tǒng)成員


    image.png
  2. 新聞?dòng)心男傩?/p>

    image.png
  3. 數(shù)據(jù)庫ER圖設(shè)計(jì)
    image.png
  4. 數(shù)據(jù)加密
    (1) 數(shù)據(jù)加密
    分類:對(duì)稱加密、非對(duì)稱加密
    (2) 對(duì)稱加密
    加密和解密使用同一個(gè)秘鑰惕它。
    分類:DES加密(已淘汰)怕午、AES加密
    (3) 非對(duì)稱加密
    加密和解密使用不同的秘鑰。
    公鑰可以解密私鑰加密的數(shù)據(jù)怠缸,私鑰可以解密公鑰加密的數(shù)據(jù)诗轻。
    分類:RSA加密、DSA加密揭北、ECC加密
  5. AES加密函數(shù)
    MySQL提供了AES加密和解密的函數(shù)扳炬。
    AES_ENCRYPT(原始數(shù)據(jù), 秘鑰字符串);
    AES解密要使用與加密相同的秘鑰,才能解密出原始數(shù)據(jù)搔体。
    AES_DECRYPT(加密結(jié)果, 秘鑰字符串);
SELECT AES_ENCRYPT('你好世界','ABC123456');
# èZ?KaB§7^SàT\-H? 亂碼了恨樟,可轉(zhuǎn)化為16進(jìn)制解決亂碼
SELECT HEX(AES_ENCRYPT('你好世界','ABC123456')); 
# hex為2二進(jìn)制轉(zhuǎn)16進(jìn)制
# E85A104B6142A7375E53C0545CAD48EE
SELECT AES_DECRYPT(UNHEX('E85A104B6142A7375E53C0545CAD48EE'), 'ABC123456') 
# unhex為16進(jìn)制轉(zhuǎn)2進(jìn)制
# 你好世界
  1. 數(shù)據(jù)庫實(shí)現(xiàn)

(1) 創(chuàng)建數(shù)據(jù)庫

# 創(chuàng)建vega數(shù)據(jù)庫
CREATE DATABASE vega;
# 切換數(shù)據(jù)庫
USE vega;

(2) t_type文章類型表
數(shù)據(jù)表中數(shù)據(jù)量不大時(shí),可以不添加索引疚俱。例如:t_type文章類型表劝术,t_role角色類型表。

# 創(chuàng)建文章類型表
CREATE TABLE t_type(
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    type VARCHAR(20) NOT NULL UNIQUE
);

# 文章類型表插入數(shù)據(jù)
INSERT INTO t_type(type) 
VALUES("要聞"), ("體育"), ("科技"), ("娛樂"), ("歷史");

(3) t_role角色類型表

# 創(chuàng)建角色類型表
CREATE TABLE t_role(
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    role VARCHAR(20) NOT NULL UNIQUE
);

# 角色類型表插入數(shù)據(jù)
INSERT INTO t_role(role)
VALUES("管理員"), ("新聞編輯");

(4) t_user用戶表
數(shù)據(jù)表中數(shù)據(jù)量很大呆奕,并且經(jīng)常使用某些字段查找數(shù)據(jù)养晋,則應(yīng)該對(duì)這些字段創(chuàng)建索引。例如:t_user表中的username梁钾。

# 創(chuàng)建用戶表
CREATE TABLE t_user(
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(20) NOT NULL UNIQUE,
    password VARCHAR(500) NOT NULL,
    email VARCHAR(100) NOT NULL,
    role_id INT UNSIGNED NOT NULL,
    INDEX(username)
);

# 用戶表插入數(shù)據(jù)
INSERT IGNORE INTO t_user(username, password, email, role_id) VALUES
('admin', HEX(AES_ENCRYPT('123456','HelloWord')), 'admin@163.com', 1),
('scott', HEX(AES_ENCRYPT('123456','HelloWord')), 'scott@163.com', 2);

(5) t_news新聞表
新聞內(nèi)容數(shù)據(jù)的特點(diǎn)為:數(shù)據(jù)量大绳泉、安全級(jí)別低,適合存儲(chǔ)在mongodb數(shù)據(jù)庫中姆泻。通過content_id查找零酪。

# 創(chuàng)建新聞表
CREATE TABLE t_news(
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(40) NOT NULL,
    editor_id INT UNSIGNED NOT NULL,
    type_id INT UNSIGNED NOT NULL,
    content_id VARCHAR(24) NOT NULL,
    is_top TINYINT UNSIGNED NOT NULL,
    create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    state ENUM('草稿', '待審批', '已審批', '隱藏') NOT NULL,
    INDEX(editor_id),
    INDEX(type_id),
    INDEX(state),
    INDEX(is_top),
    INDEX(create_time)
);

3.5 總結(jié)

  1. 技能清單
    學(xué)習(xí)了事務(wù)機(jī)制的原理和特性冒嫡。
    掌握了事務(wù)的管理。
    掌握了數(shù)據(jù)導(dǎo)出與導(dǎo)入的操作四苇。
    完成了新聞管理系統(tǒng)數(shù)據(jù)表的設(shè)計(jì)孝凌。

4. MySQL與Python交互

4.1 介紹

  1. MySQL Connector模塊
    數(shù)據(jù)庫連接池、預(yù)編譯SQL月腋、CRUD操作蟀架、事務(wù)管理、異常處理
  2. 新聞管理系統(tǒng)
    新聞管理榆骚、用戶管理辜窑、系統(tǒng)登錄、數(shù)據(jù)分頁等

4.2 MySQL與Python的交互

  1. MySQL Connector模塊
    MySQL ConnectorMySQL官方的驅(qū)動(dòng)模塊寨躁,兼容性特別好穆碎。
?  ~ pip3 install mysql-connector
...
Successfully installed mysql-connector-2.2.9
  1. 創(chuàng)建連接

(1) 語法一

import mysql.connector
con = mysql.connector.connect(
    host="localhost",
    port=3306,
    user="root",
    password="299***",
    database="demo"
)

con.close()

(2) 語法二

import mysql.connector

config = {
    "host":"localhost",
    "port": 3306,
    "user": "root",
    "password": "299***",
    "database": "demo"
}

con = mysql.connector.connect(**config)

con.close()
  1. 游標(biāo)(Cursor)
    MySQL Connector里的游標(biāo)用來執(zhí)行SQL語句,查詢的結(jié)果集也會(huì)保存在游標(biāo)中职恳。
cursor = con.cursor()
cursor.execute(sql語句)
import mysql.connector

con = mysql.connector.connect(
    host="localhost",
    port=3306,
    user="root",
    password="299***",
    database="demo"
)

cursor = con.cursor()
sql = "SELECT empno, ename, hiredate FROM t_emp;"
cursor.execute(sql)
for item in cursor:
    print(item[0], item[1], item[2])
# 7369 SMITH 1980-12-17
# 7499 ALLEN 1981-02-20
# ...

con.close()
  1. SQL注入攻擊
import mysql.connector

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "299***",
    "database": "vega"
}

# 連接數(shù)據(jù)庫
con = mysql.connector.connect(**config)

# 獲取游標(biāo)
cursor = con.cursor()
username = "1 OR 1=1"
password = "1 OR 1=1"
sql = "SELECT COUNT(*) FROM t_user WHERE username=%s" \
    " AND AES_DECRYPT(UNHEX(password), 'HelloWord')=%s;"

cursor.execute(sql%(username, password))
print(cursor.fetchone()[0])  # 2
# 關(guān)閉數(shù)據(jù)庫連接
con.close()

注意:密碼必須是字符串格式所禀。

  1. SQL注入攻擊的危害
    由于SQL語句是解釋型語言,所以在拼接SQL語句的時(shí)候放钦,容易被注入惡意的SQL語句色徘。
id = "1 OR 1=1"
sql = "DELETE FROM t_news WHERE id={}".format(id)
  1. SQL預(yù)編譯機(jī)制
    (1) SQL預(yù)編譯機(jī)制
    預(yù)編譯SQL就是數(shù)據(jù)庫提前把SQL語句編譯成二進(jìn)制,這樣反復(fù)執(zhí)行同一條SQL語句的效率就會(huì)提升操禀。
    (2) 抵御注入攻擊
    SQL語句編譯的過程中褂策,關(guān)鍵字已經(jīng)被解析過了,所以向編譯后的SQL語句傳入?yún)?shù)颓屑,參數(shù)都被當(dāng)做字符串處理斤寂,數(shù)據(jù)庫不會(huì)解析其中注入的SQL語句。
    注釋:預(yù)編譯機(jī)制既可以提升SQL語句的執(zhí)行效率揪惦,又可以抵御注入攻擊遍搞。
  2. 抵御注入攻擊
import mysql.connector

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "299***",
    "database": "vega"
}

# 連接數(shù)據(jù)庫
con = mysql.connector.connect(**config)

# 獲取游標(biāo)
cursor = con.cursor()
username = "1 OR 1=1"
password = "1 OR 1=1"
sql = "SELECT COUNT(*) FROM t_user WHERE username=%s" \
    " AND AES_DECRYPT(UNHEX(password), 'HelloWord')=%s;"

cursor.execute(sql, (username, password))
print(cursor.fetchone()[0])  # 0
# 關(guān)閉數(shù)據(jù)庫連接
con.close()

注意:execute的第二個(gè)參數(shù)為元組或數(shù)組,例如: [a]器腋、(a,)溪猿。

  1. 事務(wù)控制
con.start_transaction([事務(wù)隔離機(jī)制])
con.commit()
con.rollback()
  1. 異常處理

(1) 語法

try:
    con = mysql.connector.connect(...)
    [ con.start_transaction() ]
    ...
    con.commit()
except Exception as e:
    [ con.rollback() ]
    print(e)
finally:
    if "con" in dir():
        con.close()

(2) 示例

import mysql.connector

try:
    con = mysql.connector.connect(
        host='localhost',
        port=3306,
        user='root',
        password='299***',
        database='demo'
    )
    con.start_transaction()
    cursor = con.cursor()
    sql = "INSERT INTO t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) " \
          "VALUES(%s, %s, %s, %s, %s, %s, %s, %s);"
    cursor.execute(sql, (9600, '趙娜', 'SALESMAN', None,'1998-09-08', 2000, None, 10))
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if 'con' in dir():
        con.close()
  1. 數(shù)據(jù)庫連接池技術(shù)
    數(shù)據(jù)庫連接是一種關(guān)鍵的、有限的纫塌、昂貴的資源诊县,在并發(fā)執(zhí)行的應(yīng)用程序中體現(xiàn)的尤為突出。TCP連接需要三次握手措左,四次揮手依痊,然后數(shù)據(jù)庫還要驗(yàn)證用戶信息。
    數(shù)據(jù)庫連接池(ConnectionPool)預(yù)先創(chuàng)建出一些數(shù)據(jù)庫連接媳荒,然后緩存起來抗悍,避免了程序語言反復(fù)創(chuàng)建和銷毀連接的昂貴代價(jià)。
import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': '3306',
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    sql = "UPDATE t_emp SET sal=sal+%s WHERE deptno=%s;"
    cursor.execute(sql, (200, 20))
    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()

注意:使用數(shù)據(jù)庫連接池(ConnectionPool)也需要關(guān)閉(close)钳枕。

  1. 刪除數(shù)據(jù)

(1) DELETE語句刪除記錄

import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    sql = "DELETE e, d FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno " \
          "WHERE d.deptno=20;"
    cursor.execute(sql)
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()

(2) TRUNCATE語句快速刪除記錄
TRUNCATE語句是在事務(wù)機(jī)制之外刪除記錄缴渊。

import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    cursor = con.cursor()
    sql = "TRUNCATE TABLE t_emp"
    cursor.execute(sql)
except Exception as e:
    print(e)
  1. 循環(huán)執(zhí)行SQL語句

(1) for循環(huán)執(zhí)行execute()函數(shù)

import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    sql = "INSERT INTO t_dept(deptno, dname, loc) VALUES (%s, %s, %s);"
    data = [[50, '部門1', '北京'], [60, '部門2', '上海']]
    for item in data:
        cursor.execute(sql, item)
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()

(2) 游標(biāo)(cursor)對(duì)象中的executemany()函數(shù)可以反復(fù)執(zhí)行一條SQL語句。

import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    sql = "INSERT INTO t_dept(deptno, dname, loc) VALUES (%s, %s, %s);"
    data = [[70, '部門1', '北京'], [80, '部門2', '上海']]
    cursor.executemany(sql, data)
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()
  1. 使用INSERT語句鱼炒,把部門平均底薪超過公司平均底薪這樣的部門里的員工信息導(dǎo)入到t_emp_new表里衔沼,并且讓這些員工隸屬于sales部門。
    編程語言中昔瞧,數(shù)據(jù)庫查詢結(jié)果可以通過變量保存指蚁,比直接通過SQL語句操作數(shù)據(jù)庫的寫法簡(jiǎn)單。
import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': '3306',
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    # 創(chuàng)建數(shù)據(jù)表
    sql = "CREATE TABLE t_emp_new LIKE t_emp;"
    cursor.execute(sql)
    # 公司平均底薪
    sql = "SELECT AVG(sal) as avg FROM t_emp;"
    cursor.execute(sql)
    avg = cursor.fetchone()[0]
    # print(avg) # 2073.214286
    # 部門底薪超過公司平均底薪的部門
    sql = "SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal) >= %s;"
    cursor.execute(sql, (avg,))
    deptnos = cursor.fetchall()
    # print(deptnos) # [(10,), (20,)]
    # 符合條件的部門員工導(dǎo)入到新表
    deptnos_str = '('
    for index in range(len(deptnos)):
        if index == len(deptnos) - 1:
            deptnos_str += (str(deptnos[index][0]))
        else:
            deptnos_str += (str(deptnos[index][0]) + ',')
    deptnos_str += ')'
    sql = "INSERT INTO t_emp_new (SELECT * FROM t_emp WHERE deptno IN {});".format(deptnos_str)
    cursor.execute(sql)
    sql = "DELETE FROM t_emp WHERE deptno IN {};".format(deptnos_str)
    cursor.execute(sql)
    # 將t_emp_new表的員工部門修改為sales部門
    sql = "SELECT deptno FROM t_dept WHERE dname=%s;"
    cursor.execute(sql, ['SALES'])
    new_emptno = cursor.fetchone()[0]
    print(new_emptno)
    sql = "UPDATE t_emp_new SET deptno=%s"
    cursor.execute(sql, [new_emptno])
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()

注意:① 'CREATE TABLE t_emp_new LIKE t_emp;'表示使用t_emp表的結(jié)構(gòu)創(chuàng)建t_emp_new表自晰。② CREATE TABLE語句為DDL語句凝化,不受事務(wù)控制。③ 由于不知道符合條件的部門個(gè)數(shù)酬荞,因此該案例只能使用字符串拼接搓劫,不能使用字符串格式化。 ④ INSERT INTO t_emp_new 查詢出的表結(jié)果;語法可以將查詢出的數(shù)據(jù)表集合插入到t_emp_new表中枪向。

  1. 編寫一個(gè)INSERT語句秘蛔,向部門表插入兩條記錄,每條記錄都在部門原有最大主鍵值的基礎(chǔ)上加10辨液。

(1) 不支持邊插入,邊查詢本表數(shù)據(jù)
例如:INSERT INTO 表名(字段1,字段2, ...) VALUES(值1,值2,...);

INSERT INTO t_dept(deptno, dname, loc) 
VALUES((SELECT MAX(deotno) FROM t_dept) + 10, "A部門", "南京");
# 報(bào)錯(cuò) Unknown column 'deotno' in 'field list', Time: 0.014000s

(2) 可以先查詢出數(shù)據(jù)表燎悍,再寫入
例如:INSERT INTO 表名 數(shù)據(jù)集;

INSERT INTO t_dept (SELECT MAX(deptno) + 10, "A部門", "南京" FROM t_dept);
INSERT INTO t_dept (SELECT MAX(deptno) + 10, "A部門", "南京" FROM t_dept) UNION 
(SELECT MAX(deptno) + 20, "B部門", "上海" FROM t_dept);

(3) Python語言實(shí)現(xiàn)

import mysql.connector.pooling

config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299***',
    'database': 'demo'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    sql = "INSERT INTO t_dept " \
          "(SELECT MAX(deptno) + 10, %s, %s FROM t_dept) " \
          "UNION " \
          "(SELECT MAX(deptno) + 20, %s, %s FROM t_dept);"
    cursor.execute(sql, ('A部門', '北京', 'B部門', '上海'))
    con.commit()
except Exception as e:
    if 'con' in dir():
        con.rollback()
    print(e)
finally:
    if "con" in dir():
        con.close()

4.3 總結(jié)

  1. 技能清單
    掌握了數(shù)據(jù)庫連接池技術(shù)
    掌握了Python程序的CRUD操作
    掌握了用預(yù)編譯SQL抵御SQL注入攻擊

5. 開發(fā)新聞管理系統(tǒng)

  1. 第三方模塊
    (1) 升級(jí)pip
    ? ~ python3 -m pip install --upgrade pip
    (2) 安裝colorama
    ? ~ pip3 install colorama
    向控制臺(tái)輸出彩色文字
from colorama import Back, Fore, Style

print(Fore.LIGHTBLUE_EX, 'HelloWord')  # 設(shè)置字體顏色
print('HelloWord')
print(Back.LIGHTRED_EX, 'HelloWord')  # 設(shè)置背景色
print('HelloWord')
print(Style.RESET_ALL, 'HelloWord')  # 重置樣式
  1. 項(xiàng)目介紹

(1) 新建項(xiàng)目

image.png

(2) 項(xiàng)目結(jié)構(gòu)
vega - db奏路、service斜脂、app.py
(3) 管理員身份操作流程圖
流程圖

  1. 代碼地址
    https://github.com/nmwei/database-vega
  2. 代碼示例(部分)
    (1) mysql_db提供數(shù)據(jù)庫連接池
import mysql.connector.pooling

__config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '299792',
    'database': 'vega'
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **__config,
        pool_size=10
    )
except Exception as e:
    print(e)

(2) dao文件用來操作數(shù)據(jù)庫,以user_dao.py為例片任。

from db.mysql_db import pool

class UserDao:
    # 驗(yàn)證用戶登錄
    def login(self, username, password):
        try:
            con = pool.get_connection()
            cursor = con.cursor()
            sql = "SELECT COUNT(*) FROM t_user WHERE username=%s AND " \
                "AES_DECRYPT(UNHEX(password), 'HelloWord')=%s;"
            cursor.execute(sql, (username, password))
            count = cursor.fetchone()[0]
            # Python中的三元運(yùn)算符
            return True if count == 1 else False
        except Exception as e:
            print(e)
        finally:
            if "con" in dir():
                con.close()
...

(3) service文件用來調(diào)用dao函數(shù)氛濒,并處理業(yè)務(wù)邏輯涝动。以user_service.py為例醋粟。

from db.user_dao import UserDao


class UserService:
    __user_dao = UserDao()

    # 驗(yàn)證用戶登錄
    def login(self, username, password):
        return self.__user_dao.login(username, password)
...

(4) app.py程序入口

from colorama import Fore, Style
from getpass import getpass
from service.user_service import UserService
from service.news_service import NewsService
from service.role_service import RoleService
import os
import sys
import time

__user_service = UserService()
__news_service = NewsService()
__role_service = RoleService()

while True:  # 輪詢操作
    os.system('clear')  # 如果是window系統(tǒng)鼻吮,使用cls
    print(Fore.LIGHTBLUE_EX, '\n\t=================')
    print(Fore.LIGHTBLUE_EX, '\n\t歡迎使用新聞管理系統(tǒng)')
    print(Fore.LIGHTBLUE_EX, '\n\t=================')
    print(Fore.LIGHTGREEN_EX, '\n\t1. 登錄系統(tǒng)')
    print(Fore.LIGHTGREEN_EX, '\n\t2. 退出系統(tǒng)')
    print(Style.RESET_ALL)  # 重置樣式
    opt = input("\n\t請(qǐng)輸入操作編號(hào): ")
    if opt == '1':
        username = input('\n\t用戶名: ')
        password = getpass('\n\t密碼: ')  # 使輸密碼過程不可見
        result = __user_service.login(username, password)
        # 登錄成功
...

注意:①Python中的三元運(yùn)算符:True if count == 1 else False违柏。②數(shù)據(jù)庫中管理員用戶名密碼為:admin 123456畜伐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末悼吱,一起剝皮案震驚了整個(gè)濱河市后添,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖阻问,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哮塞,死亡現(xiàn)場(chǎng)離奇詭異衡未,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)送粱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門世舰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人姊氓,你說我怎么就攤上這事读跷。” “怎么了荡短?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弯院。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么贴妻? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任蝙斜,我火速辦了婚禮名惩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孕荠。我一直安慰自己娩鹉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布稚伍。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瑟捣。 梳的紋絲不亂的頭發(fā)上芙扎,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天磷蜀,我揣著相機(jī)與錄音,去河邊找鬼。 笑死栈暇,一個(gè)胖子當(dāng)著我的面吹牛歇僧,可吹牛的內(nèi)容都是我干的舷夺。 我是一名探鬼主播帝际,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤羔砾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愤诱,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鲜棠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓮恭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雄坪。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖屯蹦,靈堂內(nèi)的尸體忽然破棺而出维哈,到底是詐尸還是另有隱情,我是刑警寧澤登澜,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布阔挠,位于F島的核電站,受9級(jí)特大地震影響脑蠕,放射性物質(zhì)發(fā)生泄漏购撼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一谴仙、第九天 我趴在偏房一處隱蔽的房頂上張望迂求。 院中可真熱鬧,春花似錦晃跺、人聲如沸揩局。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谐腰。三九已至孕豹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間十气,已是汗流浹背励背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砸西,地道東北人叶眉。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像芹枷,于是被迫代替她去往敵國和親衅疙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容