1. 程式人生 > 實用技巧 >CSS——複合選擇器

CSS——複合選擇器

MySQL

1.初識資料庫

JavaEE:企業級開發 web

前端

後臺(連線點:連結資料庫JDBC,連結前端)

資料庫

資料庫是所有軟體體系中最核心的存在

1.1 什麼是資料庫

資料庫(DB,DataBase)

概念:資料倉庫,軟體,安裝在作業系統上!SQL,可以儲存大量的資料。

作用:儲存資料

1.2 資料庫分類

關係型資料庫:

  • MySQL,Oracle.Sql Server,DB2,SQLlite
  • 通過表和表之間,行和列之間的關係進行資料庫的儲存

非關係型資料庫:

  • Redis,MongDB
  • 非關係型資料庫,物件儲存,通過物件的自身的屬性來決定。

DBMS(資料庫管理系統)

  • 資料的管理軟體,科學有效的管理我們的資料。維護和獲取資料
  • MySQL

1.3MySQL簡介

MySQL是一個關係型資料庫管理系統

前世:瑞典MySQL AB公司

今生:屬於Oracle旗下產品

MySQL是最好的關係資料庫管理系統應用軟體之一

開源的資料庫軟體

體積小、速度快、總體擁有成本低,

中小型、大型網站都有使用

安裝建議:

  1. 儘量不要使用exe進行安裝
  2. 儘可能使用壓縮包安裝

1.4安裝MySQL

  1. 下載MySQL壓縮包,並解壓。

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

  2. 配置環境變數,將mysql資料夾下的bin目錄新增到path中

  3. 新建配置檔案my.ini

    [mysqld]
    # 目錄要換成自己mysql檔案目錄
    basedir=F:\mysql\mysql-5.7.32
    datadir=F:\mysql\mysql-5.7.32\data\
    port=3306
    skip-grant-tables
    

    要注意的是目前mysql資料夾中沒有打他資料夾,但是我們並不需要建立data資料夾,在下面的步驟中會自動生成data資料夾。

    配置檔案的最後一行表示的是跳過密碼驗證。

  4. 管理員模式下啟動CMD,進入mysql資料夾下的bin目錄,執行

    mysqld -install
    

    執行結束後會出現

    Service successfully installed.
    

  5. 再輸入以下程式碼來初始化資料檔案

    mysqld --initialize-insecure --user=mysql
    

    這時候mysql資料夾下就會自動生成data目錄,命令列沒有報錯就表示初始化完成。

  6. 然後輸入以下命令啟動mysql,

    net start mysql
    

  7. 使用以下命令進入mysql

    mysql -u root -p
    

    會出現讓你輸入密碼,由於密碼沒有設定,所以直接enter即可

  8. 使用命令來修改密碼,注意mysql中每一條命令都是分號;結尾的。

    update mysql.user set authentication_string=password('123456') where user ='root' and Host='localhost';
    

    然後使用命令flush privileges;來重新整理許可權

  9. 修改my.ini檔案

    將my.ini檔案的最後一行註釋掉,最後一行前面加# 即可

  10. 重啟mysql。輸入exit退出MySQL,然後關掉服務net stop mysql,再重新啟動mysql服務,輸入mysql -u root -p,然後輸入密碼進入mysql即可。

1.5安裝SQLyog

https://github.com/webyog/sqlyog-community/wiki/Downloads

上面的GitHub中有許多版本,對應下載即可。

下載完成後安裝。

開啟後填寫相應的連線資訊即可。localhost表示連線自己的主機,密碼是之前設定的密碼。3306表示的是資料庫的埠。

然後建立資料庫,右鍵建立資料庫

再sqlyog中每用滑鼠執行一次操作,實際上就是對應了一個sql語句,可以在軟體中的歷史記錄檢視

在新建的資料庫裡新建表,右擊新建,其中基字符集和資料排序規則要與圖片中的一致,不然可能會出現亂碼的情況。

右擊表,點選開啟表,然後可以在表裡新增資料。

點選右上的重新整理按鈕即可儲存資料。

1.6連線資料庫

命令列連線資料庫

mysql -u root -p  -- 連線資料庫

update;    -- 修改命令
flush privileges;  -- 重新整理許可權


 show databases;  -- 檢視所有資料庫
 
 use school; -- 使用school資料庫
 -- 會輸出Database changed,表明資料庫已經切換
 
 show tables; -- 檢視該資料庫中所有的表
 describe student; -- 查看錶的結構,而不是表中的所有內容
 
 create databases westos; -- 建立資料庫
 
 exit; -- 退出資料庫
 
 -- 單行註釋
 
/*
多行註釋
*/

資料庫定義語言 DDL

資料庫操作語言 DML

資料庫查詢語言 DQL

資料庫控制語言 SCL

2.操作資料庫

操作資料庫>操作資料庫中的表>操作資料庫中表的資料

mysql不區分字母大小寫

2.1操作資料庫

create database if not exists westos;  -- 建立資料庫

drop database if exists westos;  -- 刪除資料庫

-- `` 符號,當你的表明或者欄位名是一個特殊字元時,就需要使用``,以免該特殊字元程式設計高亮
use `school`;   -- 使用資料庫

show Databases;   -- 檢視所有的資料庫

可以對比SQLyog的視覺化操作來學習簡單的sql程式碼

需要記住一些關鍵字和固定的語法。

2.2資料庫的列型別

數值

  • tinyint 十分小的資料 1個位元組
  • smallint 較小的資料 2個位元組
  • mediumint 中等大小的資料 3個位元組
  • int 標準的整數 4個位元組 最常用
  • bigint 較大的數字 8個位元組
  • float 浮點數 4個位元組
  • double 浮點數 8個位元組 (具有精度問題)
  • decimal 字串形式的浮點數 用於金融計算

字串

  • char 字串 固定大小 0-255
  • varchar 可變字串 0-65535 常用
  • tinytext 微型文字 2^8 -1
  • **text 文字串 2^16-1 ** 儲存大文字

時間日期

  • data YYYY-MM-DD,日期
  • time HH:mm:ss 時間格式
  • datatime YYYY-MM-DD HH:mm:ss 最常用的時間格式
  • timestamp 時間戳,1970.1.1到現在的毫秒數
  • year 年份表示

null

  • 沒有值,未知
  • 儘量不要使用null進行運算,結果為null

2.3資料庫的欄位屬性(重點)

Unsigned :

  • 無符號的整數
  • 聲明瞭該列不能為負數

zerofill

  • 0填充的
  • 不足的位數,使用0來填充

自增

  • 理解為自增,自動在上一條記錄的基礎上+1(預設)
  • 通常用來設計唯一的主鍵 index,必須是整數型別
  • 可以自定義設計主鍵自增的起始值和步長

非空

  • 假設設定為not nul,如果不賦值,就會報錯
  • null,如果不填寫值,預設就是null

預設

  • 設定預設的值
  • 如果不賦值,就會自動賦值為你設定的預設值。

拓展:

每一個表都必須存在以下五個欄位

  1. id 主鍵
  2. version 樂觀鎖
  3. is_delete 偽刪除
  4. gmt_create 建立時間
  5. gmt_update 修改時間

2.4建立資料庫表

-- 建立一個school資料庫
-- 建立學生表
-- 學號、登陸密碼、姓名、性別、出生日期、家庭住址、email

-- 注意點:全程符號使用英文,表的名稱和欄位儘量使用``括起來
-- AUTO_INCREMENT 自增
-- 字串使用單引號括起來
-- 所有的語句後面加,最後一個不用加
-- PRIMARY KEY 主鍵,一般一個表只有一個唯一的主鍵
Create Table if not exists `student`(
`id` Int(4) not null Auto_Increment comment '學號',
`name` varchar(20) not null Default '匿名' comment '姓名',
`pwd` varchar(20) not null default '123456' comment '密碼',
`sex` varchar(5) not null default '男' comment '性別',
`birthday` date default null comment '出生日期',
`address` varchar(100) default null comment '家庭地址',
primary key(`id`)
)engine=INNOdb default charset=utf8

格式

create table `表名`(
	`欄位名` 列型別 [屬性] [索引] [註釋],
	`欄位名` 列型別 [屬性] [索引] [註釋],
    `欄位名` 列型別 [屬性] [索引] [註釋],
)[表型別] [字符集型別] [註釋]

常用命令:

show create database school  -- 檢視建立資料庫的語句
show create table student    -- 檢視student資料表的定義語句

DESC student   -- 顯示錶的結構

2.5資料表的型別

-- 資料庫的引擎
/*
INNODB 預設使用的
MYISAM 早些年使用的
*/
MYISAM INNODB
事物支援 不支援 支援
資料行鎖定 不支援 支援
外來鍵約束 不支援 支援
全文索引 支援 不支援
表空間的大小 較小 較大,約為MYISAM的兩本

常規使用:

  • MYISAM 節約空間,速度較快
  • INNODN 安全性高,支援事物的處理以及多表多使用者操作

在物理空間存在的位置

所有的資料庫檔案都存在data目錄下,一個資料夾就對應一個數據庫。

資料庫的本質還是檔案的儲存。

MySQL引擎在物理檔案上的區別

  • INNODB在資料庫表中只有一個*.frm檔案,以及在上級目錄下的 ibdata1檔案中也存放了該表中的一些資料
  • MYISAM 對應檔案
    • *.frm 表結構的定義檔案
    • *.MYD 資料檔案(data)
    • *.MYI 索引檔案(index)

設定資料庫表的字符集編碼

charset=utf8

如果沒有設定的話,會自動設定mysql預設的字符集編碼(不支援中文)

MySQL的預設編碼是Latin1

另外可以在my.ini中配置預設的編碼(不建議使用)

character-set-server=utf8

2.6修改刪除表

修改表

-- 修改表名 ALTER TABLE 舊錶名 RENAME AS 新表名
ALTER TABLE student RENAME AS teacher

-- 增加表的欄位  ALTER TABLE 表名 ADD 欄位名 列屬性
ALTER TABLE teacher ADD email VARCHAR(20)

-- 修改表的欄位,包括兩個:重新命名和修改約束
ALTER TABLE teacher MODIFY age VARCHAR(20)  -- 修改約束
ALTER TABLE teacher CHANGE age age1 INT(5)  -- 欄位重新命名

-- 刪除表的欄位
ALTER TABLE teacher DROP age1

刪除表

-- 刪除表
DROP TABLE IF EXISTS teacher

所有的建立和刪除操作儘量加上判斷,以免報錯

注意點:

  • 儘量使用``包裹欄位名
  • 註釋 -- /* */
  • sql 關鍵字大小寫不敏感,建議小寫
  • 所有的符號用英文

3.MySQL資料管理

3.1外來鍵(物理外來鍵,瞭解即可)

方式一:在建立表的時候,增加約束(麻煩、複雜)

要刪除有外來鍵關係的表,需要先刪除引用自己的其他表,在刪除該表。即該表被別的表引用,要先刪除別的表。

-- 年紀表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年紀id',
`gradename` VARCHAR(20) NOT NULL COMMENT '年紀名稱',
PRIMARY KEY(`gradeid`)		
)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 學生表的gradeid 要引用年紀表的gradeid
-- 要定義外來鍵
-- 給這個外來鍵新增約束(執行引用) references 引用
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHAR(5) NOT NULL DEFAULT '男' COMMENT '性別',
`gradeid` INT(10) NOT NULL COMMENT '學生的年紀',
`birthday` DATE DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

方式二:建立表成功後,新增外來鍵約束

CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHAR(5) NOT NULL DEFAULT '男' COMMENT '性別',
`gradeid` INT(10) NOT NULL COMMENT '學生的年紀',
`birthday` DATE DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 建立的時候沒有外來鍵關係
ALTER TABLE `student` 
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);

-- alter table 表 add constratint 約束名 foreign key(作為外來鍵的列) references 那個表(那個表的欄位)

該外來鍵的操作均屬於物理外來鍵,資料庫級別的外來鍵,不建議使用,避免資料庫過多造成困擾。

最佳實踐

  • 資料庫就是單純的表,只用來存資料,只有行和列
  • 要使用多張表的資料,用程式來實現外來鍵的功能。

3.2DML語言

資料庫的意義:資料儲存和資料管理

DML語言:資料操作語言

  • insert 插入
  • update 修改
  • delete 刪除

3.3 插入(新增)

Insert

-- 插入語句
-- insert into 表名(欄位1,欄位2,欄位3) values ('值1','值2','值3',),('值1','值2','值3',),('值1','值2','值3',),....

-- 主鍵是自增的,不主動新增的話主鍵也會自動新增值
INSERT INTO `grade` (`gradename`) VALUES ('大三');

-- 新增多行
INSERT INTO `grade` (`gradename`) 
VALUES ('大一'),('大二'),('大四');

-- 欄位名可以省略,但是值必須與表一一對應,包括主鍵也要手動新增,不能省略。
INSERT INTO `student` VALUES (2,'xh','123465','男','1','1997-6-11','px');

注意點:

  • 欄位和欄位之間使用英文逗號隔開
  • 欄位是可以省略的,但是後面的值必須與表一一對應,且不能缺少
  • 可以同時插入多條資料,values後面的值需要使用逗號隔開。('大一'),('大二'),('大四');

3.4修改

update

-- 修改
-- 修改學生姓名,有指定的條件 where
UPDATE `student` SET `name`='lzp' WHERE id=2;

-- 如果沒有指定條件,會改動所有的表的值
UPDATE `student` SET `name`='lzp'

-- 可以一次修改多個屬性
UPDATE `student` SET `name`='lll',`gradeid`=2 WHERE id=3;

-- 語法
-- update 表名 set cloume_name = value,[cloume_name = value],... where [條件]

條件:where 子句 運算子

操作符會返回布林值

操作符 含義 範圍 結果
= 等於
<>或!=
>
<
<=
>=
BETWEEN ... AND 範圍區間 [2,5](閉區間)
AND
OR
-- 通過多個條件定位資料
update `student` set `name`='lzp' where `name`='lll' and sex='女'

注意點:

  • colunm_name 是資料庫上的列,儘量帶上``
  • 條件,篩選的條件如果沒有指定,則會修改所有的列
  • value 是一個具體的值,也可以是一個變數
  • 多個設定的屬性之間,使用英文逗號隔開

3.5刪除

delete 命令

語法:delete from 表名 [where 條件]

-- 刪除資料
delete from `student` where id=1

truncate 命令

作用:完全清空一個數據庫表,表的結構和索引不會改變

truncate 表名

delete 與truncate區別

  • 相同點:都能刪除資料,都不會刪除表的結構
  • 不同:
    • truncate 重新設定自增列,計數器會歸零,delete不會
    • truncate 不會影響事務

4.DQL查詢資料(重點)

4.1 DQL

資料查詢語言:

  • 所有的查詢操作都要用
  • 簡單的查詢和複雜的查詢都能做
  • 資料庫中最核心的語言,最重要的語句
  • 使用頻率最高的語句

select語法,順序不能改變。

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
    [HAVING where_condition]
    [WINDOW window_name AS (window_spec)
        [, window_name AS (window_spec)] ...]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR {UPDATE | SHARE} [OF tbl_name [, tbl_name] ...] [NOWAIT | SKIP LOCKED]
      | LOCK IN SHARE MODE]]

4.2指定查詢欄位

SELECT * FROM `student`

SELECT * FROM `result`

-- 查詢指定欄位
SELECT `studentno`,`studentname`FROM `student`

-- 起別名,給結果起別名,AS 也可以給欄位起別名,給表起別名
SELECT `studentno` AS '學號',`studentname` AS '姓名' FROM `student`

-- 函式,concat(a,b)
SELECT CONCAT('姓名:',studentName) AS 新名字 FROM student
/*
新名字
姓名:張偉
姓名:趙強
*/

語法:select 欄位 from 表

去重distinct

作用:去除select查詢出來的結果中重複的資料,重複的資料只顯示一條

-- 查詢有哪些同學參加了考試,成績
SELECT * FROM result   -- 查詢了全部的考試成績
SELECT `studentno` FROM result
-- 發現重複資料,去重
SELECT DISTINCT `studentno` FROM result

資料庫的列(表示式)

-- 查詢系統的版本號
SELECT VERSION()
SELECT 100*3-1 AS 計算結果  -- 用來計算
SELECT @@auto_increment_increment -- 查詢自增的步長

-- 檢視學員考試成績+1分
SELECT `studentno`,`studentresult` +1 AS '提分後' FROM result

資料庫中的表示式:文字值,列,null,函式,計算表示式,系統變數。。。

select 表示式 from 表

4.3where條件子句

作用:檢索資料中符合條件的資料

搜尋的條件由一個或多個表示式組成!結果是一個布林值

邏輯運算子

and(&&) a and b 邏輯與

or(||) a or b 邏輯或

Not(!) not a 邏輯非

-- ========================== where ============================
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`>=95 AND `studentresult`<=100;

SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`<=95 OR `studentresult`>=100;

SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentno`!=1000 

模糊查詢:比較運算子

運算子 語法 描述
IS NULL a is null 操作符為null,結果為真
IS NOT NULL a is not null
BETWEEN a between b and c
LIKE a like b SQL匹配,如果a匹配b,則結果為真
IN a in (a1,a2,a3.....) a是a1,a2,a3.....其中的一個值,結果為真
-- ===========================模糊查詢===================
-- 查詢姓劉的同學
-- like結合  %(代表0到任意個字元)  _(代表一個字元)
-- 查詢姓張,且名字只有兩個字的,
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '張_';                 
-- '張__' :表示名字為三個字的,'張%'表示姓張且名字中有任意多個字的

-- 查詢名字中間有某個字
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '%張%';

-- in(具體的一個或多個值)
-- 查詢1001,1002,1003號學員
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentno` IN (1001,1002,1003)

-- 查詢在北京和安徽的學生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address` IN ('北京','安徽')


-- null、not null
-- 查詢地址為空的學生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address`='' OR `address` IS NULL

4.4聯表查詢

JOIN 對比

-- ===========================模糊查詢===================
-- 查詢姓劉的同學
-- like結合  %(代表0到任意個字元)  _(代表一個字元)
-- 查詢姓張,且名字只有兩個字的,
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '張_';                 
-- '張__' :表示名字為三個字的,'張%'表示姓張且名字中有任意多個字的

-- 查詢名字中間有某個字
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '%張%';

-- in(具體的一個或多個值)
-- 查詢1001,1002,1003號學員
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentno` IN (1001,1002,1003)

-- 查詢在北京和安徽的學生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address` IN ('北京','安徽')


-- null、not null
-- 查詢地址為空的學生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address`='' OR `address` IS NULL


-- ==================聯表查詢 join======================
-- 查詢參加了考試的同學(學號,姓名,科目編號,分數)
/*
思路:
1.分析需求,分析查詢的欄位來自哪些表,使用聯結查詢
2.確定使用哪種聯結查詢?一共有七種
確定表間的交叉點,也就是兩個表中有哪些資料是相同的
判斷的條件:學生表中的studentNO = 成績表中的studentNo
*/

-- Inner join 以兩個表的交集為基準
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.studentno = r.`studentno`

-- left join 以左邊的表為基準進行查詢
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`

-- right join 以右邊的表為基準進行查詢
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
RIGHT JOIN `result` AS r
ON s.`studentno` = r.`studentno`

-- 查詢缺考的同學
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
LEFT JOIN `result` AS r
ON s.`studentno` = r.`studentno`
WHERE `studentresult` IS NULL

-- 查詢參加了考試的同學的資訊:學號,學生姓名,科目名,分數)
/*
使用的表  `student`,`result`,`subject`
*/
SELECT stu.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS stu
RIGHT JOIN `result` AS r
ON stu.`studentno`=r.`studentno`
INNER JOIN `subject` AS sub
ON sub.`subjectno`=r.`subjectno`

SELECT stu.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS stu
LEFT JOIN `result` AS r
ON stu.`studentno`=r.`studentno`
LEFT JOIN `subject` AS sub
ON sub.`subjectno`=r.`subjectno`
WHERE `studentresult` IS NULL

要注意inner join、left join和right join之間的區別,主要看上面的七種查詢的圖

自連線

自己的表和自己的表連線,核心:一張表拆為兩張一樣的表即可

總表:

categoryid pid categroyName
2 1 資訊科技
3 1 軟體開發
4 3 資料庫
5 1 美術設計
6 3 web開發
7 5 ps技術
8 2 辦公資訊

總表中pid為1表示為父類資料,pid為其他的為子類資料。pid等於父類的categoryid表示該類為父類的子類。

父類:

categoryid pid categroyName
2 1 資訊科技
3 1 軟體開發
5 1 美術設計

子類:

categoryid pid categroyName
4 3 資料庫
6 3 web開發
7 5 ps技術
8 2 辦公資訊

操作:查詢父類對應的子類關係

父類 子類
資訊科技 辦公資訊
軟體開發 資料庫
軟體開發 web開發
美術設計 ps技術
SELECT c1.`categoryName` AS '父類',c2.`categoryName` AS '子類'
FROM `category` AS c1, `category` AS c2
WHERE c1.`categoryid`=c2.`pid`

4.5分頁和排序

排序

-- 排序: 升序 asc  降序 desc
-- order by 通過哪個欄位排序,怎麼排
SELECT stu.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS stu
RIGHT JOIN `result` AS r
ON stu.`studentno`=r.`studentno`
INNER JOIN `subject` AS sub
ON sub.`subjectno`=r.`subjectno`
ORDER BY `studentresult` DESC

分頁

-- 分頁
-- 可以緩解資料庫壓力,給人的體驗更好

-- 分頁,每頁只顯示五條資料
-- 語法:limit 其實值,頁面的大小
-- limit 0,2

SELECT stu.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS stu
RIGHT JOIN `result` AS r
ON stu.`studentno`=r.`studentno`
INNER JOIN `subject` AS sub
ON sub.`subjectno`=r.`subjectno`
ORDER BY `studentresult` DESC
LIMIT 0,2

4.6 子查詢

where 後面巢狀查詢語句

SELECT stu.`studentno`,`studentname`,`studentresult`
FROM `student` AS stu
INNER JOIN `result` AS r
ON stu.`studentno`=r.`studentno`
WHERE `subjectno` = (
    SELECT `subjectno` FROM `subject`
    WHERE `subjectname`='高等數學-1'
)

4.7分組和過濾

SELECT `subjectname`,AVG(`studentresult`),MAX(`studentresult`),MIN(`studentresult`)
FROM `result` r
INNER JOIN `subject` sub
ON sub.`subjectno`=r.`subjectno`
GROUP BY r.`subjectno`               -- 通過什麼欄位來分組
HAVING AVG(`studentresult`)>80

group by 分組

having 過濾

5.MySQL函式

5.1常用函式

-- 數學運算
SELECT ABS(-2)  -- 絕對值
SELECT CEILING(9.4)  -- 向上取整
SELECT FLOOR(9.4)     -- 向下取整
SELECT RAND()  -- 返回0-1之間的隨機數
SELECT SIGN(10)  -- 判斷一個數的符號   0-0,負數返回-1,整數返回1

-- 字串函式
SELECT CHAR_LENGTH('阿斯蒂芬愛的色放')  -- 字串長度
SELECT CONCAT('阿斯蒂芬' , '阿三士大','asd')  -- 拼接字串
SELECT INSERT('阿斯蒂hello', 1,2,'超級')      -- 從某個位置開始,替換某個長度
SELECT UPPER('asdfadsf')       -- 轉換為大寫字母
SELECT LOWER('ASFD')           -- 轉換為小寫字母
SELECT INSTR('asdsfe','s')     -- 查詢第一次出現的位置
-- replace , 
-- substr(字串,擷取的位置,擷取的長度)

-- 時間和日期函式
SELECT CURRENT_DATE()   -- 獲取當前日期
SELECT CURDATE()    -- 獲取當前日期
SELECT NOW()       -- 獲取當前日期及時間
SELECT LOCALTIME()  -- 獲取當前日期及時間
SELECT SYSDATE()    -- 獲取系統日期及時間

SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT SECOND(NOW())

-- 系統
SELECT SYSTEM_USER();
SELECT USER();
SELECT VERSION();

5.2 聚合函式

-- =========================聚合函式====================
SELECT COUNT(`studentname`) FROM student    -- count(欄位),會忽略所有的null值
SELECT COUNT(*) FROM student;               -- 不會忽略null值
SELECT COUNT(1) FROM result;                -- 不會忽略所有的null值

SELECT SUM(`studentresult`) AS 總分 FROM result
SELECT AVG(`studentresult`) AS 平均分 FROM result
SELECT MIN(`studentresult`) AS 最低分 FROM result
SELECT MAX(`studentresult`) AS 最高分 FROM result

5.3 資料庫級別的MD5加密

MD5,主要增求演算法的複雜度和不可逆性。

MD5是不可逆的,具體的值的md5是一樣的

MD5破解網站的原理是:他們有一個字典,MD5加密後的值,加密前的值

-- =================測試MD5 加密===================
CREATE TABLE `testmd5`(
    `id` INT(4) NOT NULL,
    `name` VARCHAR(20) NOT NULL,
    `pwd` VARCHAR(50) NOT NULL,
    PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 明文密碼
INSERT INTO testmd5 VALUES(1,'lll','123456'),(2,'zzz','123456'),(3,'ppp','123456'),(4,'ldfl','123456')

-- 加密
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=1
UPDATE testmd5 SET pwd=MD5(pwd)             -- 加密全部的密碼

-- 插入的時候加密
INSERT INTO testmd5 VALUES(5,'asdf',MD5('123456'))

6.事物

6.1 什麼是事物

**要麼都成功,要麼都失敗 **

將一組sql放在一個批次去執行。

事物原則:ACID原則:原子性、一致性、隔離性、永續性

  1. 原子性(Atomicity):是指一個事務要麼全部執行,要麼完全不執行。
  2. 一致性(Consistency): 事務在開始和結束時,應該始終滿足一致性約束。比如系統要求A+B=100,那麼事務如果改變了A的數值,則B的數值也要相應修改來滿足這樣一致性要求;與CAP中的C代表的含義是不同的。
  3. 隔離性(Isolation):如果有多個事務同時執行,彼此之間不需要知曉對方的存在,而且執行時互不影響,事務之間需要序列化執行,有時間順序。
  4. 永續性(Durability):事務的永續性是指事務執行成功以後,對系統狀態的更新是永久的,不會無緣無故回滾撤銷。

隔離所導致的一些問題

  1. 髒讀

    指一個事物讀取了另外一個事務未提交的資料

  2. 不可重複讀

    在一個事物內讀取表中的某一行資料,多次讀取結果不同。

  3. 虛度(幻讀)

    是指在一個事物內讀取到了別的事物插入的資料,導致前後讀取不一致

執行事物

-- ==========================事務========================
-- mysql 是預設開啟事務自動提交的
SET autocommit = 0;    -- 關閉
SET autocommit = 1;    -- 開啟

-- 手動處理事務
SET autocommit = 0;  -- 關閉自動提交

-- 事務開啟
START TRANSACTION    -- 標記一個事務的開始,從這個之後的sql都在同一個事物內

INSERT xx
INSERT xx   -- 兩個插入

-- 提交:持久化(成功)
COMMIT
-- 回滾:回滾到原來(失敗)

-- 事務結束
SET autocommit = 1   -- 開啟自動提交

-- 儲存點
SAVEPOINT 儲存點名  -- 設定一個事務的儲存點
ROLLBACK TO SAVEPOINT 儲存點名  -- 回滾到儲存點
RELEASE SAVEPOINT 儲存點名   -- 撤銷儲存點

7. 索引

7.1 索引的分類

在一個表中,主鍵索引只能有一個,唯一索引可以有多個

  • 主鍵索引(primary key)
    • 唯一的標識,主鍵不可重複,只能有一個列作為主鍵
  • 唯一索引(UNIQUE KEY)
    • 避免重複的列出現,唯一索引可以重複,多個列都可以標識為唯一索引
  • 常規索引(key/index)
    • 預設的 inde/key關鍵字來設定
  • 全文索引
    • 在特定的資料庫引擎下才有,MyISAM
    • 快速定位資料
-- 索引的使用
-- 1.在建立表的時候給欄位增加索引
-- 2.建立完畢後,增加索引

-- 顯示所有的索引資訊
 USE school
SHOW INDEX FROM student

-- 增加一個索引
ALTER TABLE `student` ADD FULLTEXT INDEX `studentname`(`studentname`)

-- explain 分析sql執行的狀況
EXPLAIN SELECT * FROM `student`

EXPLAIN SELECT * FROM student WHERE MATCH(`studentname`) AGAINST('張')

7.2 測試索引

-- 插入100萬條資料
DELIMITER $$    -- sql寫函式之前必須要寫的標誌
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
    DECLARE num INT DEFAULT 1000000;
    DECLARE i INT DEFAULT 0;
    WHILE i<num DO
	INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`,`password`,`age`) VALUES(CONCAT('使用者',i),'[email protected]',CONCAT('13',FLOOR(RAND()*((999999999-10000000)+10000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
	SET i=i+1;
    END WHILE;
    RETURN i;
END;

SELECT mock_data();
 
SELECT * FROM `app_user` WHERE `name`='使用者99999';  -- 1.463 sec
SELECT * FROM `app_user` WHERE `name`='使用者9999';   -- 1.038 sec

EXPLAIN SELECT * FROM `app_user` WHERE `name`='使用者99999';  


-- id_表名_欄位名
-- create Index 索引名 on 表(欄位)
CREATE INDEX id_app_user_name ON `app_user`(`name`)
SELECT * FROM `app_user` WHERE `name`='使用者99999';          --  0.164 sec
EXPLAIN SELECT * FROM `app_user` WHERE `name`='使用者99999';

索引在小資料量的時候,用處不大,但是在大資料量的時候,區別非常明顯

7.3

  • 索引不是越多越好
  • 不要對程序變動資料加索引
  • 小資料量的表不需要加索引
  • 索引一般載入常用來查詢的欄位上

索引的資料結構

https://blog.codinglabs.org/articles/theory-of-mysql-index.html

8.許可權管理和備份

8.1 使用者管理

SQLyog 檢視操作

sql 命令列

-- 建立使用者 create user 使用者名稱 identified by '密碼'
CREATE USER lzp IDENTIFIED BY '123456'

-- 修改密碼
SET PASSWORD = PASSWORD('1234567')

-- 修改指定使用者的密碼
SET PASSWORD FOR lzp = PASSWORD('123456')

-- 重新命名
RENAME USER lzp TO lzp2

-- 使用者授權 all privileges 全部許可權除了給別人授權,可以給庫,也可以給表設定許可權
GRANT ALL PRIVILEGES

-- 檢視指定許可權
SHOW GRANTS FOR lzp

SHOW GRANTS FOR root@localhost   -- GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION


-- 撤銷許可權 revoke 
REVOKE ALL PRIVILEGES ON *.* FROM lzp

-- 刪除使用者
DROP USER lzp

8.2MySQL備份

MySQL資料庫備份的方式

  • 直接拷貝物理檔案

  • 在sqlyog這種視覺化工具中手動到處

    • 在想要匯出的表或者庫中,右鍵,選擇備份或匯出

  • 使用命令列匯出 mysqldumo 命令列使用

# mysqldump -h 主機 -u 使用者名稱 -p 密碼 資料庫 表名 > 物理磁碟位置/檔名
mysqldump -hlocalhost -uroot -p123456 shcool student > D:/a.sql

# mysqldump -h 主機 -u 使用者名稱 -p 密碼 資料庫 表1 表2 表3 > 物理磁碟位置/檔名

# mysqldump -h 主機 -u 使用者名稱 -p 密碼 資料庫> 物理磁碟位置/檔名

# 資料庫的匯入
# 登入的情況下,切換到指定的資料庫
# source 備份檔案
source d:/a.sql


9.規範資料庫設計

9.1 良好的資料庫設計

  • 節省空間
  • 保證資料庫的完整性
  • 方便我們開發系統

9.2三大正規化

資料規範化:

  • 資訊重複
  • 更新異常
  • 插入異常
    • 無法正常顯示資訊
  • 刪除異常
    • 丟失有效的資訊

三大正規化

第一正規化

  • 原子性:保證每一列不可再分

第二正規化

  • 前提:滿足第一正規化
  • 每張表只描述一件事情

第三正規化

  • 滿足第二正規化
  • 需要確保資料表中的每一列資料都和主鍵相關,而不能間接相關。

阿里文件規定:關聯查詢的表不能超過三張表

  • 考慮商業化的需求和目標(成本、使用者體驗),資料庫的效能更加重要
  • 在規範效能的問題的時候,需要適當的考慮以下規範性
  • 故意給某些表增加一些冗餘的欄位
  • 故意增加一些計算列(從大資料量降低為小資料量的查詢:索引)

10.JDBC

10.1 資料庫驅動

10.2JDBC程式

新建資料庫

CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;

USE jdbcStudy;

CREATE TABLE `users`(
	id INT PRIMARY KEY,
	NAME VARCHAR(40),
	PASSWORD VARCHAR(40),
	email VARCHAR(60),
	birthday DATE
);

INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')

匯入資料庫驅動(匯入jar包)

import java.sql.*;

public class jdbcTest01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.載入驅動
        Class.forName("com.mysql.jdbc.Driver");

        //2. 使用者資訊和url
        //?useUnicode=true&characterEncoding=utf8&useSSL=true
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
        String username = "root";
        String password = "123456";

        //3.連線成功,資料庫物件Connection代表資料庫
        Connection connection = DriverManager.getConnection(url, username, password);

        // 4.執行SQL的物件Statement 來執行sql物件
        Statement statement = connection.createStatement();

        //5.執行sql的物件statement來執行sql語句,可能存在結果,要檢視返回結果
        String sql = "select * from users";
        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            System.out.println("id=" + resultSet.getObject("id"));
            System.out.println("name=" + resultSet.getObject("name"));
            System.out.println("pwd=" + resultSet.getObject("PASSWORD"));
            System.out.println("email=" + resultSet.getObject("email"));
            System.out.println("birth=" + resultSet.getObject("birthday"));
            System.out.println("==========================================");
        }

        //6.釋放連線
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步驟:

  1. 載入驅動
  2. 連線資料庫 DriverManager
  3. 獲得執行sql的物件Statement
  4. 執行sql,獲得返回的結果集
  5. 釋放連線

10.4 statement物件

jdbc中的statement物件用於向資料庫傳送sql語句,想完成對資料庫的增刪改查,只需要通過這個物件向資料庫傳送增刪改查語句。

statement物件的executeUpdate方法,用於向資料庫傳送增刪改的sql語句,執行完後會返回一個整數,該整數表示有幾行資料被影響

statemetn.executeQuery方法用於向資料庫傳送查詢語句,executeQuery方法返回代表查詢結果的ResultSet物件

程式碼實現

  1. 提取工具類

    package com.lzp.jdbc.util;
    
    import com.sun.org.apache.regexp.internal.RE;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    public class jdbcUtils {
        private static String driver = null;
        private static String url = null;
        private static String username = null;
        private static String password = null;
    
        static{
            try {
                InputStream in = jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
                Properties properties = new Properties();
                properties.load(in);
    
                driver = properties.getProperty("driver");
                url = properties.getProperty("url");
                username = properties.getProperty("username");
                password = properties.getProperty("password");
    
                Class.forName(driver);
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    
        }
    
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url,username,password);
        }
    
        public static void release(Connection conn, Statement stat, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(stat != null){
                try {
                    stat.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
    
    
    //db.properties
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
    username=root
    password=123456
    
  2. 編寫增刪改查的程式碼

    //增

    package com.lzp.jdbc.util;
    
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TestInsert {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet res = null;
    
    
    
            try {
                conn = jdbcUtils.getConnection();
                stat = conn.createStatement();
    
                String sql = "Insert into users(id,NAME,PASSWORD,email,birthday)values(4,'lzp','123456','[email protected]','2020-12-02')";
                int i = stat.executeUpdate(sql);
                if(i>0){
                    System.out.println("插入成功!");
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                jdbcUtils.release(conn,stat,res);
            }
    
        }
    }
    
    

    package com.lzp.jdbc.util;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TestDelete {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet res = null;
    
    
    
            try {
                conn = jdbcUtils.getConnection();
                stat = conn.createStatement();
    
                String sql = "delete from users where id=4";
                int i = stat.executeUpdate(sql);
                if(i>0){
                    System.out.println("刪除成功!");
                }
            } catch (
                    SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                jdbcUtils.release(conn,stat,res);
            }
        }
    
    }
    
    

    package com.lzp.jdbc.util;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TestUpdate {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet res = null;
    
    
    
            try {
                conn = jdbcUtils.getConnection();
                stat = conn.createStatement();
    
                String sql = "update users set name = 'lll' where id = 4";
                int i = stat.executeUpdate(sql);
                if(i>0){
                    System.out.println("修改成功!");
                }
            } catch (
                    SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                jdbcUtils.release(conn,stat,res);
            }
        }
    }
    
    

    package com.lzp.jdbc.util;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TestSelect {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet res = null;
    
    
    
            try {
                conn = jdbcUtils.getConnection();
                stat = conn.createStatement();
    
                String sql = "select name from users where id=4";
                res = stat.executeQuery(sql);
                while(res.next()){
                    System.out.println(res.getString("NAME"));
    
                }
    
            } catch (
                    SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                jdbcUtils.release(conn,stat,res);
            }
        }
    }
    
    

SQL注入問題

sql存在漏洞,會被攻擊導致資料洩露,就是SQL語句用or來拼接。

10.5PreparedStatement物件

PreparedStatement可以防止SQL注入。效率更好

package com.lzp.jdbc.lesson03;

import com.lzp.jdbc.util.jdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet res = null;

        try {
            conn = jdbcUtils.getConnection();
            String sql = "update users set name = 'lllzzzppp' where id = ?";
            stat = conn.prepareStatement(sql);

            stat.setInt(1,4);

            int i = stat.executeUpdate();

            if(i>0){
                System.out.println("修改成功!");
            }
        } catch (
                SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            jdbcUtils.release(conn,stat,res);
        }
    }
}
package com.lzp.jdbc.lesson03;

import com.lzp.jdbc.util.jdbcUtils;

import java.sql.*;

public class sqlRelease2 {
    public static void main(String[] args) {
        login("zhansan","123456");

    }

    public static void login(String username,String password){
        Connection conn = null;
        PreparedStatement stat = null;
        ResultSet res = null;

        try {
            conn = jdbcUtils.getConnection();
            //PreparedStatement 放置SQL注入的本質就是把傳遞進來的引數當作字元
            // 假設其中存在轉義字元 ‘ 會被直接轉義
            String sql = "select * from users where NAME=? and PASSWORD=?";
            stat = conn.prepareStatement(sql);

            stat.setString(1,username);
            stat.setString(2,password);


            res = stat.executeQuery();
            while(res.next()){
                System.out.println(res.getString("NAME"));
                System.out.println(res.getString("password"));
                System.out.println("==========================");

            }

        } catch (
                SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            jdbcUtils.release(conn,stat,res);
        }
    }
}

10.6資料庫連線池

池化技術:準備一些預先的資源,過來就連線預先準備好的。

最小連線數:10

最大連線數:15

等待超時:100ms

編寫連線池,需要實現一個介面DataSource

開源資料來源實現

  1. DBCP
  2. C3P0
  3. Druid

使用以上資料庫連線池之後,在專案開發中就不需要編寫連線資料庫的程式碼了。

DBCP

需要用到的jar包:

commons-dbcp-1.4.jar、commons-pool-1.6.jar

C3P0

需要用到的jar包

c3p0-0.9.5.5.jar、mchange-commons-java-0.2.19.jar

結論

無論使用什麼資料來源,本質還是一樣的,DataSource介面不會變,方法就不會變。