什麼是跨域?跨域解決方法
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是最好的關係資料庫管理系統應用軟體之一
開源的資料庫軟體
體積小、速度快、總體擁有成本低,
中小型、大型網站都有使用
安裝建議:
- 儘量不要使用exe進行安裝
- 儘可能使用壓縮包安裝
1.4安裝MySQL
-
下載MySQL壓縮包,並解壓。
-
配置環境變數,將mysql資料夾下的bin目錄新增到path中
-
新建配置檔案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資料夾。
配置檔案的最後一行表示的是跳過密碼驗證。
-
管理員模式下啟動CMD,進入mysql資料夾下的bin目錄,執行
mysqld -install
執行結束後會出現
Service successfully installed.
-
再輸入以下程式碼來初始化資料檔案
mysqld --initialize-insecure --user=mysql
這時候mysql資料夾下就會自動生成data目錄,命令列沒有報錯就表示初始化完成。
-
然後輸入以下命令啟動mysql,
net start mysql
-
使用以下命令進入mysql
mysql -u root -p
會出現讓你輸入密碼,由於密碼沒有設定,所以直接enter即可
-
使用命令來修改密碼,注意mysql中每一條命令都是分號
;
結尾的。update mysql.user set authentication_string=password('123456') where user ='root' and Host='localhost';
然後使用命令
flush privileges;
來重新整理許可權 -
修改my.ini檔案
將my.ini檔案的最後一行註釋掉,最後一行前面加
#
即可 -
重啟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
預設
- 設定預設的值
- 如果不賦值,就會自動賦值為你設定的預設值。
拓展:
每一個表都必須存在以下五個欄位
- id 主鍵
- version 樂觀鎖
- is_delete 偽刪除
- gmt_create 建立時間
- 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原則:原子性、一致性、隔離性、永續性
- 原子性(Atomicity):是指一個事務要麼全部執行,要麼完全不執行。
- 一致性(Consistency): 事務在開始和結束時,應該始終滿足一致性約束。比如系統要求A+B=100,那麼事務如果改變了A的數值,則B的數值也要相應修改來滿足這樣一致性要求;與CAP中的C代表的含義是不同的。
- 隔離性(Isolation):如果有多個事務同時執行,彼此之間不需要知曉對方的存在,而且執行時互不影響,事務之間需要序列化執行,有時間順序。
- 永續性(Durability):事務的永續性是指事務執行成功以後,對系統狀態的更新是永久的,不會無緣無故回滾撤銷。
隔離所導致的一些問題
-
髒讀
指一個事物讀取了另外一個事務未提交的資料
-
不可重複讀
在一個事物內讀取表中的某一行資料,多次讀取結果不同。
-
虛度(幻讀)
是指在一個事物內讀取到了別的事物插入的資料,導致前後讀取不一致
執行事物
-- ==========================事務========================
-- 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();
}
}
步驟:
- 載入驅動
- 連線資料庫 DriverManager
- 獲得執行sql的物件Statement
- 執行sql,獲得返回的結果集
- 釋放連線
10.4 statement物件
jdbc中的statement物件用於向資料庫傳送sql語句,想完成對資料庫的增刪改查,只需要通過這個物件向資料庫傳送增刪改查語句。
statement物件的executeUpdate方法,用於向資料庫傳送增刪改的sql語句,執行完後會返回一個整數,該整數表示有幾行資料被影響
statemetn.executeQuery方法用於向資料庫傳送查詢語句,executeQuery方法返回代表查詢結果的ResultSet物件
程式碼實現
-
提取工具類
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
-
編寫增刪改查的程式碼
//增
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
開源資料來源實現
- DBCP
- C3P0
- 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介面不會變,方法就不會變。