MySQL學習筆記(狂神說)


語法1、初識MySQL

狂神說https://space.bilibili.com/95256449/

JavaEE:企業級Java開發、Web

  • 前端(頁面:展示—數據);
  • 后端(連接點:連接數據庫JDBC,連接前端—控制視圖跳轉和給前端傳遞數據);
  • 數據庫(存數據,Txt,Excel,world)

程序員等級:
-------只會寫代碼,沒學好數據庫,基本混飯吃
-------操作系統,數據結構預算法!當一個不錯的程序員!
-------離散數學、數字電路、體系結構、編譯原理。+實戰經驗=高級程序/優秀的程序員

1.1、為什么學習數據庫

1、崗位需求
2、現在的世界,大數據時代~,得數據庫者得天下。
3、被迫需求:存數據
數據庫是所有軟件體系中最核心的存在 DBA

1.2、什么事數據庫

  1. 數據庫(DB 、DataBase)
  2. 概念:數據倉庫,軟件,安裝在操作系統(windows,linux,mac,…)之上!SQL,可以存儲大量的數據。500萬!
  3. 作用:存儲數據、管理數據

1.3、數據庫分類

關系型數據庫:(SQL)

  • MySQL,Oracle、Sql server , DB2,SQLlite
  • 通過表和表之間,行和列之間的關系進行數據的存儲,學員信息表,考勤表…
    非關系型數據庫(NoSQL)not only
  • Redis、MongDB
  • 非關系型數據庫,對象存儲,通過對象的自身屬性來決定。

DBMS(數據庫管理系統)

  • 數據庫管理系統 ( DataBase Management System )
  • 數據庫管理軟件 , 科學組織和存儲數據 , 高效地獲取和維護數據
    在這里插入圖片描述

為什么要說這個呢?
因為我們要學習的MySQL應該算是一個數據庫管理系統.

1.4 MySQL簡介

在這里插入圖片描述
概念 : 是現在流行開源的,免費關系型數據庫
歷史 : 由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。
特點 :

  • 免費 , 開源數據庫
  • 小巧 , 功能齊全
  • 使用便捷
  • 可運行於Windows或Linux操作系統
  • 可適用於中小型甚至大型網站應用
    官網 : https://www.mysql.com/

1.5連接數據庫

安裝MySQL
這里建議大家使用壓縮版,安裝快,方便.不復雜.
軟件下載
mysql5.7 64位下載地址:
https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip
電腦是64位的就下載使用64位版本的!
安裝步驟
1、下載后得到zip壓縮包.
2、解壓到自己想要安裝到的目錄,本人解壓到的是D:\Environment\mysql-5.7.19
3、添加環境變量:
1、我的電腦->屬性->高級->環境變量
2、選擇PATH,在其后面添加: 你的mysql 安裝文件下面的bin文件夾
3、在D:\Environment\mysql目錄下新建my.ini文件
4、編輯 my.ini 文件 ,注意替換路徑位置

[mysqld]
basedir=D:\Program Files\mysql-5.7\
datadir=D:\Program Files\mysql-5.7\data\
port=3306
skip-grant-tables
12345

5、啟動管理員模式下的CMD,並將路徑切換至mysql下的bin目錄,然后輸入mysqld –install (安裝mysql)
6、再輸入 mysqld --initialize-insecure --user=mysql 初始化數據文件
7、然后輸入命令net start mysql再次啟動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即可正常使用(先使用exit,退出mysql)

net stop mysql
net start mysql

12、連接上測試出現以下結果就安裝好了
在這里插入圖片描述
一步步去做 , 理論上是沒有任何問題的 .
如果您以前裝過,現在需要重裝,一定要將環境清理干凈 .
好了,到這里大家都裝好了,因為剛接觸,所以我們先不學習命令.
這里給大家推薦一個工具 : SQLyog .
即便有了可視化工具,可是基本的DOS命名大家還是要記住!

SQLyog
可手動操作,管理MySQL數據庫的軟件工具
特點 : 簡潔 , 易用 , 圖形化
在這里插入圖片描述

在這里插入圖片描述
使用SQLyog管理工具自己完成以下操作 :

  • 連接本地MySQL數據庫
  • 新建MySchool數據庫
    • 字段
    • GradeID : int(11) , Primary Key (pk)
    • GradeName : varchar(50)
    • 數據庫名稱MySchool
    • 新建數據庫表(grade)
      在歷史記錄中可以看到相對應的數據庫操作的語句 .

連接數據庫
打開MySQL命令窗口

  • 在DOS命令行窗口進入 安裝目錄\mysql\bin
  • 可設置環境變量,設置了環境變量,可以在任意目錄打開!
    連接數據庫語句 : mysql -h 服務器主機地址 -u 用戶名 -p 用戶密碼
    注意 : -p后面不能加空格,否則會被當做密碼的內容,導致登錄失敗 !
    幾個基本的數據庫操作命令 :
update user set password=password('123456')where user='root'; 修改密碼
flush privileges; 刷新數據庫
show databases; 顯示所有數據庫
use dbname;打開某個數據庫
show tables; 顯示數據庫mysql中所有的表
describe user; 顯示表mysql數據庫中user表的列信息
create database name; 創建數據庫
use databasename; 選擇數據庫
exit; 退出Mysql
? 命令關鍵詞 : 尋求幫助
-- 表示注釋

2、操作數據庫

操作數據庫》操作數據庫中的表》操作數據庫中表的數據
MySQL不區分大小寫

2.1操作數據庫

1.創建數據庫

CREATE DATABASE IF NOT EXISTS westos;

2.刪除數據庫

DROP DATABASE IF EXISTS westos

3.使用數據庫

如果你的表名或者字段名是一個特殊字符,需要帶``
USE 'school'

4.查看數據庫

SHOW DATABASES--查看所有數據庫

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 (保存大文本)

時間日期
java.util.Date

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

null

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

2.3數據庫的字段類型(重點)

unsigened:

  • 無符號的整數
  • 聲明該列不能聲明負數
    zerofill:
  • 0填充的
  • 10的長度 1 – 0000000001 不足位數用0 填充

自增:

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

非空 NULL not Null

  • 假設設置為 not null,如何不給他賦值,就會報錯
  • NULL 如果不填寫,默認為NULL
    默認:
  • 設置默認的值!

2.4 創建數據庫表

--目標:創建一個schoo1數據庫

--創建學生表(列,字段)使用SQL 創建

--學號int 登錄密碼varchar(20)姓名,性別varchar(2),出生日期(datatime),家庭住址,emai1--注意點,使用英文(),表的名稱和字段盡量使用括起來

-- AUTO_ INCREMENT 自增

--字符串使用單引號括起來!

--所有的語句后面加,(英文的),最后一個不用加

-- PRIMARY KEY 主鍵,一般- 一個表只有一個唯一 -的主鍵!
CREATE DATABASE school
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性別',
`birthday` DATETIME 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的兩倍

常規使用操作:

  • MYISAM 節約空間,速度較快,
  • INNODB 安全性高,事務處理,多表多用戶操作

在物理空間存在的位置
所有的數據庫文件都存在data目錄下,一個文件夾就對應一個數據庫

本質還是文件的存儲

MySQL 引擎在物理文件上的區別

  • innoDB 在數據庫表中,只有一個*.frm文件,以及上級目錄下的ibdata1文件
  • MYISAM 對應的文件
    • *.frm - 表結構的定義文件
    • *. MYD -數據文件
    • *.MYI 索引文件

設置數據庫字符集編碼

CHARTSET=UTF8

不設置的話,會是mysql默認的字符集編碼-(不支持中文)
可以在my.ini中配置默認的編碼

character-set-server=utf8

2.6修改刪除表

修改

-- 修改表名 ALTER TABLE 舊表面 AS 新表名
ALTER TABLE student RENAME  AS student1
-- 增加表的字段 ALTER TABLE 表名 ADD 字段名 列屬性
ALTER TABLE student1 ADD age INT(11)
-- 修改表的字段(重命名,修改約束)
ALTER TABLE student1 MODIFY age VARCHAR(11)  -- 修改約束
ALTER TABLE student1 CHANGE age age1 INT(1)  -- 字段重命名

-- 刪除表的字段
ALTER TABLE student1 DROP age1

刪除

-- 刪除表
DROP TABLE IF EXISTS student1

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

注意點:

  • `` 字段名,使用這個包裹
  • 注釋 – /**/
  • sql 關鍵字大小寫不敏感,建議寫小寫
  • 所有的符號全部用英文

3、MySQL數據管理

3.1外鍵(了解)

方式一:在創建表的時候,增加約束(麻煩,比較復雜)

CREATE TABLE `grade`(`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年級id',`gradename` VARCHAR(50) NOT NULL COMMENT '年級名稱',PRIMARY KEY (`gradeid`))ENGINE=INNODB DEFAULT CHARSET=utf8-- 學生表的 gradeid 字段 要去引用年級表的gradeid-- 定義外鍵KEY-- 給這個外鍵添加約束(執行引用) references 引用CREATE TABLE IF NOT EXISTS `student` (`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性別',`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',`gradeid` INT(10) NOT NULL COMMENT '學生年級',`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',`email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱',PRIMARY KEY (`id`),KEY `FK_gardeid` (`gradeid`),CONSTRAINT `FK_gardeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (gradeid))ENGINE=INNODB DEFAULT CHARSET=utf8

刪除有外鍵關系的表的時候,必須先刪除引用的表(從表),再刪除被引用的表(主表)

方式二: 創建表成功后添加外鍵

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

-- 學生表的 gradeid 字段 要去引用年級表的gradeid
-- 定義外鍵KEY
-- 給這個外鍵添加約束(執行引用) references 引用
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性別',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '學生年級',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) 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 CONSTRAINT 約束名 FOREIGN KEY(作為外鍵的列) 引用到哪個表的哪個字段

以上的操作都是物理外鍵,數據庫級別外鍵,不建議使用。(避免數據庫過多造成困擾)

最佳實踐

  • 數據庫就是單純的表,只用來存數據,只有行(數據)和列(字段)
  • 我們想使用多張表的數據,想使用外鍵(程序去實現)

3.2 DML語言(全記住)*

數據庫意義:數據存儲,數據管理

DML語言:數據操作語言

  • Insert
  • update
  • delete

3.3添加

insert

-- 插入語句(添加)-- nsert into 表名([字段一], [字段二])values('值1'),('值2')INSERT INTO `grade` (`gradename`) VALUES('大四')-- 由於主鍵自增我們可以省略(如何不寫表的字段,他會一一匹配)INSERT INTO `grade` VALUES('大三')INSERT INTO `grade` (`gradeid`,`gradename`) VALUES ('大三','null')-- 一般寫插入語句,我們一定要數據和字段一一對應。-- 插入多個字段INSERT INTO `grade`(`gradename`) VALUES ('大二'),('大一');INSERT INTO `student`(`name`) VALUES ('張三')INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('張三','aaaaa','男')INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('李四','aaaaa','男'),('王五','23232','女')

語法:-- insert into 表名([字段一], [字段二])values(‘值1’),(‘值2’)

注意事項:

1.字段和字段之間用逗號分開

2.字段可以省略,但是后面的值必須一一對應

3.可以同時插入多條數據,VALUES后面的值需要使用,隔開即可

INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('李四','aaaaa','男'),('王五','23232','女')

3.4 修改

update 修改誰(條件) set 原來的值=新值

-- 修改學員名字UPDATE `student` SET `name`='囷' WHERE id =1;-- 不指定條件的情況下,會改動所有表UPDATE `student` SET `name`='233'-- 語法;-- UPDATE 表名 set column_name,[] = value where 條件

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

操作符返回布爾值

操作符 含義 范圍 結果
= 等於 5=6 false
!= <> 不等於 5!=6 true
> 大於
< 小於
>=
<=
between and 在某個范圍內,閉合區間
and && 5>1and1>2 false
or || 5>1or1>2 true

注意:

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

3.5 刪除

delete 命令

語法 delete from 表名 [where 條件]

-- 刪除數據 (避免這樣寫)DELETE FROM `student`-- 刪除指定DELETE FROM `student` where id= 1

TRUNCATE 命令

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

delete 和 TRUNCATE 區別

  • 相同點: 都能刪除數據,都不會刪除表結構
  • 不同:
    • TRUNCATE 重新設置自增列 計數器會歸零
    • TRUNCATE 不會影響事務
-- 測試delete 和 truncate 區別CREATE TABLE `test`(`id` INT(4) NOT NULL AUTO_INCREMENT,`coll` VARCHAR(20) NOT NULL,PRIMARY KEY (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `test`(`coll`) VALUES('1'),('2'),('3')DELETE FROM `test` -- 不會影響自增TRUNCATE TABLE `test` -- 自增會歸零

了解即可:delete刪除的問題 重啟數據庫,現象

  • innoDB 自增列會從1開始(存在內存當中,斷電即失)
  • MyISAM 繼續從上一個自增量開始(存在文件中,不會丟失)

4、DQL查詢數據(最重點)

4.1DQL

(Data Query Language) :數據查詢語言

  • 所有的查詢操作都用它 Select
  • 簡單的查詢,復雜的查詢它都能做
  • 數據庫中最核心的語言
  • 使用頻率最高的語言

4.2指定查詢字段

-- 查詢  SELECT 字段 FROM 表-- 查詢指定字段  such asSELECT `StudentNo`,`StudentName` FROM student-- 別名,給結果起一個名字 AS   可以給字段起別名 也可以給表起別名SELECT `StudentNo` AS 學號,`StudentName`AS 學生姓名 FROM student AS S-- 函數 Concat(a,b)SELECT CONCAT('姓名:',StudentName) AS 新名字 FROM student

語法: SELECT 字段 ... FROM 表

有時候,列名字不是那么見名知意。我們起別名 AS 字段名 AS 別名 表名 AS 別名

去重

作用:去除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 a&&b 邏輯與
or || a or b a||b 邏輯或
Not != not a !a 邏輯非

盡量使用英文

-- 查詢考試成績在95分到100分之間SELECT `StduentNo`,`StudentResult` FROM resultWHERE StudentResult >=95 AND StudentResult<=100-- 模糊查詢(區間)SELECT `StduentNo`,`StudentResult` FROM resultWHERE StudentResult BETWEEN 95 AND 100-- 除了1000號學生之外的同學成績SELECT `StduentNo`,`StudentResult` FROM resultWHERE NOT StudentNo = 1000

模糊查詢:比較運算符

運算符語法描述I S NULLa is null如果操作符為null 結果為真IS NOT NULLa is not null如果操作符為not null 結果為真BETWEENa between b and c若a在b 和c之間則為真LIKEa like bSQL匹配,如果a 匹配到b 則為真INa in (a1,a2,a3…)假設a 在 a1,a2,a3其中的某一個中,為真

運算符 語法 描述
I S NULL a is null 如果操作符為null 結果為真
IS NOT NULL a is not null 如果操作符為not null 結果為真
BETWEEN a between b and c 若a在b 和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 '劉_';-- 查詢姓劉的同學,名字后只有兩個字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 = 1001SELECT `StudentNo`,`StudentName` FROM `student`WHERE StudentNo = 1002SELECT `StudentNo`,`StudentName` FROM `student`WHERE StudentNo = 1003SELECT `StudentNo`,`StudentName` FROM `student`WHERE StudentNo IN (1001,1002,1003);-- 查詢在北京的學生SELECT `StudentNo`,`StudentName` FROM `student`WHERE `Address` IN('安徽','河南洛陽');===================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.4 聯表查詢

JOIN 對比

在這里插入圖片描述

img

======================聯表查詢 join ==============================-- 查詢參加考試的同學 (學號,姓名,考試編號,分數)SELECT * FROM student SELECT * FROM result/*1. 分析需求,分析查詢的字段來自哪些表2.確定使用哪種連接查詢?7種確定交叉點(這兩個表中哪個數據是相同的)判斷的條件: 學生表中 studentNo = 成績表中 studentNo */-- JION(表) ON (判斷的條件)連接查詢-- where 等值查詢SELECT studentNo,studentName,SubjectNo,StudentResultFROM student AS sINNER JOIN result AS rWHERE s.studentNo=r.studentNo--Right JoinSELECT s.studentNo,studentName,SubjectNo,StudentResultFROM student AS sRIGHT JOIN result AS rON s.studentNo = r.studentNo--LEFT JoinSELECT s.studentNo,studentName,SubjectNo,StudentResultFROM student AS sLEFT JOIN result AS rON s.studentNo = r.studentNo
操作 描述
Inner join 如果表中至少有一個匹配,就返回行
left join 即使左表中沒有匹配,也會從左表中返回所有的值
right jion 即使右表中沒有匹配,也會從右表中返回所有的值
-- 查詢考的同學SELECT s.studentNo,studentName,SubjectNo,StudentResultFROM student AS sLEFT JOIN result AS rON s.studentNo = r.studentNoWHERE StudentResult IS NULL-- 查詢了參加考試同學的信息:學號:學生姓名:科目名:分數SELECT s.`studentNo`,`studentName`,`SubjectName`,`studentResult`FROM student sRIGHT JOIN result rON r.studentNo=s.studentNoINNER JOIN `subject` subON r.SubjectNo=sub.SubjectNo-- 我要查詢哪些數據 SELECT ....-- 從哪幾個表中查 FROM 表 xxx JOIN 連接的表 ON 交叉條件-- 假設存在一中多張表查詢,先查詢兩章表,然后再慢慢增加--FROM a LEFT JOIN b   左為准--FROM a RIGHT JOIN b	右為准

自連接

自己的表跟自己的表連接,核心:一張表拆為兩張一樣的表

父類

categoryid categoryName
2 信息技術
3 軟件開發
5 美術設計

子類

pid categoryid categoryName
3 4 數據庫
2 8 辦公信息
3 6 web開發
5 7 ps技術

操作:查詢父類對應子類關系

父類 子類
信息技術 辦公信息
軟件開發 數據庫
軟件開發 web開發
美術設計 ps技術
-- 查詢父子信息

SELECT a.`categroryName` AS `父欄目`,b.`categroryName` AS `子欄目`
FROM `catgroy` AS a,`catgroy` AS b
WHERE a.`categoryid`=b.`pid`

-- 查詢學員所屬的年級(學號,學生的姓名,年級)
SELECT 	studentNo,studentName,gradeName
FROM student s
INNER JOIN `grade` g
ON s.`GradeId`=g.`GradeId`

4.5分頁和排序

============================分頁 limit 和排序order by=================


-- 排序:  升序ASC  降序  DESC
SELECT  xx
FROM xx
JOIN xx
WHERE  xx
ORDER BY  xx
ASC   ||  DESC


分頁

-- 為什么要分頁-- 緩解數據庫壓力,給人的體驗更好-- 分頁,每頁顯示五條數據-- 語法: limit 當前頁,頁面的大小-- limit 0,5 1-5-- limit 1,5 1-5-- limit 6,5SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`FROM student sINNER JOIN `result` rON s.`StudentNo`=r.`StudentNo`INNER JOIN `subject` subON r.`subjectNo`=sub.`subjectNo`WHERE subjectName='數據結構-1'ORDER BY StudentResult ASCLIMIT 0,5-- 第一頁 limit 0,5-- 第二頁 limit 5,5-- 第三頁 limit 10,5-- 第N頁 limit 5*(n-1),5

語法 limit(查詢起始下標,pagesize)

4.6 子查詢

where (這個值是計算出來的)

本質:在where語句中嵌套一個子查詢語句

-- ===========================where=========================

-- 1.查詢 數據庫結構-1的所有考試結構(學號,科目編號,成績) 降序
-- 方式一: 連接查詢
SELECT `StudentNo`,r.`SubjectName`,`StudentResult`
FROM `result` r
INNER JOIN `subject` sub
ON r.SubjectNo = sun.SubjectNo
WHERE subjectName = '數據庫結構-1'
ORDER BY StudentResult DESC

-- 方式二:使用子查詢(由里及外)
SELECT `StudentNo`,r.`SubjectName`,`StudentResult`
FROM `result`
WHERE StudentNo=(
	SELECT SubjectNo FROM  `subject` 
    WHERE SubjectName = '數據庫結構-1'
)
ORDER BY StudentResult DESC


-- 分數不少於80分的學生的學號和姓名
SELECT DISTINCT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE StudentResult>=80

-- 在這個基礎上 增加一個科目 ,高等數學-2
SELECT DISTINCT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE StudentResult>=80 AND `SubjectNo`=(
    SELECT Subject FROM `subject`
    WHERE SubjectName='高等數學-2'
)

-- 查詢課程為 高等數學-2 且分數不小於80分的同學的學號和姓名
SELECT s.`StudentNo`,`StudentName`
FROM student s
INNER JOIN result r
ON s.StudentNo = r.StudentNo
INNER JOIN `subject` sub
ON r.`SubjectName`='高等數學-2'
WHERE `SubjectaName`='高等數學-2' AND StudentResult >=80


-- 再改造 (由里即外)
SELECT `StudentNo`,`StudentName` FROM student
WHERE StudentNo IN(
SELECT StudentNo result WHERE StudentResult >80 AND SubjectNo =(
SELECT SubjectNo FROM `subject` WHERE `SubjectaName`='高等數學-2'
)
)

4.7 分組

-- 查詢不同課程的平均分,最高分,最低分,平均分大於80
-- 核心:(根據不同的課程分組)

SELECT `SubjectName`,AVG(StudentResult),MAX(StudentResult)
FROM result r
INNER JOIN `Subject` sub
ON r.SubjectNo=sub.SubjectNo

GROUP BY r.SubjectNo -- 通過什么字段來分組
HAVING AVG(StudentResult)>80

5、MySQL函數

5.1 常用函數

-- 數學運算

SELECT ABS(-8) -- 絕對值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4)  -- 向下取整
SELECT RAND() -- 返回0-1隨機數
SELECT SIGN(-10) -- 判斷一個數的符號 0-0 負數返回-1 正數返回1

-- 字符串函數
SELECT CHAR_LENGTH('2323232') -- 返回字符串長度
SELECT CONCAT('我','233') -- 拼接字符串
SELECT INSERT('java',1,2,'cccc') -- 從某個位置開始替換某個長度
SELECT UPPER('abc') 
SELECT LOWER('ABC')
SELECT REPLACE('堅持就能成功','堅持','努力')

-- 查詢姓 周 的同學 ,改成鄒
SELECT REPLACE(studentname,'周','鄒') FROM student
WHERE studentname LIKE '周%'

-- 時間跟日期函數(記住)
SELECT CURRENT_DATE() -- 獲取當前日期
SELECT CURDATE() -- 獲取當前日期
SELECT NOW() -- 獲取當前日期
SELECT LOCATIME()  -- 本地時間
SELECT SYSDATE()  -- 系統時間

SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT DAY(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())

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

5.2 聚合函數(常用)

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

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,PRIMARY KEY (`id`))ENGINE=INNODB DEFAULT CHARSET=UTF8-- 明文密碼INSERT INTO testmd5 VALUES(1,'張三','123456'),(2,'李四','123456'),(3,'王五','123456')-- 加密UPDATE testmd5 SET pwd=MD5(pwd) WHERE id =1UPDATE testmd5 SET pwd=MD5(pwd) WHERE id !=1  -- 加密全部-- 插入時加密INSERT INTO testmd5 VALUES(4,'小明',MD5('123456'))INSERT INTO testmd5 VALUES(5,'紅',MD5('123456'))-- 如何校驗,將用戶傳遞過來的密碼,進行MD5加密,然后對比加密后的值SELECT * FROM testmd5 WHERE `name`='紅' AND pwd=MD5('123456')

6、事務

6.1 什么是事務(ACID)

要么都成功,要么都失敗

  1. SQL執行, A給B轉賬 A 1000–> 200 B200
  2. SQL 執行, B收到A的錢 A800 — B400

將一組SQL放在一個批次中執行

事務原則 : ACID原則 原子性,一致性,隔離性,持久性 (臟讀,幻讀…)

原子性(Atomicity)

要么都成功,要么都失敗

一致性(Consistency)

事務前后的數據完整性要保持一致

持久性(Durability)–事務提交

事務一旦提交就不可逆轉,被持久化到數據庫中

隔離性

事務產生多並發時,互不干擾

隔離產生的問題

臟讀:

指一個事務讀取了另外一個事務未提交的數據。

不可重復讀:

在一個事務內讀取表中的某一行數據,多次讀取結果不同。(這個不一定是錯誤,只是某些場合不對)

虛讀(幻讀)

是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致。
(一般是行影響,多了一行)

執行事務

-- mysql 自動開啟事務提交
SET autocommit=0 -- 關閉
SET autocommit=1 -- 開啟(默認的)

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

-- 事務開啟

START TRANSACTION -- 標記一個事務的開始,從這個之后的SQP都在同一個事務內

INSERT XX
INSERT XX

-- 提交 : 持久化(成功)
COMMIT 
-- 回滾:  回到原來的樣子(失敗)
ROLLBACK
-- 事務結束
SET autocommit = 1 -- 開啟自動提交
-- 了解
SAVEPOINT 保存點名稱 -- 設置一個事務的保存點
ROLLBACK TO SAVEPOINT 保存點名 -- 回滾到保存點
RELEASE SAVEPOINT 保存點 -- 刪除保存點

WUtsns.png

模擬場景

CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ciUSE shopCREATE TABLE `account`(`id` INT(3) NOT NULL AUTO_INCREMENT,`name` VARCHAR(30) NOT NULL,`money` DECIMAL(9,2) NOT NULL,PRIMARY KEY (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO account(`name`,`money`)VALUES('A',2000),('B',10000)-- 模擬轉賬:事務SET autocommit = 0; -- 關閉自動提交START TRANSACTION -- 開啟事務(一組事務)UPDATE account SET money = money-500 WHERE `name` = 'A' -- A 轉賬給BUPDATE account SET money = money+500 WHERE `name` = 'B' -- B 收到錢COMMIT ; -- 提交事務ROLLBACK ; -- 回滾SET autocommit=1 -- 恢復默認值

7、索引

MySQL索引的建立對於MySQL的高效運行是很重要的,索引可以大大提高MySQL的檢索速度。

7.1索引的分類

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

  • 主鍵索引 (PRIMARY KEY)

    • 唯一的標識,主鍵不可重復,只能有一個列作為主鍵
  • 唯一索引 (UNIQUE KEY)

    • 避免重復的列出現,唯一索引可以重復,多個列都可以標識唯一索引
  • 常規索引(KEY/INDEX)

    • 默認的,index,key關鍵字來設置
  • 全文索引(FULLTEXT)

    • 在特點的數據庫引擎下才有,MyISAM
    • 快速定位數據
-- 索引的使用
-- 1.在創建表的時候給字段增加索引
-- 2.創建完畢后,增加索引

-- 顯示所有的索引信息
SHOW INDEX FROM 表

-- 增加一個索引
ALTER TABLE 表 ADD FULLTEXT INDEX 索引名(字段名)

-- EXPLAIN 分析sql執行狀況
EXPLAIN SELECT * FROM student -- 非全文索引

7.2 測試索引sql

CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT '',
`email` VARCHAR(50) NOT NULL,
`phone` VARCHAR(20) DEFAULT '',
`gender` TINYINT(4) UNSIGNED DEFAULT '0',
`password` VARCHAR(100) NOT NULL DEFAULT '',
`age` TINYINT(4) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

-- 插入100萬數據
DELIMITER $$ --  寫函數之前必寫
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`)
VALUE(CONCAT('用戶',i),'534240118@qq.com',FLOOR (CONCAT('18',RAND()*9999999)),FLOOR (RAND()*2),
UUID(),FLOOR (RAND()*100));

SET i = i+1;
END WHILE;
RETURN i;


END;

INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUE(CONCAT('用戶',i),'534240118@qq.com',FLOOR (CONCAT('18',RAND()*9999999)),FLOOR (RAND()*2),
UUID(),FLOOR (RAND()*100))


SELECT mock_data();

SELECT * FROM app_user WHERE `name`='用戶9999' -- 接近半秒

EXPLAIN SELECT * FROM app_user WHERE `name`='用戶9999'  -- 查詢99999條記錄

-- id _ 表名_字段名
-- create index on 字段
CREATE INDEX id_app_user_name ON app_user(`name`); -- 0.001 s
EXPLAIN SELECT * FROM app_user WHERE `name`='用戶9999'  -- 查詢一條記錄

索引在小數據的時候,用處不大,但是在大數據的時候,區別十分明顯

7.3 索引原則

索引不是越多越好

  • 不要對經常變動的數據加索引
  • 小數據量的表不需要加索引
  • 索引一般加在常用來查詢的字段上

索引的數據結構

Hash 類型的索引

Btree: 默認innodb 的數據結構

閱讀:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

8、權限管理和備份

8.1用戶管理

SQLyog 可視化管理

在這里插入圖片描述

SQL命令操作

用戶表:mysql.user

本質:對這張表進行,增刪改查

-- 創建用戶  CREATE USER 用戶名 IDENTIFIED BY '密碼'
CREATE USER sanjin IDENTIFIED BY '123456'

-- 修改密碼(修改當前密碼)
SET PASSWORD = PASSWORD('111111')


-- 修改密碼(修改指定用戶密碼)

SET PASSWORD FOR sanjin = PASSWORD('111111')


-- 重命名  rename user 原名字 to 新名字
RENAME USER sanjin TO sanjin2

-- 用戶授權   ALL PRIVILEGES 全部的權限   庫,表
-- ALL PRIVILEGES 除了給別人授權,其他都能干
GRANT ALL PRIVILEGES ON *.* TO sanjin2

-- 查詢權限
SHOW GRANTS FOR sanjin2  -- 查看指定用戶的權限
SHOW GRANTS FOR root@localhost


-- 撤銷權限 REVOKE 哪些權限,在哪個庫撤銷,給誰撤銷
REVOKE ALL PRIVILEGES ON *.* FROM sanjin2

-- 刪除用戶
DROP USER sanjin2

8.2 MySQL備份

為什么備份:

保證重要數據不丟失

  • 數據轉移

MySQL數據庫備份的方式

  • 直接拷貝物理文件
  • 在SQLyog這種可視化工具中手動導出
    • 在想要導出的表或者庫中,右鍵選擇備份和導出

在這里插入圖片描述

在這里插入圖片描述

9、規范數據庫設計

當數據庫比較復雜的時候,我們就需要設計了

糟糕的數據庫設計:

  • 數據冗余,浪費空間

  • 數據庫插入和刪除都會麻煩,異常【屏蔽使用物理外鍵】

  • 程序的性能差

良好的數據庫設計:

  • 節省內存空間
  • 保證數據庫的完整性
  • 方便我們開發系統

軟件開發中,關於數據庫的設計

  • 分析需求:分析業務和需要處理的數據庫的需求
  • 概要設計:設計關系圖 E-R圖

設計數據庫的步驟(個人博客)

1、收集信息,分析需求

  • 用戶表(用戶登錄注銷,用戶的個人信息,寫博客,創建分類)
  • 分類表(文章分類,誰創建的)
  • 文章表(文章的信息)
  • 友鏈表(友鏈信息)
  • 自定義表(系統信息,某個關鍵的字,或者某些主字段)
  • 說說表(發表心情…id ,content ,time)

2、標識實體(把需求落地到每個字段)

3、 標識實體之間的關系

  • 寫博客 user–>blog
  • 創建分類 user–>category
  • 關注 user–>user
  • 友鏈–>links
  • 評論 user–>user

9.2三大范式

為什么需要數據規范化?

  • 信息重復
  • 更新異常
  • 插入異常
  • 刪除異常
    • 無法正常顯示異常
  • 刪除異常
    • 丟失有效的信息

三大范式

第一范式(1NF)

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

第二范式(2NF)

前提:滿足第一范式

每張表只描述一件事情

第三范式(3NF)

前提:滿足第一范式和第二范式

第三范式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。

(規范數據庫的設計)

規范性和性能的問題

關聯查詢的表,不得超過三張表

  • 考慮商業化的需求和目標(成本和用戶體驗) 數據庫的性能更加重要
  • 再規范性能的問題的時候,需要適當的考慮一下,規范性
  • 故意給某些表加一些冗余的字段(從多表,變成單表)
  • 故意增加一些計算列(從大數據量降低為小數據量的查詢:索引)

10、JDBC(重點)

10.1 數據庫驅動

驅動:聲卡,顯卡,數據庫在這里插入圖片描述

我們的程序會通過數據庫驅動,和數據庫打交道!

10.2 JDBC

SUN 公司為了簡化開發人員的(對數據庫的統一)操作,提供了一個(Java操作數據庫的)規范,JDBC

這些規范的實現由具體的廠商去做

對於開發人員來說,我們只需要掌握JDBC的接口操作即可在這里插入圖片描述

java.sql

javax.sql

還需要導入數據庫驅動包

10.3 第一個JDBC程序

創建測試數據庫

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','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')


1.創建一個普通項目

2.導入數據庫驅動

3.編寫測試代碼

package com.kuang.lesson01;
//我的第一個JDBC程序

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcFirstDemo {
    public static void main(String[] args) throws Exception {
        //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 name = "root";
        String password = "123456";

        //3. 連接成功,返回數據庫對象  connection代表數據庫
        Connection connection= DriverManager.getConnection(url,name,password);
        //4. 執行SQL的對象 statement 執行SQL的對象
        Statement statement = connection.createStatement();

        //5. 執行SQL的對象 去執行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("password+"+resultSet.getObject("PASSWORD"));
            System.out.println("email+"+resultSet.getObject("email"));
            System.out.println("birthday+"+resultSet.getObject("birthday"));
        }
        //6. 釋放連接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步驟總結:
1.加載驅動

2.連接數據庫 DriverManager

3.獲取執行SQL的對象 Statement

4.獲得返回的結果集

5.釋放連接

DriverManager

//DriverManager.registerDriver(new com.mysql.jdbc.Driver());Class.forName("com.mysql.jdbc.Driver");//固定寫法Connection connection= DriverManager.getConnection(url,name,password);//connection代表數據庫//數據庫設置自動提交//事務提交//事務回滾connection.rollback();connection.commit();connection.setAutoCommit();

URL

String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false";//mysql 默認3306//協議://主機地址:端口號/數據庫名?參數1&參數2&參數3//Oracle   1521//jdbc:oralce:thin:@localhost:1521:sid

statement 執行SQL的對象 pPrepareStatement 執行SQL的對象

String sql="SELECT * FROM users";//編寫Sql

statement.executeQuery();
statement.execute();
statement.executeUpdate();//更新,插入,刪除,返回一個受影響的行數

ResultSet 查詢的結果集,封裝了所以的查詢結果

獲得指定的數據類型

ResultSet resultSet = statement.executeQuery(sql);//返回的結果集,結果集中封裝了我們全部查詢的結果
        resultSet.getObject();//在不知道列類型下使用
        resultSet.getString();//如果知道則指定使用
        resultSet.getInt();
        

遍歷,指針

    resultSet.next(); //移動到下一個
    resultSet.afterLast();//移動到最后
    resultSet.beforeFirst();//移動到最前面
    resultSet.previous();//移動到前一行
    resultSet.absolute(row);//移動到指定行

釋放內存

//6. 釋放連接
        resultSet.close();
        statement.close();
        connection.close();//耗資源


10.4 statement對象

Jdbc中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查語句即可。

Statement對象的executeUpdate方法,用於向數據庫發送增、刪、改的sq|語句, executeUpdate執行完后, 將會返回一個整數(即增刪改語句導致了數據庫幾行數據發生了變化)。

Statement.executeQuery方法用於向數據庫發生查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象。

CRUD操作-create

使用executeUpdate(String sql)方法完成數據添加操作,示例操作:

 Statement statement = connection.createStatement();
        String sql = "insert into user(...) values(...)";
        int num = statement.executeUpdate(sql);
        if(num>0){
            System.out.println("插入成功");
        }

CRUD操作-delete

使用executeUpdate(String sql)方法完成數據刪除操作,示例操作:

Statement statement = connection.createStatement();
        String sql = "delete from user where id =1";
        int num = statement.executeUpdate(sql);
        if(num>0){
            System.out.println("刪除成功");
        }

CURD操作-read

使用executeUpdate(String sql)方法完成數據查詢操作,示例操作:

Statement statement = connection.createStatement();
        String sql = "select * from  user where id =1";
        ResultSet rs= statement.executeQuery(sql);
        if(rs.next()){
            System.out.println("");
        }

代碼實現

1.提取工具類

package com.kuang.lesson02.utils;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");            //1.驅動只用加載一次            Class.forName(driver);        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }    //2.獲取連接    public static Connection getConnection() throws Exception{        return DriverManager.getConnection(url, username, password);    }    //3.釋放資源    public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {        if(rs!=null){            rs.close();        }        if (st!=null){            st.close();        }        if(conn!=null){            conn.close();        }    }}

2.編寫增刪改的方法,exectueUpdate

package com.kuang.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import static com.kuang.lesson02.utils.JdbcUtils.*;

public class TestInnsert {
    public static void main(String[] args){
        Connection conn =null;
        Statement st = null;
        ResultSet rs =null;



        try {
             conn = getConnection();//獲取連接
            st = conn.createStatement();//獲取SQL執行對象
            String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
                    "VALUES(5,'sanjin','123456','233223@qq.com','2020-01-01')";

            int i = st.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功");
            }
        JdbcUtils.release(conn,st,rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

3.查詢 executeQuery

package com.kuang.lesson02.utils;

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

import static com.kuang.lesson02.utils.JdbcUtils.*;

public class TestInnsert {
    public static void main(String[] args) throws SQLException {
        Connection conn =null;
        Statement st = null;
        ResultSet rs =null;



        try {
             conn = getConnection();//獲取連接
            st = conn.createStatement();//獲取SQL執行對象
            String sql = "select * from users";
            rs=st.executeQuery(sql);//查詢完畢返回結果集

            while (rs.next()){
                System.out.println(rs.getString("NAME"));
            }
        JdbcUtils.release(conn,st,rs);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }

}


SQL注入問題

sql存在漏洞,會被攻擊導致數據泄露 SQL會被拼接 or

package com.thb.study2;

/**
 * @Author 天紅
 * @Date 2021/7/23 16:31
 * @Version 1.0
 */

import com.thb.study2.Utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import static com.thb.study2.Utils.JdbcUtils.getConnection;

public class SQL {
    public static void main(String[] args) {


        //SQL注入
        login("' or '1=1","' or '1=1");
    }
    public static void login(String name,String password){


        Connection conn =null;
        Statement st = null;
        ResultSet rs =null;



        try {
            conn = getConnection();//獲取連接

            st = conn.createStatement();//獲取SQL執行對象
            String sql = "select * from users where `NAME`='"+ name +"'  AND `PASSWORD`='"+ password +"'" ;
            rs=st.executeQuery(sql);//查詢完畢返回結果集

            while (rs.next()){
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("password"));
                System.out.println("==========================================");
            }
            JdbcUtils.release(conn,st,rs);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}


10.5 PreparedStatement對象

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

更新都一樣

  1. 新增
  2. 刪除
  3. 查詢
package com.thb.study2;

import com.thb.study2.Utils.JdbcUtils;

import java.sql.*;

/**
 * @Author 天紅
 * @Date 2021/7/23 20:30
 * @Version 1.0
 */
public class TestInsert02 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";
            ps = conn.prepareStatement(sql);

            ps.setInt(1, 6);
            ps.setString(2, "無言");
            ps.setString(3, "999");
            ps.setString(4, "th@hhh.com");
            ps.setDate(5, new Date(new java.util.Date().getTime()));

            int i = ps.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功o(*////▽////*)q");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.release(conn, ps, rs);
        }

    }
}

查詢

package com.thb.study2;

/**
 * @Author 天紅
 * @Date 2021/7/23 16:31
 * @Version 1.0
 */

import com.thb.study2.Utils.JdbcUtils;

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

import static com.thb.study2.Utils.JdbcUtils.getConnection;

public class TestQuary03 {
    public static void main(String[] args) {
        
        login("蘇蘇", "222");
    }

    public static void login(String name, String password) {

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;


        try {
            conn = getConnection();//獲取連接
            String sql = "SELECT * FROM users WHERE `NAME`=? and `PASSWORD`=?";
            st = conn.prepareStatement(sql);//獲取SQL執行對象

            st.setString(1, name);
            st.setString(2, password);

            rs = st.executeQuery();//查詢完畢返回結果集

            while (rs.next()) {
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("password"));
                System.out.println("==========================================");
            }
            JdbcUtils.release(conn, st, rs);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.release(conn, st, rs);
        }
    }
}

防止SQL注入本質,傳遞字符 帶有“ ”,轉義字符會被轉義

10.6 使用IDEA連接數據庫

在這里插入圖片描述

連接成功后,可以選擇數據庫

在這里插入圖片描述

雙擊數據庫

在這里插入圖片描述

更新數據、

在這里插入圖片描述

編寫sql代碼的地方

在這里插入圖片描述

10.7 JDBC事務

要么都成功,要么都失敗

ACID原則

原子性:要么全部完成,要么都不完成

一致性:結果總數不變

隔離性:多個進程互不干擾

持久性:一旦提交不可逆,持久化到數據庫了

隔離性的問題:

臟讀: 一個事務讀取了另一個沒有提交的事務

不可重復讀:在同一個事務內,重復讀取表中的數據,表發生了改變

虛讀(幻讀):在一個事務內,讀取到了別人插入的數據,導致前后讀出來的結果不一致

代碼實現

  1. 開啟事務conn.setAutoCommit(false);
  2. 一組業務執行完畢,提交事務
  3. 可以在catch語句中顯示的定義回滾,但是默認失敗會回滾
package com.thb.study3;

import com.thb.study2.Utils.JdbcUtils;

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

/**
 * @Author 天紅
 * @Date 2021/7/24 13:54
 * @Version 1.0
 */
public class Test03 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            connection = JdbcUtils.getConnection();
            connection.setAutoCommit(false);

            String sql = "update account set money=money-100 where `name`='A'";
            ps = connection.prepareStatement(sql);
            ps.executeUpdate();
            
            String sql2 = "update account set money=money+100 where `name`='B'";
            ps = connection.prepareStatement(sql2);
            ps.executeUpdate();

            connection.commit();
            System.out.println("成功d=====( ̄▽ ̄*)b");


        } catch (SQLException e) {
            //默認失敗會回滾
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,ps,null);
        }
    }
}

10.8數據庫連接池

數據庫連接–執行完畢–釋放
連接–釋放 十分浪費資源
池化技術: 准備一些預先的資源,過來就連接預先准備好的
常用連接數 100
最少連接數:100
最大連接數 : 120 業務最高承載上限
排隊等待,
等待超時:100ms
編寫連接池,實現一個接口 DateSource

簡單看一下結構Wgu8PI.png

開源數據源實現(拿來即用)

  • DBCP

  • C3P0

  • Druid: 阿里巴巴

使用了這些數據庫連接池之后,我們在項目開發中就不需要編寫連接數據庫的代碼了

DBCP

需要用到的jar包 看上圖--> dbcp和pool(還有個logging)

  • dbcpconfig.properties

#連接設置,這里面的名字是DBCP數據源中定義好的
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8useSSL=false

username=root
password=root
#<!-- 初始化連接-->
initialSize=10

#最大連接數量
maxActive=50

#最大空閑連接
maxIdle=20

#最小空閑連接
minIdle=5

#超時等待時間以毫秒為單位/s
maxWait=60000

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

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

#driver default 指定由連接池所創建的連接的事務級別(TransactionIsolation)。
#可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

  • JdbcUtils_DBCP工具類

package com.thb.study4.utils;

import org.apache.commons.dbcp2.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @Author 天紅
 * @Date 2021/7/23 14:28
 * @Version 1.0
 */
public class JdbcUtils_DBCP {
    private static DataSource dataSource=null;

    static {
        try {
            InputStream is = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(is);

            //創建數據源 工廠模式-->創建
            dataSource = BasicDataSourceFactory.createDataSource(properties);
            

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //2.獲取連接
    public static Connection getConnection() throws SQLException {

            return dataSource.getConnection();//從數據源中獲取連接

    }

    //3.釋放資源
    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();
            }
        }
    }

}

  • DBCP測試代碼

package com.thb.study4;

import com.thb.study2.Utils.JdbcUtils;
import com.thb.study4.utils.JdbcUtils_DBCP;

import java.sql.*;

/**
 * @Author 天紅
 * @Date 2021/7/24 21:33
 * @Version 1.0
 */
public class TestDBCP {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils_DBCP.getConnection();
            String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";
            ps = conn.prepareStatement(sql);

            ps.setInt(1, 24);
            ps.setString(2, "無言");
            ps.setString(3, "999");
            ps.setString(4, "th@hhh.com");
            ps.setDate(5, new Date(new java.util.Date().getTime()));

            int i = ps.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功o(*////▽////*)q");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils_DBCP.release(conn, ps, rs);
        }


    }
}

C3P0

jar包看上圖 --> c3p0和mchange開頭的

  • c3p0-config.xml配置文件(名字不要變)

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
<!--
C3P0的缺省(默認)配置,
如果在代碼中是    ComboPooledDataSource cp = new ComboPooledDataSource();  這樣寫是default-config的配置
        -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/student?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="password">root</property>


        <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->
        <property name="acquireIncrement">3</property>

        <!--初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。Default: 10 這些都是自己定義 -->
        <property name="initialPoolSize">10</property>

        <!-- 連接的最大空閑時間,default: 30  -->
        <property name="maxIdleTime">30</property>

             <!--連接池中保留的最大連接數。Default: 100 -->
        <property name="maxPoolSize">100</property>

        <!--連接池中保留的最小連接數。Default: 15 -->
        <property name="minPoolSize">15</property>
    </default-config>



<!--
C3P0的命名配置,
如果在代碼中是    ComboPooledDataSource cp = new ComboPooledDataSource("MySQL");  這樣寫是default-config的配置
-->
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/student?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="root">root</property>

        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
    </named-config>


<!-- 所以下面想什么配置就寫什么配置   -->
</c3p0-config>

  • 工具類

package com.thb.study4.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

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

/**
 * @Author 天紅
 * @Date 2021/7/23 14:28
 * @Version 1.0
 */
public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource=null;

    static {
        try {

/*            //代碼配置,麻煩不用
           dataSource = new ComboPooledDataSource();
           dataSource.setDriverClass("com.mysql.jdbc.Driver");
           dataSource.setUser("root");
           dataSource.setPassword("root");

           dataSource.setMaxPoolSize(100);
           dataSource.setMinPoolSize(10);*/

//      配置文件的配法,我們只要導入xml文件,寫個一句就好了
      dataSource= new ComboPooledDataSource("MySQL");




        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //2.獲取連接
    public static Connection getConnection() throws SQLException {

            return dataSource.getConnection();//從數據源中獲取連接

    }

    //3.釋放資源
    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();
            }
        }
    }

}
  • 測試C3P0類

package com.thb.study4;

import com.thb.study4.utils.JdbcUtils_C3P0;
import com.thb.study4.utils.JdbcUtils_DBCP;

import java.sql.*;

/**
 * @Author 天紅
 * @Date 2021/7/24 21:33
 * @Version 1.0
 */
public class TestC3P0 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils_C3P0.getConnection();
            String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";
            ps = conn.prepareStatement(sql);

            ps.setInt(1, 27);
            ps.setString(2, "我愛你");
            ps.setString(3, "1314");
            ps.setString(4, "804328977@qq.com");
            ps.setDate(5, new Date(new java.util.Date().getTime()));

            int i = ps.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功o(*////▽////*)q");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils_DBCP.release(conn, ps, rs);
        }


    }
}

結論

無論使用什么數據源,本質是不變的,DateSource接口不會變,方法就不會變

筆記參考自


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM