1. 程式人生 > 其它 >狂神說階段三——MySQL

狂神說階段三——MySQL

原視訊網站
https://www.bilibili.com/video/BV1NJ411J79W?p=7&t=17

1.初始MySQL

javaEE:企業級java開發 Web
前端 (頁面:展示資料)
後臺 (連線點,連線資料庫JDBC,連線前端:控制檢視跳轉,給前端傳遞資料)
資料庫 (存資料 txt,excel...)

只會寫程式碼,學好資料庫,基本混飯吃(大部分程式設計師)
作業系統,資料結構與演算法,當一個不錯的程式設計師
離散數學,數位電路,體系結構,編譯原理,實戰經驗。高階程式設計師,不怕被幹掉的

1.1 為什麼學習資料庫

  1. 崗位需求
  2. 現在的世界,大資料時代,得資料者得天下(如精準營銷)
  3. 被迫需求:存資料(例去IOE"去掉IBM的小型機、Oracle資料庫、EMC儲存裝置")
  4. 資料庫是所有軟體體系中最核心的存在 DBA (資料庫管理員)

1.2 什麼是資料庫

資料庫(DB DataBase)
概念: 資料倉庫、是一個軟體、安裝在作業系統(windows,linux,mac...)之上
作用:儲存資料,管理資料

1.3 資料庫分類

  • 關係型資料庫:SQL
    • MySQL,Oracle,Sql Server,DB2,SQLlite
    • 通過表和表之間,行和列之間的關係進行資料的儲存,學生資訊,考勤表...
  • 非關係資料庫: (NoSQL)Not Only
    • Redis,MonDB
    • 物件儲存,通過物件滋生的屬性來決定
  • DBMS資料庫管理系統
    • 資料庫管理軟體,方便獲取和維護管理我們的資料
    • MySQL 本質上是資料庫管理系統,可以管理我們的資料

1.4 MySQL簡介

(看簡介推薦去百度百科,然後抽取核心)
MySQL是一個關係型資料庫管理系統
前世:瑞典MySQL AB 公司開發
今生:Oracle 旗下產品
開源的,體積小、速度快、總體擁有成本低。(招人成本低,所以必須會)
中小型網站,或者大型網站(叢集)
https://www.mysql.com/
安裝建議(用的是穩定版5.7)
1.儘量不要使用exe,會修改登錄檔(解除安裝,可能寫在不乾淨)
2. 儘可能使用壓縮包安裝
mysql5.7 64位下載地址:

https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip

1.5 安裝

安裝步驟
1、下載後得到zip壓縮包,解壓

2、把這個包放到自己電腦環境目錄下

3、新增環境變數:我的電腦->屬性->高階->環境變數

選擇PATH,在其後面新增: 你的mysql 安裝檔案下面的bin資料夾

4、編輯 my.ini 檔案 ,注意替換路徑位置

[mysqld]
# 目錄一定要換成自己的
basedir = D:\Environment\mysql-5.7.19\
datadir = D:\Environment\mysql-5.7.19\data\
port=3306
skip-grant-tables

5、啟動管理員模式下的CMD,並將路徑切換至mysql下的bin目錄,然後輸入mysqld –install (安裝mysql)

6、再輸入 mysqld --initialize-insecure --user=mysql 初始化資料檔案

7、然後再次啟動mysql 然後用命令 mysql –u root –p 進入mysql管理介面(密碼可為空)

8、進入介面後更改root密碼

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

9、重新整理許可權

flush privileges;

10、修改 my.ini檔案刪除最後一句skip-grant-tables

11、重啟mysql即可正常使用

net stop mysql
net start mysql

12、連線上測試出現以下結果就安裝好了
安裝不成功執行 sc delete mysql 然後再重灌

1.6 安裝SQLyog(視覺化工具)

  1. 安裝註冊,預設的4個數據庫一個都不要動
  2. 新建一個數據庫
    滑鼠右鍵點選操作,每一個sqlyog的操作本質上都是執行的sql語句,都可以在歷史記錄中檢視
  3. 新建一張表student
    id,name,age

1.7 連線資料庫

命令列連線
所有語句都使用;結尾

mysql -uroot -p123456 --連線資料庫
update mysql.user set authentication_string=password('123456') where user='root'and Host = 'localhost';
--修改使用者密碼
flush privileges;--重新整理許可權
show databases;--檢視所有的資料庫
use DBname;--切換資料庫
show tables;--檢視資料庫中所有表
describe student;--顯示資料庫中所有的表的資訊
create database dbname;--建立資料庫
exit;--退出
--單行註釋(sql的註釋)
/*
多行註釋
*/

資料庫xxx語言
DDL 資料庫定義語言
DML 操作管理語言
DQL 查詢語言
DCL 控制

2. 操作資料庫

操作資料庫-》操作表-》操作表中資料
MySQL不區分大小寫

2.1 操作資料庫(瞭解)

1.建立資料庫
中括號項表示可選,大括號項表示必選

CREATE DATABASE [IF NOT EXISTS] westos

2.刪除資料庫

DROP DATEBASE [IF EXISTS] westos

3.使用資料庫
如果表名或者欄位名帶有特殊字元,需要帶`反引號

USE `school`
select `user` FROM student
  1. 檢視資料庫
show DATABASES--檢視所有的資料庫

學習思路:

  • 對比 sqlyog視覺化操作,檢視歷史紀錄裡的sql語句來學習
  • 固定語法或關鍵字必須要記住

2.2 資料型別

2.2.1 數值

  • tinyint 十分小的資料 1個位元組
  • smallint 較小的資料 2個位元組
  • mediumint 中等大小的資料 3個位元組
  • int 標準整數 4個位元組(常用的
  • big 較大的資料 8個位元組
  • float 浮點數 4個位元組
  • double 浮點數 8個位元組
    注:int(M)M表示顯示的寬度,不是實際儲存範圍
  • decimal 字串形式的浮點數 金融計算的時候,一般用decimal(常用

2.2.2 字串

  • char 固定大小的字串 0~255
  • varchar 可變大小的字串 0~65535(用來存常用的變數,對應java中string)
  • tinytext 微型文字 2^8-1
  • text 文字串 2^16-1 (儲存大文字)
    注 varchar(M)表示實際儲存的字元數

2.2.3 時間日期

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

2.2.4 null

  • 沒有值,未知
    **注意,不要使用NULL來運算,結果一定是NULL

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

  • Unsigned:
    • 無符號的**整數*
    • 聲明瞭該列不能宣告為負數
  • zerofill:
    • 0填充的
    • 不足的位數使用0來填充,int(3) (3表示顯示寬度為3,和儲存的範圍大小無關)輸入值為5,則實際儲存為005
  • 自增
    • 自動在上一條記錄的基礎上+1(預設+1,也可以自定義主鍵自增的起始值和步長)
    • 通常用來設計唯一的主鍵index,必須是整數型別
  • 非空 not null
    • 假設設定為not null,不賦值就會報錯
    • NULL,如果不填寫值,預設就是NULL
  • 預設:
    • 設定預設的值,如果不指定該列的值,則使用預設值
  • 擴充套件
    每張表必須存在以下5個欄位,未來做專案用的
    id 主鍵
    version 每條記錄都有個版本,用來做樂觀鎖的
    is_delete 偽刪除 標記為1後只有管理員才能檢視被刪除的資料
    gmt_create 建立時間 該記錄的建立時間
    gmt_update 修改時間

2.4 建立資料庫表(重點)

--注意點使用英文符號{},表的名稱和欄位儘量使用``反引號包起來
-- 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` VARCHA(2) NOT NULL DEFAULT '女' COMMENT '性別',
  `birthday` DATATIME DEFAULT NULL COMMENT '出生日期',
  `address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
  `email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
  PRIMARY KEY(`id`)
}ENGINE=INNODB DEFAULT CHARSET=utf8

格式:

CREATE TABLE [IF NOT EXISTS] `表名`{
  '欄位名' 列型別 [屬性] [索引] [註釋],
  '欄位名' 列型別 [屬性] [索引] [註釋],
  ...
  '欄位名' 列型別 [屬性] [索引] [註釋]
}[表型別][字符集集設定][表的註釋]

如果不記得怎麼寫,可以檢視已存在的資料庫或表的建立語句

SHOW CREATE DATABASE school --檢視建立資料庫的語句
SHOW CREATE TABLE student --檢視student資料表的定義語句
DESC student --顯示錶的結構

2.5 資料表的型別

資料庫引擎
INNODB 預設使用,MYISAM 早些年使用的。二者區別如下:

MYISAM INNODB
事務支援 不支援
資料行鎖定 不支援
外來鍵約束 不支援
全文索引 支援
表空間的大小 較小
  • 常規使用操作
    • MYISAM 節約空間,速度較快
    • INNODB 安全性高,事務的處理,多表多使用者操作
  • 在物流空間存在的位置
    所有的資料庫檔案都存在data目錄下,一個資料夾就對應一個數據庫
    本質還是檔案的儲存
    MySQL引擎在物理檔案上的區別
    • InnoDB在資料庫表中只有一個*.frm檔案以及上級目錄下的ibdata1檔案
    • MYISAM對應檔案
      • *.frm--表結構定義的檔案
      • *.MYD 資料檔案(data)
      • *.MYI 索引檔案(index)
  • 設定資料庫表的字符集編碼
    CHARSET=utf8
    不設定使用預設字符集Latin1編碼,不支援中文
    可以修改my.ini配置編碼 character-set-server=utf8,但最好每次建立表時都加一句CHARSET=uft8.這樣這張表拿到別人那沒設定配置檔案也可以用

2.6 修改刪除表

修改

--修改表名: ALTER TABLE 舊錶名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS teacher1
--增加表的欄位: ALTER TABLE 表名 ADD 欄位名 列屬性
ALTER TABLE teacher1 ADD age INT(11)
--修改表的欄位(重新命名,修改約束)
-- 修改約束:ALTER TABLE 表名 MODIFY 欄位名 新列屬性 
-- 重新命名: ALTER TABLE 表名 CHANGE 舊名字  新名字 列屬性[]
ALTER TABLE teacher MODIFY age VARCHAR(11) --修改約束
ALTER TABLE teacher CHANGE age age1 INT(1) --欄位重新命名
--刪除表的欄位: ALTER TABLE 表名 DROP 欄位名
ALTER TABLE teacher1 DROP age1
--刪除表
DROP TABLE IF EXISTS teacher

注:* change用來修改欄位名,modify用來修改約束
* 所有建立和刪除操作儘量加上判斷,以免報錯
* ``欄位名用反引號包裹(防止和關鍵字重複)
* 註釋-- /* */
* sql 關鍵字大小寫不敏感,建議使用小寫,方便閱讀
* 所有符號都用英文

3 MySQL資料管理

3.1 外來鍵 (瞭解即可)

刪除表A,如果表A(主表)存在表B(從表)的外來鍵引用,先要把表B刪除,才能刪除表A(被引用表)

  • 建立外來鍵方式一
CREATE TABLE `grade`{
  `gradeid` INT(10)  NOT NULL AUTO_INCREMENT COMMENT '年級id',
  `gradename` VARCHAR(50) NOT NULL COMMENT '年級名稱',
   PRIMARY KEY (`gradeid`)
} ENGIN = INNODB DEFAULT CHARSET =utf8
--學生表的gradeid欄位要去引用年級表的gradeid欄位
--定義外來鍵
--給這個外來鍵新增約束(執行引用)
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` VARCHA(2) NOT NULL DEFAULT '女' COMMENT '性別',
  `birthday` DATATIME DEFAULT NULL COMMENT '出生日期',
  `gradeid` INT(10)  NOT NULL AUTO_INCREMENT COMMENT '學生年級',
  `address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
  `email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
  PRIMARY KEY(`id`),
  KEY `FK_gradeid` (`gradeid`),
  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
}ENGINE=INNODB DEFAULT CHARSET=utf8
  • 方式二
    建立表的時候沒有外來鍵關係
    ALERT TABLE 表名 ADD CONSTAINT 約束名 FOREIGN KEY(作為外來鍵的列) REFERENCE 被引用表名 (被引用欄位)
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade` (`gradeid`)

以上操作都是資料庫級別的物理外來鍵,不建議使用。(避免資料庫過多造成困擾,這裡瞭解即可)
最佳實踐

  • 資料庫就是單純的表,只用來存資料,只有行(資料)和列(欄位)
  • 我們項使用多張表的資料,想使用外來鍵(用程式去實現)

3.2 DML語言(全部記住)

資料庫存在意義:資料儲存,資料管理
DML語言: 資料操作語言
insert, update,delete

3.2.1 insert

INSERT INTO 表名([欄位名1,欄位2,欄位3])values ('值1','值2','值3'),('值1','值2','值3')
插入語句一定要欄位和值一一對應

INSERT INTO `grade` (`gradename`) VALUES('大三')
--一次插入多行
INSERT INTO `grade` (`gradename`) VALUES('大三')('大四')
--多行多欄位(下例兩行)
INSERT INTO student(`name`,`pwd`,`sex`) VALUES('李四','12324','男'),('王五','232434','女')

注意事項:

  1. 欄位和欄位之間使用 英文逗號隔開
  2. 欄位是可以省略的,但是表裡後面的值要都列出來,一一對應
  3. 可以同時插入多條資料,VALUES後面的值,需要使用逗號隔開 value(),()...
  • update
  • delete

3.2.2 修改

語法(關鍵字大寫)
UPDATE 表名 SET column_name = value [, column_name2 = value..] WHERE[條件]

--加where條件,修改指定的行
UPDATE `student` SET `name` ='xiaoming' WHERE id=1;
--不加where條件,修改的是整張表
UPDATE `student` SET `name`='xiaohong' ;
--同時修改多個欄位
UPDATE `student` SET `name`='xiaofang', email='[email protected]' WHERE id=1;
--多個條件定位資料
UPDATE `student` SET `name`='長江7好' WHERE `name`='xiaoming` AND sex ='女';
--value可以是個變數
UPDATE `student` SET `birthday`=CIRRENT_TIME WHERE `name`='長江7好' AND sex ='女'

條件
where 子句 運算子 id等於某個值,大於某個值,在某個區間內修改...
注意:

  • column_name 是資料庫的列,儘量帶上``
  • 條件,篩選的條件,如果沒有指定則會修改所有的列
  • value 可以是個具體的值,也可以是個變數(通常是時間)
  • 設定多個屬性,用英文逗號隔開(java操作,通常用trim把最後一個逗號剪掉)

3.2.3 刪除

語法
DELETE FROM 表名 WHERE

--避免這種寫法刪除整張表,要帶條件
DELETE FROM `student`;

--刪除指定資料
DELETE FROM `student` WHERE id=1;
``
**TRANCATE清空命令**
作用:完全清空一個表,表的結構和約束不會變
```sql
TRANCATE `student`
操作符 含義
‘=’ 等於
<>或者!= 不等於
>
<
<=
>=
BETWEEN…AND.. [a,b]閉合範圍內
AND && 兩個條件同時成立
OR

** DELETE和TRANCATE的區別**

  • 相同點都能刪除資料,而且都不會刪除表結構
  • 不同點
    • TRANCATE 不同於delete重新設定自增列,計數器會歸零,不會影響事務(推薦)
      DELETE刪除的問題,重啟資料庫現象
  • INNODB 自增列重新從1開始(存在記憶體中,斷電即失)
  • MyISAM 繼續從上一個自增量開始(存在檔案中,不會丟失)

4 DQL查詢資料(最重點)

(Data Query Launguage)

  • 所有的拆線呢操作都用它,Select
  • 簡單的查詢,複雜的查詢都能做
  • 使用頻率最高的最核心的語言
SELECT [ALL|DISTINCT]
{
*|table.*|table.field1[as alias1][,table.field2[as alias2]][,....]]}--查哪些欄位
From table_name [as table_alias] --從哪個表查
      [left|right|inner join table_name2]--聯合查詢
      [WHERE...]--指定結果需要滿足的條件
      [GROUP BY..]--指定結果按照哪幾個欄位來分組
      [HAVING]--過濾分組的記錄必須滿足的次要條件
      [ORDER BY...]--指定查詢記錄按一個或多個條件排序
      [LIMIT {[offset,]row_count|row_countOFFSET offset}];
      --指定查詢記錄從哪條至哪條  
}

中括號可選,大括號必選,注意遵守先後順序

4.1 SELECT語法

語法:
SELECT 欄位1 ... FROM 表名

有時候,列的名字不是那麼的見名知意,我們起別名,AS 欄位名 as 別名 表名 AS 別名

--查詢全部的學生
SELECT * FROM student
--查詢指定欄位
SELECT `StudentNo`,`StudentName` FROM student
--別名,給查詢結果欄位起別名,結果列名就是這個別名,給表起別名用於多表查詢
SELECT `StudentNo` AS 學號, `StudentName` AS 學生姓名 FROM student AS s
--函式 CONCAT(a,b)字串拼接
SELECT CONCAT('姓名:',StudentName) AS 新名字 FROM student

4.2 去重

使用distinct 去除SELECT** 查詢結果**中重複的資料,重複就只顯示一條
注意distinct只區別目標欄位,所有目標欄位有一個不重複就是不同的

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

4.3 資料庫列表達式

資料庫中的表示式:文字值,列,Null,函式,計算表示式,系統變數...
select 表示式 from 表

SELECT VERSION()         --查詢系統版本(函式)
SELECT 100*3-1 AS 計算結果 --用來計算(表示式)
SELECT @@auto_increment_increment --查詢自增的步長(變數)
--學員考試成績+1分檢視
SELECT `StudentNo`,`StudentResult`+1 AS '提分後' FROM result

4.4 where條件子句

作用:檢索資料中符合條件的值
搜素條件由一個或者多個表示式組成,結果為布林值,儘量使用英文關鍵字,可讀性提高

  • 邏輯運算子
運算子 語法
and && a and b , a && b
or a or b, a
Not ! not a ! A
SELECT studentNo, `StudentResult` FROM result
-- 查詢考試成績在95-100之間的
SELECT studentNo, `StudentResult` FROM result WHERE StuentResult>=95 AND StudentResult<=100
--使用between andd(區間)
SELECT studentNo, `StudentResult` FROM result WHERE StudentResult BETWEEN 95 AND 100
-- 除了1000號學生之外的同學的成績
SELECT studentNo,`StudentResult` FROM result WHERE studentNo!=1000;
SELECT studentNo,`StudentResult` FROM result WHERE NOT studentNo=1000;
  • 模糊查詢:比較運算子
運算子 語法
IS NULL a is null 為真
IS NOT NULL a is not null 為真
BETWEEN a between b and c, a在[b,c]為真
Like a like b,如果a能夠匹配b 則結果為真
In a in(a1,a2,a3..),a 在後面的集合裡,則結果為真

like結合%(%代表0到任意個字元)_(代表一個字元), in後面是具體的值不和符號結合使用

--查詢姓劉的同學
SELECT `StudentNo`,`StudentName` FROM 'student' WHERE StudentName LIKE '劉%'
--查詢姓劉的同學,名字後面只有一個字
SELECT 'StudentNo','StudentName' FROM 'student' WHERE StudentName LIKE '劉_'
--查詢姓劉的同學,名字後面有兩個字
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)

--==null not null==
--查詢地址為空的學生 null ''
SELECT 'StudentNo','StudentName' FROM 'student' WHERE address='' OR address IS NULL
--查詢有出生日期的同學 不為空
SELECT 'StudentNo','StudentName' FROM 'student' WHERE 'BornDate' IS NOT NULL

4.5 聯表查詢

Join .. on

7 Join 操作符 描述
1 left join … on左連線 左表的全部,右表不滿足的列補空NULL
2 right join 右連線 右表的全部,左表不滿足的列補空
3 left join B.key is null 只保留左表特有的資料,右表裡沒有
4 inner join 內連線 只輸出左右表均存在的記錄(交集)
5 right join A.key is null 只保留右表特有的資料
6 full outer join/union 合併左,右外連線結果集 獲取左右表所有記錄,各自沒有時補空
7 "full outer join key is null 從合併左右外連線結果集裡查詢a.key=null 或者B.key=null" 獲取兩表連線交集的補集
  • where 是用來做篩選條件的
  • join...on才是連線查詢,通常使用on

寫sql語句思路:

  1. 確定要查哪些資料select ...
  2. 從那幾張表種查, FROM表, XXX Join連線的表, on 交叉條件
  3. 如存在多表查詢,慢慢來,先查詢兩張表然後再逐步增加連表
---查詢參加了考試的同學(學號,姓名,科目編號,分數)
/*思路
1.分析需求,查詢的欄位來自哪些表,多表需要聯合查詢
2.確定使用過那種連線查詢?7 種
確定交叉點,這兩個表中哪個資料是相同的
判斷的條件:學生表中的studentNo = 成績表中的studentNo
*/
--Inner join,此時where 和on等效,但是在其他查詢裡是不一樣的
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student AS s
INNER JOIN result AS r WHERE s.studentNO = r.studentNO
--Right JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student s RIGHT JOIN
result r ON s.studentNO=r.studentNO
--left JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student s LEFTJOIN
result r ON s.studentNO=r.studentNO
--查詢缺考的同學
SELECT s.studentNO,studentName,SubjectNo,StudentResult
FROM student s LEFT JOIN result r ON s.studentNO = r.studentNO WHERE StudentResult IS NULL
--查詢參加考試的同學資訊:學號,學生姓名student,科目名subject,分數score(三表查詢)
SELECT s.studentNo,studentName,SubjectName,'StudentResult' FROM student s RIGHT JOIN
result ON r.studentNo=s.studentNo INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo

4.6 自連線查詢

自己的表和自己連線

  `CREATE TABLE `category` {
  `categoryid ` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主題id',
  `pid` INT(10) NOT NULL COMMENT '父id',
  'categoryName' VARCHAR(50) NOT NULL COMMENT '主題名字',
  PRIMARY KEY('categoryid')
}
INSERT INTO `category` (`categoryid`,`pid`,`categoryName`)
VALUES('2','1','資訊科技').
('3','1','軟體開發'),
('4','3','資料庫'),
('5','1','美術設計'),
('6','3','web開發'),
('7','5','ps技術'),
('8','2','辦公資訊');
}

原始的單表如下,是個樹形結構

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

可以拆成如下兩張表
父類(pid為1的):

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

子類:

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

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

父類 子類
資訊科技 辦公資訊
軟體開發 資料庫
軟體開發 web開發
美術設計 ps技術
--查詢父子關係:把一張表看作兩張一摸一樣的表即可
SELECT a.`categoryName` AS '父欄目',b.`categoryName` AS '子欄目'
FROM `category` AS a, `category` AS b WHERE a.`categoryid` = b.`pid`

4.7 排序ORDER BY和分頁LIMIT

--排序 升序 ASC,降序DESC
SELECT S.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN `result` r
ON s.StudentNo = r.`StudentNo`
INNER JOIN `subject` sub ON r.`SubjectNo`=sub.SubjectNo`
WHERE subjectName = '資料庫結構-1'
ORDER BY `StudentResult` DESC --降序排列

--分頁,緩解資料庫壓力,給人更好的體驗
--(百度圖片沒使用分頁,而是用瀑布流)

--語法:limit 起始值,頁面顯示的資料行數大小
--LIMIT 0,5 1~5
--LIMIT 1,5 2~6
--LIMIT 6,5 第二頁
SELECT S.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN `result` r
ON s.StudentNo = r.`StudentNo`
INNER JOIN `subject` sub ON r.`SubjectNo`=sub.SubjectNo`
WHERE subjectName = '資料庫結構-1'
ORDER BY `StudentResult` DESC
LIMIT 6,5
/*
網頁應用:當前curPage,總資料量,頁面的大小pageSize(展示多少條資料)
firstIndex=(curpage-1)*pageSize
lastIndex=curPage*PageSize
pages=(total+pageSize-1)/pageSize
*/
--查詢JAVA 第一學年課程成績排名前十的學生,並且分數要大於80的學生資訊(學號,姓名,課程名稱,分數)
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN result r ON s.studentNo=r.studentNo
INNER JOIN subject sub ON r.SubjectNo=sub.SubjectNo
Where subjectName='JAVA 第一學年' AND StudentResult>80
ORDER BY StudentResult DESC
LIMIT 0,10

4.8 子查詢

where(子句判斷條件是計算出來的)
本質:在where 語句種巢狀一個子查詢, where(select * from)
通常子查詢效率要比連表查詢效率低

--1. 查詢資料庫結構-1的所有考試結果(學號,科目編號,成績)降序排列
--方式一使用連線查詢
SELECT s.`StudentNo`,'SubjectNo','StudentResult'
FROM result r 
INNER JOIN subject sub ON r.SubjectNo=sub.SubjectNo
WHERE SubjectName='資料庫結構-1' 
ORDER BY StudentResult DESC
--方式二使用子查詢(由裡及外,相當於小學生分步計算)
--查詢所有資料庫結構-1的學生學號
SELECT SubjectNo FROM `subject` WHERE SubjectName='資料庫結構-1'
--組合子查詢條件
SELECT `StudentNo`,`SubjectNo`,`StudentResult` FROM student
WHERE SubjectNo = (
SELECT SubjectNo FROM `subject` WHERE SubjectName='資料庫結構-1')
ORDER BY StudentResult DESC

--分數不小於80分的學生的學號和姓名
SELECT s.StudentNo, StudentName FROM student 
INNER JOIN result r ON r.StudentNo = s.StudentNo
WHERE `StudentResult`>=80 AND `SubjectNo` = 
(SELECT SubjectNo FROM `subject` WHERE `SubjectName`='高等數學-2')
--再改造
SELECT StudentNo, StudentName FROM student 
WHERR studentNo IN (SELECT StudentNo from result 
WHERE StudentResult>=80 AND subjectNo = (
SELECT subjectNo from subject WHERE subjectName='高等數學-2'))

4.9 過濾和分組

  • 當時用GROUP BY後,不能再使用where來限制條件篩選,而是使用HAVING來進行分組篩選
  • GOURP BY 一般結合聚合函式使用(多個輸入一個輸出,如AVG平均值,MAX最大值),因為分組後有的列入數學對應多個學生的分數,需要寫在一個單元格里,不再是多個單元格
--查詢不同課程的平均分,最高分,最低分
-- 根據不同的課程分組
SELECT `SubjectName`, AVG(StudentResult), MAX(StudentResult),MIN(StudentResult)
FROM result r INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo
GOURP BY `r.subjectNo` --通過什麼分組
--增加條件 查詢不同課程的平均分,最高分,最低分,且要求平均分大於80分
SELECT `SubjectName`, AVG(StudentResult) AS 平均分, MAX(StudentResult),MIN(StudentResult)
FROM result r INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo
GOURP BY `r.subjectNo`
HAVING 平均分>80

實際應用中sql查詢跨表,跨資料庫,本地資料庫遠端資料庫等等,複雜度增加(淘寶頁面千人千面)

5 MySQL函式

官網https://dev.mysql.com/doc/refman/5.7/en/built-in-function-reference.html

5.1 基本函式

--========數學運算======
SELECT ABS(-8) --絕對值
SELECT CEILING(9.4) --向上取整
SELECT FLOOR(9.4)--向下取整
SELECT RAND()--返回一個0~1之間的隨機數
SELECT SIGN(10) --判斷符號,正數返回1,負數返回-1
---字串函式
SELECT CHAR_LENGTH('即使在校的帆,也能遠航')--字串長度
SELECT CONCAT('世界','之大','無奇','不有')
SELECT INSERT('我愛程式設計helloworld',1,2,'超級熱愛')--插入替換,我愛-->超級熱愛
SELECT UPPER('hello')
SELECT LOWER('HEllo')
SELECT INSTR('hello world','r')--返回第一次出現的字串的索引
SELECT REPLACE('堅持就是勝利','堅持','努力')--替換指定字串
SELECT SUBSTR('堅持就是勝利',4,1)--擷取字串
SELECT REVERSE('堅持就是勝利')--反轉
--舉例
SELECT REPLACE(studentname,'周','鄒')FROM student
WHERE studentName LIKE '周%'
--時間和日期函式
SELECT CURRENT_DATE()--獲取當前日期
SELECT NOW()--獲取當前時間
SELECT LOCALTIME()--獲取本地時間
SELECT SYSDATE() --獲取系統時間
SELECT YEAR(NOW())--獲取年(時分秒類似)
--系統
SELECT SYSTEM_USER()
SELECT USER() --同上獲取系統當前使用者
SELECT VERSION()

5.2 聚合函式(常用)

函式名稱 描述
COUNT() 計數
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值

想查詢一個表中有多少記錄,就使用COUNT
注意COUNT(*),COUNT(1),COUNT(列名)都會統計行數,但略有不同

  • COUNT(列名)會進行非NULL判斷,只有非NULL才會進入統計
    COUNT(*),COUNT(1)都統計所有行數,不論是否是NULL
  • COUNT(1)可以想象成表有個固定欄位1,對其進行統計
  • COUNT(*)則會根據Mysql的優化自動指定到效率高的欄位上
  • 有主鍵的情況下COUNT(主鍵)查索引速度最快
--COUNT(*) COUNT(1) COUNT(列名)
SELECT COUNT(studentname) FROM student;--Count指定列
SELECT COUNT(*) FROM student;
SELECT COUNT(1) FROM student;

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

5.3 資料庫級別的MD5加密(擴充套件)

什麼事MD5? 不可逆的演算法,具體值對應的md5值是一致的。
MD5破解網站的原理,背後有一個字典,輸出MD5加密後的值,查表返回加密前的值

--測試MD5加密
CREATE TABLE 'testmd5'{
  `id` INT(4) NOT NULL,
  `name` VARCHAR(20) NOT NULL,
  `pwd` VARCHAR(50) NOT NULL,
    PRIMIARY KEY(`id`)
} ENGINE=INNODB DEFAULT CHARSET=utf8
--明文密碼
INSERT INTO testmd5 VALUES (1,'zhangsan','123456'),(2,'lisi','123434'),
(3,'wangwu','1234346')
--加密
UPDATE testmd5 SET pwd=MD5(pwd) --加密全部的密碼
--插入的時候加密
INSERT INTO testmd5 VALUES (4,'xiaoming',MD5('34343434'))
--如何校驗:將使用者傳遞進來的密碼,進行md5加密,比較加密後的值
SELECT * FROM testmd5 WHERE `name`='xiaoming' AND pwd=MD5('123456')

6. 事務

6.1 什麼是事務

  • 事務原則:ACID 原子性(Atomicity),一致性(Consisitency),隔離性(Isolation),永續性(Durability)
    • 原子性:要麼都成功,要麼都失敗,一組SQL放在一個批次中執行
---------
1. SQL 執行 A給B轉賬 A:1000->200 B:200
2. SQL 執行 B收到A的錢 A:800  B:400
---------
  • 一致性:事務操作前後資料的完整性是保持一致的,如A,B賬戶錢的總和在轉帳前後保持一致
  • 永續性: 事務一旦提交就不可逆不受事故影響了。假設出現事故,如斷電,事務沒有提交,資料庫回覆到原有狀態;事務已經提交了,持久化到資料庫,重啟後仍然是持久化後的狀態。
  • 隔離性:多個使用者併發訪問資料庫時,資料庫為每個使用者開啟單獨的事務,事務間相互隔離,排除其他事務對本次事務的影響
  • 事務的隔離級別(隔離所產生的問題)
    • 髒讀:一個事務讀取另外一個事務未提交的資料
    • 不可重複讀:在一個事務內讀取表的某一行資料,多次讀取結果不一樣(如第二次讀之前,有人轉錢了,賬戶餘額變多了),這個不一定是錯誤,只是某些場合不對。
    • 幻讀(虛讀) 指在一個事務內讀取到了別的事務插入的資料,導致前後讀取不一致(如多了一行)
      參考連結:https://blog.csdn.net/dengjili/article/details/82468576

6.2 處理事務sql

--mysql是預設開啟事務自動提交的
SET autocommit = 0 /*關閉自動提交*/
SET autocommit = 1 /*開啟自動提交*/
--手動處理事務
SET autocommit = 0
--事務開啟
START TANSACTION -- 標記一個事務的開啟,從這個之後的sql都在同一個事務內
INSERT XX
INSERT XX
--提交:持久化(成功)
COMMIT
--回滾:回到原來的樣子(失敗)
ROLLBACK
--事務結束
SET autocommit = 1
--儲存點了解,(玩遊戲掛掉,回到相應的關卡)
SAVEPOINT 儲存點名 --設定一個事務的儲存點
ROLLBACK TO SAVEPOINT 儲存點名--回滾到儲存點
RELEASE SAVEPOINT 儲存點名--撤銷儲存點

CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf_8_general_ci--核對COLLATE
USE shop
CREATE TABLE `account` {
  `id` INT(3) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(30) NOT NULL,
  `money` DECIMA(9,2) NOT NULL.
  PRIMARY KEY ('id')
}ENGINE=INNODE DEFAULT CHASET=utf8
INSERT INTO account(`name`,`money`)
VALUES('A',2000.00),('B',1000.00)
----模擬轉賬:事務
SET autocommit=0;
START TRANSACTION
UPDATE account SET money=money-500 WHERE `name`='A'--A減500
UPDATE account SET money=money+500 WHERE `name`='B'--B加500

COMMIT;--提交事務
ROLLBACK;
SET autocommit=1; --恢復預設值

7 索引

https://blog.csdn.net/wufuhuai/article/details/79631466 (講的比較深的mysql原理,待看)

MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取資料的資料結構
索引的本質是資料結構。

7.1 索引的分類

  • 主鍵索引(PRIMARY KEY)
    • 唯一標識,主鍵不可重複,表中只能有一個列作為主鍵,不能為null
  • 唯一索引 (UNIQUE KEY)
    • 被標識的列值不可以重複,在一個表中帶唯一索引的列可以有多個
      主鍵一定是唯一性索引,但是唯一索引不一定是主鍵
  • 常規索引 (KEY/Index)
    • 預設的用Index/Key關鍵字來設定
  • 全文索引(FullText)
    • 在特定的資料庫引擎下才有,Myisam,作用快速定位資料,用關鍵字FULLTEXT INDEX

7.2 索引的使用

  • 建立索引兩種方法
    1.在建立表的時候CREATE給欄位增加索引
    2.建立完畢後,增加索引 ALTER TABLE 表名 ADD xxx INDEX 索引名(列名)
    3. 在表上加索引,索引命名方式 id_表名_欄位名
    語法: CREATE INDEX 索引名 on 表(欄位)
--顯示所有的索引資訊
SHOW INDEX FROM student
--增加一個全文索引 (索引名)列名,查詢的時候有索引的列會快一點
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`studentName`);

  • 索引建立完使用,是指查詢的時候自動使用,加快搜索
  • explain分析sql執行的情況
    語法:explain+SQL語句
-- EXPLAIN 分析sql執行的情況
EXPLAIN SELECT * FROM student WHERE MATCH(studentName) AGAINST('劉')

explain的使用參考https://blog.csdn.net/jiadajing267/article/details/81269067

  • 測試索引
    給app_user表加入1000000條測試資料
--插入100萬的資料(寫sql函數了解即可)
DELIMITER $$ --寫函式之前必須要寫的標誌
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
  DECLARE num INT DEFAULT 1000000;
  DECLARE i INT DEFAULT 0;
  WHILE i<num DO
    --插入語句
    --currenttime, update time 不用手動寫,勾選了自動更新
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('使用者',i),'[email protected]',CONCAT('18',FLOOR(RAND()*(999999999-100000000))+100000000)),
FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
    SET i = i+1;
  END WHILE
  RETURN I;
END;

建立索引,索引命名id_表名_欄位名
比較加上索引和沒加索引查詢速度

SELECT * FROM app_user WHERE `name`='使用者9999';--1sec左右的執行時間
EXPLAIN SELECT * FROM app_user WHERE `name`='使用者9999';--查了9000多條資料

--id_表名_欄位名
--CREATE INDEX 索引名 on 表(欄位)
CREATE INDEX id_app_user_name ON app_user(`name`);
--此時再查使用者9999速度飛起
SELECT * FROM app_user WHERE `name`='使用者9999';--0.001 sec
--rows為1行,相當於唯一定位了,key value查詢
EXPLAIN SELECT * FROM app_user WHERE `name`='使用者9999';

索引再小資料量的時候,差別不大,但是大資料時十分明顯

7.3 索引原則

  • 索引不是越多越好

  • 不要對經常變動的資料加索引

  • 小資料量的表不需要加索引

  • 索引一般加在常用來查詢的欄位上

  • 索引的資料結構
    Hash型別的索引
    Btree:InnoDB的預設資料結構

--業務級的mysql
--運維級的mysql 負載均衡,mysql底層

8.許可權管理和備份

8.1 使用者管理

  • SQLyog 可是化管理
  • SQL 命令操作
    在資料庫目錄下有張user使用者表,增加刪除使用者就是對該表進行增刪改查
--建立使用者 CREATE USER 使用者名稱 IDENTIFIED BY '密碼'
CREATE USER xiaoming IDENTIFIED BY '123456'
--修改當前使用者的密碼
SET PASSWORD = PASSWORD('1232434')
--修改指定使用者密碼
SET PASSWORD FOR xiaoming= PASSWORD('12323233')
--重新命名 RENAME USER 原名字 TO 新名字
RENAME USER xiaoming TO xiaolan
--使用者授權 ALL PRIVILEGES 全部的許可權(除了給別人授權). 庫.表
GRANT ALL PRIVILEGES ON *.* TO xiaolan
--查詢許可權
SHOW GRANTS FOR xiaolan --檢視指定使用者的許可權
--root的許可權查出來是GRAN ALL PRIVILEGES ON *.* TO 'root@localhost' WITH GRANT OPTION
SHOW GRANTS FOR root@localhost
--撤銷許可權 REVOKE 哪些許可權,在哪個庫表,給誰撤銷
REVOKE ALL PRIVILEGES ON *.* FROM xiaolan
--刪除使用者
DROP USER xiaolan

8.2 資料庫備份

為什麼要備份:

  • 保證資料不丟失
  • 資料轉移
    MySQL資料備份的方式
  • 直接拷貝物理檔案 data資料夾
  • 在Sqlyog這種視覺化工具中手動匯出
    右鍵想要匯出的表或資料庫->轉儲到sql,選結構和資料,其他預設
  • 使用命令列在終端上匯出 mysqldump (對於windows系統指的是cmd彈出的終端)
# ======匯出======
# mysqldump -h 主機 -u 使用者名稱 -p密碼 資料庫 表名>物理位置
mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
# dump多張表
# mysqldump -h 主機 -u 使用者名稱 -p密碼 資料庫 表名1 表名2 表名3>物理位置
mysqldump -hlocalhost -uroot -p123456 school student result>D:/b.sql
# dump資料庫
mysqldump -hlocalhost -uroot -p123456 school >D:/db.sql
#======匯入=======
# 先登入
mysql -uroot -p123456
# 切換到指定的資料庫
use school
# 匯入,登入的情況下切換到指定的資料庫,source備份的檔案
source d:/a.sql
# 第二種匯入方法
mysql -u使用者名稱 -p密碼 庫名<備份檔案

9 規範資料庫設計

9.1 為什麼需要設計

當資料庫比較複雜的時候,我們就需要設計了
糟糕的資料庫設計:

  • 資料冗餘,浪費空間

  • 資料庫插入和刪除都會比較麻煩,異常【遮蔽使用物理外來鍵】

  • 程式的效能差
    良好的資料庫設計:

  • 節省記憶體空間的

  • 保證資料庫的完整性

  • 方便我們開發系統的
    軟體開發中,關於資料庫的設計

  • 分析需求: 分析業務和需要處理的資料庫的需求

  • 概要設計:設計關係圖E-R圖
    設計資料庫的步驟:(個人部落格)

  • 收集資訊,分析需求

    • 使用者表(使用者登入登出,使用者的個人資訊,寫部落格,建立分類)
    • 分類表(文章分類,誰建立的)
    • 文章表(文章的資訊)
    • 友連結串列(友鏈資訊)
    • 自定義表(系統資訊,某個關鍵的字,或者一些主欄位 key:value)可選項
    • 說說表(發表心情..id...content...create_time)
      comments表,user_id_parent回覆評論形式,查詢時單表自聯接

      links表

      user表

      user_follow表(中間表)

      category分類表

      blog表
  • 標識實體,實現功能時表與表之間的關係(把需求落地到每個欄位)

    • 寫部落格:user->blog
    • 建立分類:user->category
    • 關注:user->user
    • 友鏈:links
    • 評論:user->user->blog
      常見的系統:部落格,論壇,CRM管理系統
      注:資料庫裡欄位使用下劃線_分隔,儘量不要使用駝峰命名,因為資料庫不區分大小寫

9.2 三大正規化

  • 為什麼需要資料規範化?
    • 資訊重複(如兩張表裡都寫username 和userid)
    • 更新異常
    • 插入異常
      • 無法正常顯示資料(插入資訊不完整,多張表重複欄位,漏插入)
    • 刪除異常
      • 丟失有效的資訊
  • 三大正規化
    (注:檢索概念的時候,搜那些有例子的部落格,方便理解,不要純文字)
    參考 https://www.cnblogs.com/wsg25/p/9615100.html
    • 第一正規化(1NF)
      原子性:保證每一列不可以再分
    • 第二正規化(2NF)
      滿足第一正規化的前提下,每張表只描述一件事情,產品,或者訂單是兩張不同的表,不能混在一起談
    • 第三正規化
      滿足一二正規化的前提下,確保資料表中的每一列水簌俱都和主鍵直接相關,而不能間接相關
  • 規範性和效能的問題
    關聯查詢的表不能超過三張
    • 考慮商業化的需求和目標,(成本,使用者體驗等考慮)資料庫的效能更加重要
    • 在規範效能的問題的時候,需要適當的考慮一下規範性
    • 故意給某些表增加一些冗餘的欄位,從多表查詢變成單表查詢
      如訂單-商品id,還增加了商品資訊
    • 故意增加一些計算列(從大資料量計算,降為小資料兩的查詢)

10. JDBC(重點)

10.1 資料庫驅動

類似於音效卡顯示卡,資料庫也需要有安裝驅動,我們的程式會通過資料庫驅動來和資料庫互動

10.2 JDBC

SUN公司為了簡化開發人員對資料庫的統一操作,提供了一個java操作資料庫的規範JDBC.這些規範的具體實現由資料庫廠商實現。
(注:在架構中沒有什麼是加一層解決不了的)

  • 主要涉及的包
    java.sql
    javax.sql
    匯入的資料庫驅動包:
    mysql-connector-java-5.1.47.jar
    下載該包的時候一般去maven倉庫下載 maver repository
    官網也可以下載,但是用的少 官網下載地址

10.3 第一個JDBC程式

1.建立測試資料庫

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')
  1. 建立一個普通專案,把驅動包mysql-connector-java-5.1.47.jar放在建立的lib目錄下,右鍵add as library新增進來
  2. 編寫測試程式碼
    步驟總結:
  3. 載入驅動 Class.forName
  4. 使用者資訊及url
  5. 連線資料庫DriverManager->connection
  6. 獲得執行sql的物件->statement
  7. 執行sql,可能得到返回結果
  8. 關閉結果集resultSet,Statement,connection釋放資源
public class JdbcFirstDemo{
	public static void main(String[]args){
		//1.載入驅動
		Class.forName("com.mysql.jdbc.Driver");//固定寫法
		//2.使用者資訊和url
		//jdbc:mysql://serverIP:3306/databaseName?
		//useUnicode支援中文編碼,characterEncoding設定字符集,useSSL安全連線
		String url =
"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8useSSL=true“;
		String username="root";
		String password="123456";
		
		//3.連線成功,返回資料庫物件connection
		Connection connection = DriverManager.getConnection(url,username,password);
		
		//4.執行SQL物件statement
		Statement statement = connection.createStatement();
		
		//5.去執行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("pwd"));
			System.out.println("email="+resultSet.getObject("email"));
			System.out.println("birth="+resultSet.getObject("birth"));
			System.out.println("=======================")
		}
		//6.釋放連線
		resultSet.close();
		statement.close();
		connection.close();
		
	}
		
}

解釋:

  1. 載入資料庫驅動
    Class.forName("com.mysql.jdbc.Driver")對應靜態程式碼塊,載入類直接執行DriverManager.registerDriver(new com.mysql.jdbc.Driver())
    推薦用Class.forName這種寫法
  2. URL
    String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
    協議//主機地址:3306(mysql預設埠號)/資料庫名?引數1&引數2&引數3
    擴充套件oralce--1521寫法
    jdbc:oracle:thin:@localhost:1521:sid
  3. connection
    connection代表資料庫,可以設定自動提交,事務提交,事務回滾
    connection.rollback()
    connection.commit()
    connection.setAutoCommit();
  4. statement執行SQL類(PrepareStatement也是)
    executeQuery()//返回查詢結果集Resultset
    execute()//執行任何sql,裡面有判斷的過程,效率更低一點
    executeUpdate()//增刪改都用它,返回受影響的行數
    executeBatch()//執行批處理多個sql
  5. ResultSet查詢的結果集
    封裝了所有的查詢結果,拿結果時可以指定資料型別
    getObject(),getString(),getInt(),getfloat()...
    在不知道資料庫列對應的資料型別時用getObject,知道的情況就用指定的型別
    遍歷,指標resultSet.next()
  6. 釋放資源
    resultSet.close();
    statement.close();
    connection.close();

10.4 statement物件

statement物件用於向資料庫傳送增刪改查語句
executeQuery()返回查詢結果集ResultSet
executeUpdate增刪改,返回受影響改變的行數,當返回值大於零說明執行成功

  • 提取工具類
    • db.properties
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=xiaoming
password=123456
  • JdbcUtils.java工具類
    static塊load properties檔案,載入驅動
    提取獲取連線的方法
    提取釋放資源的方法
public class JdbcUtils{
	private static String driver = null;
	private static String url = null;
	private static String name = null;
	private static String password = null;
	static {
		try{
		//在src目錄下的資源都可以用類反射載入
		InputStream in =
		JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
		Properties properties = new Properties();
		properties.load(in);
		
		driver = properties.getProperty(driver);
		url = properties.getProperty(url);
		name = properties.getProperty(name);
		password = properties.getProperty(password);
		
		//1.驅動只用載入一次
		Class.forName(driver);
		}catch(Exception){
			e.printStackTrace();
		}
	}
	//獲取連線
	public static void getConnection() throw SQLException{
		return DriverManager.getConnection(url,name,password);
	}
	//釋放資源
	public static void release(Connection conn, Statement st, ResultSet rs){
		if(rs!=null){
			try{
				rs.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(st!=null){
			try{
				st.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(conn!=null){
			try{
				conn.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
	}
}
  • 測試編寫增刪改查的程式碼
    變的時sql語句和執行語句,查詢略
    在finally裡釋放資源
public class TestInsert{
	public static void main(String[] args){
	Connection conn = null;
	Statement st = null;
	ResultSet rs = null;
		try{
			conn= JdbcUtils.getConnection();
			st = conn.createStatement();
			String sql =" Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
			VALUES(4,‘xiaoming','1232434','[email protected]’,‘2001-3-4’)";
			/* 刪除的sql
			String sql ="DETELET FROM users WHERE id=4”;
			*/
			int i = st.executeUpdate(sql);
			if(i>0){
				System.out.println("插入成功");
			}
		
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			JdbcUtils.release(conn,st,rs)
		}
	}

}
  • SQL注入問題
    本質上輸入的sql存在惡意拼接(or,and version()>0),攻擊者可以在web應用程式中事先定義好的查詢語句的結尾上新增額外的SQL語句。實現非授權的任意查詢
	public static void login(String username, String password){
		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		try{
			conn= JdbcUtils.getConnection();
			st = conn.createStatement();
			//對應組合的sql,sql注入時如下
		//SELECT * from users WHERE `name`= ' ' OR ‘1=1’ AND `password`=' ’ or '1=1';
String sql ="SELECT * from users WHERE `name`= '"+username+"' AND `password`='"+ password+"'";
			rs =st.executeQuery(sql);
			while(rs.next()){
				System.out.println(rs.getString(name));
			}
		
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			JdbcUtils.release(conn,st,rs)
		}		
	}
	public static void main(String args[]){
		//正常登入
		//login("xiaoming","123456");
		
		//sql注入
		login(" 'or 1=1"," 'or 1=1");
		
	}

10.5 PreparedStatement物件

PreparedStatement(sql)預編譯的可以防止注入,且效率更高

  • 編寫sql先用?佔位符來代表值,
  • 預編譯preparedStatement
  • 賦值
  • 再執行
public class TestInsert(){
	public static void main(String[] args){
		Connection conn = null;
		PreparedStatement pst =null;
		
		try{
			conn = JdbcUtils.getConnection();
			//區別,先使用?佔位符代替引數
			String sql ="Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
			VALUES(?,?,?,?,?)"
			//引數預編譯sql,先寫sql然後不執行
			pst = conn.prepareStatement(sql);
			//手動給引數賦值
			pst.setInt(1,4);
			pst.setString(2,"xiaohong");
			pst.setString(3,"1232434");
			pst.setString(4,"[email protected]");
			//注意 sql.Date資料庫裡的時間,引數是時間戳
			//util.Date java裡的時間
			pst.setDate(5,new java.sql.Date(new Date().getTime()));
			
			//執行,不用傳參
			int i = pst.executeUpdate();
			if(i>0){
				System.out.println("插入成功");
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			
		}	
	}
}

10.6 使用IDEA連線資料庫

前提工程裡已經導好了資料庫驅動包connector

  1. 點選IDEA右側Database標籤->點選+加號->選擇MySQL資料庫
    新增資料庫具體資訊Host,User,Password,和URL,使用Test Connection 進行連線測試
    點選apply OK, 第一次連線比較耗時
  2. 連線成功mysql後,新增具體的資料庫
    點選Database標籤裡的設定按鈕(彈出Data Sources and Drivers)->Schemas(裡面勾選資料庫)->apply->OK
  3. 檢視資料庫表
    雙擊新增的資料庫裡面的表,即可展示裡面的內容
  4. 更新資料
    直接再開啟的表裡修改,注意點選提交按鈕
  5. IDEA裡執行命令列寫sql
    開啟database標籤裡的console,輸入sql語句執行即可
  6. 如果連線sql出現問題,可以檢視驅動配置是否有問題
    參考 https://blog.csdn.net/weixin_44199123/article/details/106296349

10.7 事務

程式碼實現

  1. 開啟事務 conn.setAutoCommit(false);
  2. 一組業務執行完畢,提交事務connection.submit
  3. 可以在catch裡顯示定義回滾,但是預設失敗就會回滾的
public class TestTransaction1{
	public static void main(String[] args){
		Connection conn = null;
		PrepareStatement st = null;
		ResultSet rs = null;
		
		try{
			conn = JdbcUtils.getConnection();
			//關閉資料庫自動提交,會自動開啟事務
			conn.setAutoCommit(false);
			String sql1 = "UPDATE account SET money = money-100 where name ='A'";
			st = conn.prepareStatement(sql1);
			st.executedUpdate();
			
			int x = 1/0;//報錯,測試兩個操作在同一個事務裡,回滾
			
			String sql2 = "UPDATE account SET money = money+100 where name ='B'";
			st = conn.prepareStatement(sql2);
			st.executedUpdate();
			
			//業務完畢,提交事務
			conn.commit();
			System.out.println("成功");
		}catch(Exception e){
			//如果不手動回滾,也可以自動回滾
			try{
				//如果失敗回滾
				conn.rollback();
			}catch(SQLException e1){
				e1.printStackTrace();
			}
			e.printStacTrace();
		}finally{
			JdbcUtils.release(con,st,rs);
		}
	}
}

10.8 DBCP-C3P0連線池

資料庫連線--執行--釋放,十分耗費資源
池化計數:預先準備一些資源,後面就直接取用就行
編寫連線池實現JDK提供介面DataSource

  • 開源資料實現DataSource
  • DBCP
  • C3P0
  • Druid:阿里巴巴
    使用了這些資料庫連線池後,我們在專案開發中就不需要編寫載入資料庫驅動的程式碼了
  • DBCP
    • 匯入相關jar包,add as libary
      commons-dbcp-1.4.jar
      commons-pool-1.6.jar
    • 匯入配置檔案dbcpconfig.properties
#連線設定 這裡面的名字是DBCP資料來源中定義好的,可以只寫這4條後面的都不要
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

#<!-- 初始化連線 -->
initialSize=10

#最大連線數量
maxActive=50

#<!-- 最大空閒連線 -->
maxIdle=20

#<!-- 最小空閒連線 -->
minIdle=5

#<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
maxWait=60000

#JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:【屬性名=property;】
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由連線池所建立的連線的自動提交(auto-commit)狀態。
defaultAutoCommit=true

#driver default 指定由連線池所建立的連線的只讀(read-only)狀態。
#如果沒有設定該值,則“setReadOnly”方法將不被呼叫。(某些驅動並不支援只讀模式,如:Informix)
defaultReadOnly=

#driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。
#可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
  • 寫JdbcUtils_DBCP.java工具類
public class JdbcUtils_DBCP{

	private DataSource dataSource=null;
	static {
		try{
		//載入jdbc對應的properties檔案
		InputStream in =
		JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
		Properties properties = new Properties();
		properties.load(in);

		//建立資料來源 工廠模式-->建立
		dataSource = BasicDataSourceFactory.creatDataSource(properties);
		}catch(Exception){
			e.printStackTrace();
		}
		
	}
	//獲取連線
	public static void getConnection() throw SQLException{
		//從資料來源中獲取連線
		return dataSource.getConnection();
	}
	
	//釋放資源
	public static void release(Connection conn, Statement st, ResultSet rs){
		if(rs!=null){
			try{
				rs.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(st!=null){
			try{
				st.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(conn!=null){
			try{
				conn.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
	}
}
  • 測試類和前面一樣,只是工具類換成剛建立的JdbcUtils_DBCP
	public static void main(String[] args){
	Connection conn = null;
	Statement st = null;
	ResultSet rs = null;
		try{
			conn= JdbcUtils_DBCP.getConnection();
			st = conn.createStatement();
			String sql ="Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
			VALUES(4,‘xiaoming','1232434','[email protected]’,‘2001-3-4’)";
			/* 刪除的sql
			String sql ="DETELET FROM users WHERE id=4”;
			*/
			int i = st.executeUpdate(sql);
			if(i>0){
				System.out.println("插入成功");
			}
		
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			JdbcUtils_DBCP.release(conn,st,rs)
		}
	}
  • C3P0
  1. 匯入jar包
    c3p0-0.9.5.5.jar
    mchange-commons-java-0.2.19.jar
  2. C3P0配置檔案c3p0-config.xml(注意使用xml配置)
    xml裡可以寫多套資料來源配置,ComboPooledDataSource ds=new ComboPooledDataSource(),不寫引數代表使用預設資料來源
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--
    c3p0的預設(預設)配置
    如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource();"無參使用預設資料來源-->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&amp;characterEncoding=utf8&amp;uesSSL=true&amp;serverTimezone=UTC</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquiredIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>

    <!--如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");
      使用指定的資料來源-->
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&amp;characterEncoding=utf8&amp;uesSSL=true&amp;serverTimezone=UTC</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquiredIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </named-config>

</c3p0-config>

對應工具類

public class JdbcUtils_C3P0{

	private static comboPooledDataSource dataSource=null;
	static {
		try{
			//程式碼版配置 一般不這麼配
			/*
			dataSource = new ComboPooledDataSource();
			dataSource.setDriverClass();
			dataSource.setUser();
			dataSource.setPassword();
			dataSource.setJdbcUrl();
			*/
			//xml版配置
			dataSource = new ComboPooledDataSource("MySQL");
		}catch(Exception){
			e.printStackTrace();
		}
		
	}
	//獲取連線
	public static void getConnection() throw SQLException{
		//從資料來源中獲取連線
		return dataSource.getConnection();
	}
	
	//釋放資源
	public static void release(Connection conn, Statement st, ResultSet rs){
		if(rs!=null){
			try{
				rs.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(st!=null){
			try{
				st.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(conn!=null){
			try{
				conn.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
	}
}

測試類 類似上面的略

  • 總結
    無論使用什麼資料來源,本質上是一樣的,dataSource及方法getConnection不會變

擴充套件
Apacha開源專案網站:Durid(阿里貢獻的),maven, tomcat等等