MySQLデータベースは理解しやすいです

MySQL

  • MySQL で使用される SQL 言語は、データベースにアクセスするために最も一般的に使用される標準化された言語です。MySQL ソフトウェアはデュアル ライセンス ポリシーを採用しており、コミュニティ バージョンと商用バージョンに分かれており、その小型、高速、総所有コストの低さ、特にオープン ソースの特性により、MySQL は一般に Web サイトのデータベースとして選択されます。中小規模のウェブサイトの開発。
  • MySQL はリレーショナル データベース管理システムです
  • スウェーデンのMySQL AB社が開発
  • 現在はOracleの製品になっています
  • MySQL は、最高のRDBMS (リレーショナル データベース管理システム、リレーショナル データベース管理システム) アプリケーション ソフトウェアの 1 つです。
  • オープンソースのデータベース ソフトウェア
  • サイズが小さく、スピードが速く、総所有コストが低く、採用コストも比較的低いため、誰もがその方法を知っておく必要があります。
  • 公式ウェブサイト:https://www.mysql.com/

MySQLをインストールする

  1. 解凍する

  2. このパッケージをコンピュータ環境のディレクトリに置きます~

  3. 環境変数を構成する

    1. 新しいコンピュータ環境のパスを作成し、インストール パス D:\mysql\mysql-8.0.21\bin をコピーします。
  4. 新しいmysql設定ファイルを作成する

    [mysqld]
    # 目录要换成自己的	
    basedir=D:\mysql\mysql-8.0.21\
    datadir=D:\mysql\mysql-8.0.21\data\
    port=3306
    skip-grant-tables
    
  5. CMDを管理者モードで起動し、mysqlのbinディレクトリに移動します。

  6. mysqlサービスをインストールする

    • mysqld -install
  7. データベースファイルの初期化

    • mysqld --initialize-insecure
  8. 起動する

    • ネットスタートmysql
  9. デフォルトのパスワードは空です。ログイン コマンド

    • mysql -uroot -p
  10. パスワード変更はMysql8.0のため、パスワード機能の使用はサポートされていません。

    • mysqlを使用するデータベースを選択します
    • パスワードを変更します。「123456」で識別されるユーザー「root」@「localhost」を変更します。
  11. 更新: 権限をフラッシュ; 更新後に終了: 終了; ログアウトして再度ログインするだけです

コマンドライン

--连接数据库
mysql -u root -p123456
--修改用户密码
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
-- 查看时区,显示 SYSTEM 就是没有设置时区啦。
show variables like'%time_zone';
--设置时区 设置完需要重新连接sql重新查看
set global time_zone = '+8:00';
--刷新权限
flush privileges;

--所有的sql语句都使用;结尾

--查看所有的数据库
show databases;
--切换数据库
use 数据库名
--查看数据库中所有的表
show tables;
--显示表中所有的信息
describe 表名

---------------------
--创建一个数据库
create database 数据库名
--退出连接
exit;
--单行注释
/*多行注释*/

データベースxxx言語

DDLデータベース制御言語

DMLデータベース操作言語

DQL データベース クエリ言語

DCL データベース制御言語

運用データベース

データベースの操作 > データベース内のテーブルの操作 > データベース内のテーブルのデータの操作

mysql キーワードは大文字と小文字を区別しません [ ] はオプションを意味します

**ディスプレイ名またはデータベース名が特殊文字の場合は、「**」を追加します。

運用データベース

  1. データベースの作成

    CREATE DATABASE [IF NOT EXISTS] 数据库名
    
  2. データベースの削除

    DROP DATABASE IF EXISTS 数据库名
    
  3. データベースを使用する

    USE `数据库名`
    
  4. データベースを見る

    SHOW DATABASE
    

データベースの列の型

数値

  • tinyint 非常に小さいデータ 1 バイト
  • smallint より小さいデータ 2 バイト
  • Mediumint 中サイズのデータ​​ 3 バイト
  • int標準整数一般的に使用される 4 バイト
  • bigint より大きなデータ 8 バイト
  • float 浮動小数点数 4 バイト
  • 倍精度浮動小数点数 8 バイト (精度の問題)
  • 10 進数 文字列形式の浮動小数点数に対して財務計算を実行する場合、通常は 10 進数が使用されます。

  • 文字列固定サイズ0~255
  • varchar変数文字列0~65535 よく使用される変数文字列
  • tinytext 小さなテキスト 2^8-1
  • テキストテキスト文字列2^16-1 大きなテキストを保存

時間日付

  • 日付 YYYY-MM-DD 日付形式
  • 時間 HH:mm:ss 時間形式
  • datetime YYYY-MM-DD HH:mm:ss最も一般的に使用される時刻形式
  • タイムスタンプ 1970.1.1 から現在までのミリ秒数も一般的に使用されます。
  • year は年を表します

ヌル

  • 値が不明です
  • 演算には null を使用しないでください。結果は null になります。

データベースフィールドの属性 (強調)

署名なし:

  • 符号なし整数
  • 列を負の数として宣言できないことが宣言されています

ゼロフィル:

  • 0 パディング
  • 桁が不足しています。0 を使用して埋めてください。int (3)、5 — 005

自己増加

  • 通常は自動インクリメントとして理解され、前のレコードに基づいて自動的に +1 (デフォルト)
  • 通常、一意の主キーを設計するために使用されます。これは整数型である必要があります。
  • 主キーの自動インクリメントの開始値とステップサイズをカスタマイズできます。

null ではありません NULL ではありません

  • デフォルト値を設定してください!
  • 性別、デフォルト値は男性です。この列の値が指定されていない場合は、デフォルト値が設定されます。

拡大する

-- 每一个表都必须存在以下五个字段,未来做项目用的,表示一个表记录存在的意义
id 主键
version 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间

データベーステーブルの作成(ポイント)

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 '密码',
  `set` 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

形式: [ ] は、存在するかどうかを判断するためのオプションの IF NOT EXISTS を示します。

CREATE TABLE [IF NOT EXISTS] `表名`(
    `字段名` 列类型 [非空] [自增] [注释] '学号',
    `字段名` 列类型 [非空] [默认值] '匿名' [注释] '姓名'.....(注意最后一行不要加,)
    )[引擎]ENGINE=INNODB[字符集]CHARSET=utf8)

共通コマンド

 -- 查看数据库的语句
SHOW CREATE DATABASE 数据库名;

-- 查看表中数据的定义语句
SHOW CREATE TABLE 表名; 

-- 显示表的结构
DESC 表名; 

テーブルの変更、削除

改訂

-- 修改表名 ALTER TABLE 旧表名 RENAME AS 新表名;
ALTER TABLE student RENAME AS student1;

-- 增加表的字段  ALTER TABLE 表名 ADD 字段名 列属性;
ALTER TABLE student1 ADD age INT(11);

-- 修改表的字段约束 ALTER TABLE 表名 MODIFY 字段名 列属性;
ALTER TABLE student1 MODIFY age VARCHAR(20);

-- 修改表字段名 ALTER TABLE 表名 CHANGE 旧字段 新字段 列属性;
ALTER TABLE student1 CHANGE age age1 INT(1);

-- 删除表字段 ALTER TABLE 表名 DROP 字段名;
ALTER TABLE student1 DROP age1;

消去

-- 删除表 (判断表存在 在删除)
DROP TABLE IF EXISTS student1;

MySQL データ管理

外部キー (理解するだけ)

方法 1: テーブルの作成時に制約を追加する (面倒で複雑)

CREATE TABLE IF NOT EXISTS `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 '密码',
  `set` 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_gradeid` (`gradeid`), --定义外键 key
  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`) -- 
)ENGINE=INNODB DEFAULT CHARSET=utf8

外部キー関係を持つテーブルを削除する場合は、まず他人を参照しているテーブル(スレーブテーブル)を削除し、次に参照されているテーブル(マスターテーブル)を削除する必要があります。

方法 2: テーブルが正常に作成された後、外部キー制約を追加します。

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

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 '密码',
  `set` 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 表名 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 哪个表(哪个字段);
ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);

DML 言語 (すべて記憶)

データベースの意味:データストレージ、データ管理

DML言語: データ操作言語

  • 入れる
  • アップデート
  • 消去

に追加

入れる

-- insert into 表名(字段1,字段2,...)values(值1),(值2)
-- 一般写插入语句,我们一定要数据和字段一一对应
 
INSERT INTO `grade`(`gradeid`,`gradename`)VALUES(1,'大一'),(2,'大二');

構文: テーブル名 (フィールド 1、フィールド 2、…) に値 (値 1)、(値 2)… を挿入します。

予防:

  1. カンマを使用してフィールドを区切ります
  2. フィールドは省略可能ですが、次の値は 1 対 1 に対応する必要があります (
    例: テーブル名に挿入) 値 (値...) 内の値は、次の値と 1 対 1 に対応する必要があります。テーブル内のすべてのフィールド。
  3. 複数のデータを同時に挿入できますが、値以降の値は区切る必要があります。

改訂

更新しました

UPDATE `grade` SET `gradename` = '大1' WHERE `gradeid` = 1;

-- 不指定条件的情况下,会改动表里的这个字段全部的值
UPDATE `grade` SET `gradename` = '大2';

-- 修改多个属性 逗号隔开
UPDATE `grade` SET `gradeid` = 11,`gradename` = '大11' WHERE `gradeid` = 1;

-- 语法
update 表名 set 字段(需要修改的哪个字段) =,.... where = 

条件: where 句の演算子 ID が特定の値に等しい、特定の値より大きい、特定の間隔内で変更された...

演算子はブール値を返します

オペレーター 意味 範囲 結果
= 等しい 5=6 間違い
<>または!= 等しくない 5<>6 真実
> 以上 5>4 真実
< 未満 5<6 真実
>= 以上 5>=4 真実
<= 以下 5<=6 真実
間…と… 2~5など一定の範囲内 [2,5]
そして 私とあなた&& 5>1 および 1>2 間違い
または 私かあなた|| 5>1 または 1>2 真実

構文: UPDATE テーブル名 SET 列名=値,… WHERE [条件]

知らせ:

  • Colnum_name はデータベースの列です。それを取得してみてください
  • 条件、フィルター条件が指定されていない場合は、すべての列が変更されます
  • value は特定の値または変数です
  • 複数の設定属性を区切るには、カンマを使用します。

消去

削除コマンド

構文: テーブル名から削除 [where 条件]

-- 删除数据(避免这样写,会全部删除)
DELETE FROM 数据库名;

-- 删除指定数据
DELETE FROM 数据库名 WHERE 条件;

切り捨てコマンド

機能: データベース テーブルを完全にクリアしても、テーブルの構造とインデックスの制約は変更されません。

-- 清空表
TRUNCATE 表名;

削除と切り捨ての違い

  • 同様の点: どちらもデータを削除できますが、テーブル構造は削除されません。
  • 違う:
    • Turncate は自動インクリメント列カウンターをゼロにリセットします
    • Turncate は物事に影響を与えません

理解してください: 削除の問題とデータベースの再起動現象

  • innoDB の自動インクリメント列は 1 から始まります (メモリに保存され、電源を切ると失われます)
  • MylSAM は最後の自己インクリメントから継続します (ファイル内に存在し、失われません)

DQL クエリ データ (最も重要)

DQL (データクエリ言語:)

  • すべてのクエリ操作は Select を使用します
  • 単純なクエリと複雑なクエリの両方を実行できます。
  • データベース内の中心となる言語と最も重要なステートメント
  • 最も頻繁に使用されるステートメント

選択構文 [ ] はオプションを表します。 { } は必須を表します

select [all | distinct] -- 去重
{
   
   * | table.* | [table.field1[as alias1],[,table.field2[as alias2]][....]} -- 要查询的字段
from table_name [as table_alias] -- (from 表名  as取别名)
   [left | right | inner join table_name2] -- 联合查询 (... join 要连接的表  on 等值判断)
   [where ...]  -- 指定结果需满足的条件(具体的值,子查询语句)
   [group by ...] -- 指定结果按照哪几个字段来分组(通过哪个字段来进行分组)
   [having]  -- 过滤分组的记录必须满足的次要条件 (过滤分组后的信息,条件和where是一样的,就是上下位置不同)
   [order by ...]  -- 指定查询记录按一个或多个条件排序 (通过哪个字段排序)[升序/降序]
   [limit {
   
   [offset,]row_count | row_countOFFSET offset}]; -- 指定查询的记录从哪条至哪条 (起始下标值,页面有多少条记录)
               
-- 查询表中全部信息   
-- SELECT * FROM 表名;
SELECT * FROM `student`;

-- 查询指定字段 
-- SELECT 字段1,字段2... FROM 表名;
SELECT `StudentName`,`Address` FROM `student`;

-- 别名 给结果起一个别名 
-- SELECT 字段1 AS 别名,字段2 AS 别名 FROM 表名;
SELECT `StudentName` AS 姓名,`Address`AS 地区 FROM `student`;

-- 函数 concat(a,b)拼接
SELECT CONCAT('姓名:',StudentName) AS 名字 FROM `student`;

構文: フィールドを選択,…テーブル名から

場合によっては、名前のリストがそれほど明白ではないことがあります。エイリアス AS フィールド名をエイリアスとして使用するだけです

個別の重複に移動

機能: 選択クエリの結果から重複データを削除し、重複データを 1 件だけ表示します。

-- 发现重复数据,去重 
-- SELECT DISTINCT 字段名 FROM 表名;
SELECT DISTINCT `StudentNo` FROM `result`;

データベース列 (式)

-- 查询系统版本
SELECT VERSION();
-- 用来计算
SELECT 100*3-1 AS 计算结果
-- 查询自增的步长
SELECT @@auto_increment_increment;

where 条件節

機能:データ内の修飾された値を取得します

検索条件は 1 つ以上の式で構成されます。結果のブール値

論理演算子
オペレーター 文法 説明する
そして && a と b または a&&b 論理積
または || a または b または a||b 論理的または
ない ! ではありません または ! 論理否定

文法:

そして

フィールド名 = 5 およびフィールド名 = 6 のテーブル名からフィールド名を選択します。

または

フィールド名=6 またはフィールド名=7 のテーブル名からフィールド名を選択します。

ない

フィールド名 = 5 ではないテーブル名からフィールド名を選択します。

ファジークエリ: 比較演算子
オペレーター 文法 説明する
無効である aはnullです 演算子が null の場合、結果は true になります
nullではありません a は null ではありません 演算子が null でない場合、結果は true になります
bとcの間のa a が b と c の間にある場合、結果は true
のように aはbに似ています SQL マッチング、a が b と一致する場合、結果は true
(a1、a2、a3…) の a a が値 a1、a2... のいずれかにあるとすると、結果は true になります
-- Like结合 %(代表0到任意一个字符) _ (表示一个字符)
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE `SubjectName` LIKE '高%';

SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE `SubjectName` LIKE 'C#__';

SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectName LIKE '%数%';

-- in (具体的一个或多个值)
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectNo IN (3,5,2,13);

-- not null 相当于不为空
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectNo IS NOT NULL;

結合テーブルクエリ

結合比較

アイデアは必読であり、非常に役立ちます

-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
SELECT * FROM `student`;
SELECT * FROM `result`;
/* 思路
1.分析需求,分析查询的字段来自哪张表,如果超过一张表就使用(连接查询)
2.确定使用哪种连接查询? 有7种
确定交叉点(这两个表中哪个数据是相同的)如果没有交叉点是查不了东西的
判断的条件就是, 学生表中 StudentNo = 成绩表中 StudentNo
就是学生表拥有StudentNo  成绩表也拥有 StudentNo 共同字段
*/

-- join(连接的表) on(判断的条件)  连接查询
-- where 等值查询

-- inner join 内连接--
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult -- 因为有两个同样的字段,所以需要表名区引用,要不然不知道是哪个表的字段
FROM student AS s
INNER JOIN result AS r   -- 定义了别名,就可以用别名区访问东西了,当然表名也可以,只是会稍微繁琐
WHERE s.StudentNo = r.StudentNo  -- 判两张表是否都有这个字段

-- right join 右连接查询--
SELECT student.StudentNo,StudentName,SubjectNo,StudentResult
FROM student 
RIGHT JOIN result   -- 这是不用别名,用表名的操作,比较繁琐
ON student.StudentNo = result.StudentNo 

-- left join 左连接查询--
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult
FROM student s
LEFT JOIN result r   -- 别名的 AS 是可以省略的
ON s.StudentNo = r.StudentNo
操作する 説明する
内部結合 Union では、このデータを含むテーブルが 1 つ存在する限り、それを取得できます。つまり、複数のテーブルの 1 つが一致します。
左結合 左結合は、右のテーブルに一致するものがない場合でも、左のテーブルからすべての値を返します。
右結合 右結合は、左側のテーブルに一致するものがない場合でも、右側のテーブルからすべての値を返します。
-- (查询了参加考试同学的信息:学号,学生姓名,科目名,分数)  (StudentNo StudentName SubjectName StudentResult)
/* 思路
1.分析需求,分析查询的字段来自哪张表,如果超过一张表就使用(连接查询)  来自( student , result , subject )表
2.确定使用哪种连接查询? 有7种
确定交叉点(这两个表中哪个数据是相同的)如果没有交叉点是查不了东西的
*/
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult` 
FROM `student` AS s
RIGHT JOIN `result` AS r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` AS sub
ON r.`SubjectNo` = sub.`SubjectNo`


-- 步骤
/*
我要查询哪些数据 select ....
从哪几个表中查  frominner(right,left) join 连接的表 on 交叉条件 

假设存在多张表查询,先查询两张表然后再慢慢增加

自己接続

自分のテーブルを自分のテーブルに接続する 要点: 1 つのテーブルを 2 つの同一のテーブルに分割するだけです。

-- ==========自连接==============

CREATE TABLE categorg (
	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)
)ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

INSERT INTO categorg(categoryid,pid,categoryName)
VALUES(2,1,'信息技术'),
(3,1,'软件开发'),
(4,3,'数据库'),
(5,1,'美术设计'),
(6,3,'web开发'),
(7,5,'ps技术'),
(8,2,'办公信息');
-- 查询父子信息
SELECT f.categoryName AS '父栏目',z.categoryName AS '子栏目'
FROM categorg AS f,categorg AS z
WHERE f.categoryid = z.pid  
-- 就相当于 categoryid的值 = pid的值
-- 比如 办公信息的2=信息技术的2 因为1不匹配 所以是单独的

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ページネーションと並べ替え

並べ替え構文: ORDER BY 並べ替えフィールド ASC または DESC

-- order by排序:升序asc,降序desc
-- 语法 ORDER BY 排序的字段  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`
ORDER BY StudentResult ASC

ページング構文: 開始添え字値の制限、ページ上に存在するレコードの数

-- 为什么要分页?
-- 为了缓解数据库压力,给人的体验更好,  还有一种不分页的叫做瀑布流

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`
ORDER BY StudentResult ASC
LIMIT 0,5  -- 语法  limit  起始下标值,页面有多少条记录

サブクエリ

ここで (この値は計算されます)

サブクエリ(内側から外側)を使用して適用し、後で条件を追加します

本質: where ステートメント内でサブクエリ ステートメントをネストする

-- 查询高等数学的所有考试结果(学号 科目名称 成绩),降序查询
 -- 方式一: 使用连接查询
 SELECT `StudentNo`,SubjectName,StudentResult
 FROM `result` AS r
 INNER JOIN `subject` sub
 ON r.`SubjectNo` = sub.`SubjectNo`
 WHERE  SubjectName LIKE '高等数学%'
 ORDER BY StudentResult DESC
 
 
 -- 方式二:使用子查询 (由里及外)  适用于,后面还加条件的
 -- 查询所有考试结果(学号 科目名称 成绩)>70分的,
 SELECT `StudentNo`,SubjectName,StudentResult
 FROM `result` AS r
 INNER JOIN `subject` sub
 ON r.`SubjectNo` = sub.`SubjectNo`
 WHERE StudentResult>=70 
 -- 在基础上增加一个 且是高等数学的
 AND SubjectName = (
	SELECT SubjectName FROM `subject`
	WHERE SubjectName = '高等数学-1'
 )
  
 -- 改造方式二:查询学生学号,学生姓名  成绩大于70分的
 SELECT StudentNo,StudentName FROM student WHERE StudentNo IN (
	SELECT StudentNo FROM result WHERE StudentResult>70 AND SubjectNo =(
		SELECT SubjectNo FROM `subject` WHERE SubjectName = '高等数学-1'
	)
 )
 

グループ化とフィルタリング

-- 查询不同课程的平均分,最高分,最低分,平均分大于90
-- 核心:根据不同的课程分组    不分组的话只有一个,按照最高的 最低的来排   因为每个课程都有最高分最低分
SELECT SubjectName,AVG(StudentResult)AS 平均分,MAX(StudentResult)AS 最大值,MIN(StudentResult)AS 最小值
FROM `result` AS r 
INNER JOIN `subject` AS sub
ON r.`SubjectNo` = sub.`SubjectNo`
GROUP BY r.SubjectNo  -- 指定结果按照哪几个字段来分组
HAVING 平均分>=80  -- 过滤分组的记录必须满足的次要条件

MySQL関数

公式ウェブサイト: https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html

よく使われる機能

-- 数学运算
SELECT ABS(-8)  -- abs 绝对值
SELECT CEILING(9.4)  -- ceiling 向上取整
SELECT FLOOR(9.4)  -- floor 向下取整
SELECT RAND()  -- rand 返回一个0~1之间的随机数
SELECT SIGN(7)  -- sign 判断一个数的符号 负数返回-1 正数返回1


-- 字符串函数
SELECT CHAR_LENGTH('dffhf附件四')  -- char_length 字符串长度
SELECT CONCAT('热','爱','编程')  -- concat 拼接字符串
SELECT INSERT('我热爱编程helloword',2,3,'我超级喜欢')  -- insert 查询 从某个位置开始 替换某个长度
SELECT LOWER('ASDDlele')  -- lower 小写字母
SELECT UPPER('asddLELE')  -- upper 大写字母
SELECT INSTR('abcdeh','h')  -- instr 返回第一次出现的字串的索引
SELECT REPLACE('坚持就一定能成功','坚持','努力')  -- replace 替换出现的指定字符串
SELECT SUBSTR('坚持就一定能成功',4,6)  -- substr 返回指定的子字符串 从哪里开始,到哪里结束
SELECT REVERSE('坚持就一定能成功')  -- reverse 反转

		-- 查询性李的  然后替换名字 利
		SELECT REPLACE(StudentName,'李','利') FROM student
		WHERE StudentName LIKE '李%'
 
 
-- 时间和日期函数(记住)
SELECT CURRENT_DATE()  -- current_date 获取当前日期
SELECT CURDATE()  -- curdate 获取当前日期
SELECT NOW()  -- now 获取当前的时间
SELECT LOCALTIME()  -- localtime 本地时间
SELECT SYSDATE()  -- sysdate 系统时间

SELECT YEAR(NOW())  -- year 年
SELECT MONTH(NOW())  -- month 月
SELECT DAY(NOW())  -- day 日
SELECT HOUR(NOW())  -- hour 时
SELECT MINUTE(NOW()) -- minute 分
SELECT SECOND(NOW())  -- second 秒
 

-- 系统
SELECT SYSTEM_USER() -- system_user 获取当前用户
SELECT USER()	-- user 获取当前用户
SELECT VERSION()  -- version 获取当前版本

集計関数(よく使われる)

関数名 説明する
カウント() カウント
和()
平均() 平均値
最大() 最大値
分() 最小値
-- ========聚合函数========
-- 都能够统计表中的数据
SELECT COUNT(`StudentNo`)FROM student;  -- count(字段) 会忽略所有的null值
SELECT COUNT(*) FROM student  -- count(*) 不会忽略null值,本质 计算行数
SELECT COUNT(1) FROM student  -- count(1) 不会忽略所有的null值,本质 计算行数

SELECT SUM(StudentResult)AS 总和 FROM result; -- sum 总和
SELECT AVG(StudentResult)AS 平均分 FROM result; -- avg 平均分 
SELECT MAX(StudentResult)AS 最高分 FROM result; -- max 最大值
SELECT MIN(StudentResult)AS 最低分 FROM result; -- min 最小值

データベースレベルのMD5暗号化(拡張)

MD5とは何ですか?

主にアルゴリズムの複雑さと不可逆性を強化します。

MD5 は不可逆的であり、MD5 の特定の値は同じです

MD5クラッキングWebサイトの原理、その背後に辞書があり、MD5暗号化後の値、暗号化前の値

--  ============测试MD5 加密=========
CREATE TABLE `testmd5`(
   `id` INT(4) NOT NULL,
   `name` VARCHAR(20) NOT NULL,
   `pwd` VARCHAR(50) NOT NULL,
   PRIMARY KEY(`id`)
)

-- 明文密码
INSERT INTO `testmd5` VALUES(1,'zhangsan','123456'),(2,'lishi','123456'),(3,'wangwu','123456');
-- 加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE id = 1;
-- 加密全部的密码
UPDATE testmd5 SET pwd = MD5(pwd);
-- 插入的时候加密
INSERT INTO testmd5 VALUES(4,'xiaoming',MD5('123456')) ;
-- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值
SELECT * FROM testmd5 WHERE `name` = 'xiaoming' AND pwd = MD5('123456')

もの

物とは何ですか

両方とも成功するか、両方とも失敗するかのどちらかです

一連の SQL をバッチに入れて実行します ~

物事の原則: DCID の原則、原子性、一貫性、分離、耐久性 (ダーティ リーディング、ファントム リーディングなど)

原子性

両方とも成功するか、両方とも失敗するかのどちらかです

一貫性

トランザクションの前後でデータの整合性が一貫している必要がある

分離

モノの分離とは、複数のユーザーが同時にデータベースにアクセスする場合、各ユーザー用にデータベースが開いているモノが他のトランザクションの操作データに干渉されず、モノ同士が分離されていなければならないことを意味します。

耐久性

送信されたものは元に戻すことはできず、データベースに永続化されます。

孤立によって引き起こされるいくつかの問題

ダーティリード

あるトランザクションが別のトランザクションからコミットされていないデータを読み取ることを指します。

反復不可能な読み取り

トランザクション内のテーブル内の特定の行のデータを読み取る場合、複数の読み取りの結果は異なります。(これは必ずしも間違いではありません。状況によっては間違っているだけです)

バーチャルリーディング(ファントムリーディング)

これは、他のものによって挿入されたデータがトランザクション内で読み取られることを意味し、その結果、前後の読み取りの間に不整合が生じます。

-- =============事物
-- mysql 是默认开启事务自动提交的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认的)

-- 手动处理事物
 SET autocommit = 0 -- 关闭自动提交
 -- 事物开启
 START TRANSACTION  -- 标记一个事务的开始,从这个之后的sql都在同一个事物内
 

  -- 提交:持久化(成功)
  COMMIT
  -- 回滚:回到原来的样子(失败)
  ROLLBACK
  
  -- 事务结束
  SET autocommit = 1 -- 开启自动提交

-- 了解
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点


シミュレーションシナリオ

-- 转账例子
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop

CREATE 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=utf8

INSERT INTO `account`(`name`,`money`)
VALUES('A',2000.00),('B',10000.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;  -- 恢复默认值,开启自动提交

索引

MySQL のインデックスの公式定義は次のとおりです。 **インデックスは、MySQL がデータを効率的に取得するのに役立つデータ構造です。

文章のバックボーンを抽出すると、インデックスの本質がわかります。インデックスはデータ構造です。

指数の分類

テーブルには、主キー インデックスが 1 つだけ、一意のインデックスが複数存在できます。

  • 主キーインデックス(主キー)
    • 一意の識別子である主キーは繰り返すことができず、主キーとして存在できる列は 1 つだけです。
  • 一意のキー
    • 列の重複を避けるために、一意のインデックスを繰り返し、複数の列を一意のインデックスとして識別できます。
  • 通常のインデックス(キー)
    • デフォルトでは、インデックスとキーのキーワードが設定に使用されます。
  • 全文インデックス (FullText)
    • 特定のデータベース エンジン MyISAM でのみ利用可能
    • インデックスを追加せずにデータを迅速に検索することは走査を意味し、インデックスを追加することは位置決めを意味します。
-- 索引的使用
 -- 1. 在创建表的时候给字段增加索引
 -- 2. 创建完毕后,增加索引
-- 显示所有的索引信息 SHOW INDEX FROM 表名
SHOW INDEX FROM student
 
-- 增加一个全文索引(索引名) 列名
ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `StudentName`(`StudentName`);

-- explain 分析sql执行的状况
EXPLAIN SELECT * FROM student;  -- 非全文索引

EXPLAIN SELECT * FROM student WHERE MATCH(studentName)AGAINST('李')

テストインデックス

 
CREATE TABLE `app_user` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT '' COMMENT '用户名称',
  `email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
  `phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
  `gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男 1:女)',
  `password` VARCHAR(100) NOT NULL COMMENT '密码',
  `age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'

SHOW CREATE DATABASE `school`
SHOW  TABLES;

-- 插入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`)
	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;

SELECT mock_data();

SELECT * FROM app_user WHERE `name` = '用户500000'; -- 没创建索引之前执行6秒

-- id_表名_字段名
-- create index 索引名 no 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
SELECT * FROM app_user WHERE `id` = 500000; -- 创建索引之后执行0.007秒

データの量が少ない場合、インデックスはあまり役に立ちませんが、大きなデータになると、その違いは非常に明らかです。

インデックス作成の原則

  • インデックスが多ければ多いほど良い
  • プロセス変更データのインデックスを作成しない
  • データ量が少ないテーブルにはインデックスを付ける必要はありません
  • インデックスは通常、クエリによく使用されるフィールドに追加されます。

インデックスデータ構造

ハッシュ型インデックス

Btree: InnoDB のデフォルトのデータ構造

読む: http://blog.codinglabs.org/articles/ Theory-of-mysql-index.html

権限管理とデータベースのバックアップ

ユーザー管理

SQLコマンドの操作

ユーザーテーブル: mysql.user

要点: この表を読んで追加、削除、変更、確認してください。

-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码';
CREATE USER xun IDENTIFIED BY '123456';

-- 修改密码 (修改当前用户密码)
SET PASSWORD = PASSWORD('111111');

-- 修改密码(修改指定用户密码)
SET PASSWORD FOR xun = PASSWORD('111111');

-- 重命名 RENAME USER 原来名字 TO 新的名字;
RENAME USER xun TO xun2;

-- 用户授权 ALL PRIVILEGES 全部的权限 ,库.表
-- ALL PRIVILEGES 除了给别人权限,其他的都能干
GRANT ALL PRIVILEGES ON *.* TO xun2

-- 查询权限
SHOW GRANTS FOR xun2;  -- 查看指定用户的权限
SHOW GRANTS FOR root@localhost

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM xun2

-- 删除用户
DROP USER xun2

MySQLのバックアップ

バックアップする理由:

  • 重要なデータが失われないようにする
  • データ転送

MySQLデータベースのバックアップ方法

  • 物理ファイルのデータフォルダーを直接コピーする
  • Sqlyog 視覚化ツールでの手動エクスポート
    • エクスポートするテーブルのデータベースで、右クリックして [バックアップ] を選択し、次に [SQL ダンプ] を選択します。
  • コマンドラインを使用して mysqldump をエクスポートする コマンドラインの使用
# mysqldump -h主机 -u用户名 -p密码 数据库 表名 > 物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 shop account >E:/aa.sql

# 导出多个表
# mysqldump -h主机 -u用户名 -p密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名

# 导出数据库
mysqldump -h主机 -u用户名 -p密码 数据库 > 物理磁盘位置/文件名

#导入
#登录的情况下,切换到指定的数据库
# source 备份文件
source e:aa.sql

# 或
mysql -u用户名 -p密码 库名<备份文件

標準的なデータベース設計

なぜデザインが必要なのか

データベースがより複雑になると、設計が必要になります。

不適切なデータベース設計:

  • データの冗長性、スペースの無駄遣い
  • データベースの挿入と削除は面倒で異常です [物理外部キーの使用をシールドする]
  • プログラムのパフォーマンスが低い

優れたデータベース設計:

  • メモリスペースを節約する
  • データベースの整合性を確保する
  • システム開発を促進します

ソフトウェア開発、データベース設計について

  • 分析ニーズ: ビジネスのニーズと処理が必要なデータベースを分析します。

  • 概略設計:設計関係図 ER図

データベースを設計する手順: (個人ブログ)

  • 携帯電話情報、分析ニーズ
    • ユーザーテーブル (ユーザーのログインとログアウト、ユーザーの個人情報、ブログ、カテゴリの作成)
    • 分類表(記事分類、作成者)
    • 記事テーブル(記事情報)
    • コメントフォーム
    • フレンドリンクリスト(フレンドリンク情報)
    • カスタム テーブル (システム情報、キーワード、または一部のメイン フィールド) キー: 値
  • エンティティの特定 (各フィールドへの要件の実装)
  • エンティティ間の関係を特定する
    • ブログ: ユーザー -> ブログ
    • カテゴリを作成します: ユーザー -> カテゴリ
    • フォロー: ユーザー -> ユーザー
    • フレンドリーリンク: リンク
    • コメント: ユーザー ユーザー ブログ

三大規範

データの正規化が必要な理由

  • 重複した情報
  • 更新例外
  • 例外の挿入
    • 情報が正しく表示されない
  • 例外の削除
    • 有効な情報の喪失

3 つの主要なパラダイム

第 1 正規形 (1NF)

原子性: 各列を再分割できないようにする

第 2 正規形 (2NF)

前提条件: 第一正規形を満たす

各表には 1 つのことだけが説明されています

第 3 正規形 (3NF)

前提条件: 第 1 正規形と第 2 正規形を満たすこと

第 3 正規形では、データ テーブル内のデータの各列が主キーに直接関連付けられており、間接的に関連付けることができないことを保証する必要があります。

(データベース設計の標準化)

標準化とパフォーマンスの問題

関連クエリのテーブルは 3 テーブルを超えてはなりません

  • 商用化のニーズと目標を考慮すると、(コスト、ユーザー エクスペリエンス!) データベースのパフォーマンスの方が重要です。
  • パフォーマンスの問題を標準化する場合は、標準化について適切に考慮する必要があります。
  • いくつかのテーブルに冗長なフィールドを意図的に追加します。(複数テーブルクエリから単一テーブルクエリへ)
  • 計算列を意図的に追加する (大きなデータ量から小さなデータ量へのクエリ: インデックス)

JDBC (キー)

データベース主導型

ドライバー: サウンド カード、グラフィック カード、データベースはすべて、実行するためにドライバーを必要とします。

アプリケーションは、データベースに直接接続するのではなく、最初にデータベース ドライバーに接続し、次にドライバーからデータベースに接続します。

JDBC

開発者の (統合データベース) 操作を簡素化するために、SUN は、一般に JDBC として知られる (Java データベース操作用の) 仕様を提供しています。

これらの仕様の実装は特定のメーカーによって行われます。

開発者にとって必要なのは、JDBC インターフェイスの操作をマスターすることだけです。

java.sql をインポートする必要があります javax.sql はデータベース ドライバー パッケージ mysql-connector-java-5.1.47.jar もインポートする必要があります

最初の 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(60),
  `email` VARCHAR(60),
  `birthday` DATE
  );
  
 INSERT INTO users(id,`name`,`password`,email,birthday) 
 VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lishi','123456','[email protected]','1985-12-04'),
(3,'wangwu','123456','[email protected]','1981-12-04');
  1. プロジェクトを作成する

  2. データベースドライバーをインポートします。jar パッケージを自分でダウンロードするか、maven を使用してインポートすることもできます (推奨) mysql-connector-java-5.1.47.jar

  3. テストコードを書く

    package com.kuang.jdbc01;
    
    import java.sql.*;
    
    // 第一个JDBC程序
    public class test01 {
          
          
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
          
          
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
    
            //2.用户信息和url
            //"jdbc:mysql://localhost:3306/数据库名?支持中文编码&设置中文字符集=utf8&use使用安全的一个连接";
            String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
            //用户名
            String username = "root";
            //密码
            String password = "123456";
    
            //3.连接成功  后,会返回 数据库对象
            //驱动管理DriverManager  获得连接getConnection   代表数据库connection
            Connection connection = DriverManager.getConnection(url, username, password);
    
            //4.执行SQL的对象     用statement执行sql对象
            Statement statement = connection.createStatement();
    
            //5.执行SQL对象 去 执行SQL, 可能存在结果,查看返回结果
            String sql = "SELECT * FROM users";
            // 查询 sql
            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"));
                System.out.println("============================");
            }
            //6.释放连接
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    

    手順の概要: クエリのみが結果セットを持ちます。

    1. ドライバーのロード Class.forName()
    2. データベース DriverManager に接続します
    3. オブジェクトを取得 SQLを実行する文
    4. 返された結果セットを取得する
    5. 接続を解除する

    ドライバーマネージャー

     // DriverManager.registerDriver(new com.mysql.jdbc.Driver());
     Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
    
     // connection 代表数据库
    //数据库设计自动提交
    //事务提交
    //事物回滚
            connection.rollback();
            connection.commit();
            connection.setAutoCommit();
    

    URL

    String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
    //mysql  -- 3306
    // sTRING URL = 协议://主机地址+端口号/数据库名?参数1&参数2&参数3
    
    // oralce --1521
    // jdbc:oracle:thin:@localhost:1521:sid
    

    SQLオブジェクトを実行する文

    String sql = "SELECT * FROM users"; //编写SQL
    
    statement.executeQuery();  //查询操作 返回ResultSet(结果集)
    statement.execute();        //执行任何sql
    statement.executeUpdate();  //更新、插入、删除、都使用这个,返回一个受影响的行数
    

    ResultSet クエリ結果セット: すべてのクエリ結果をカプセル化します。

    指定されたデータ型を取得します

            resultSet.getObject();// 在不知道列类型的情况下使用
            //如果知道列的类型就使用指定的类型
            resultSet.getString();
            resultSet.getInt();
            resultSet.getFloat();
            resultSet.getTime();
    		...
    

    トラバース、ポインタ

            resultSet.beforeFirst();//移动到最前面
            resultSet.afterLast();//移动到最后面
            resultSet.next();//移动到下一个数据
            resultSet.previous();//移动到下一行
            resultSet.absolute(row);//指定到移动行
    

    リソースをリリースする

    resultSet.close();
    statement.close();
    connection.close();
    //耗资源 ,用完关掉
    

ステートメントオブジェクト

jdbc のステートメント オブジェクトは、SQL ステートメントをデータベースに送信するために使用されます。データベースの追加、削除、変更、クエリを完了したい場合は、追加、削除、変更、クエリ ステートメントを、このオブジェクト。

Statement オブジェクトのexecuteUpdate メソッドは、追加、削除、および変更の SQL ステートメントをデータベースに送信するために使用されます。executeUpdate の実行後、整数が返されます (つまり、追加、削除、および変更ステートメントにより複数の行が発生しました)変更するデータベース内のデータの数)。

Statement.executeQuery メソッドは、クエリ ステートメントをデータベースに送信するために使用されます。executeQuery メソッドは、クエリ結果を表す ResultSet オブジェクトを返します。

CRUD操作-create

データ追加操作を完了するには、executeUpdate (String sql) メソッドを使用します。操作例:

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

CRUD 操作 - 削除

データ削除操作を完了するには、executeUpdate(String sql) メソッドを使用します。操作例:

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

CRUD操作-更新

データ変更操作を完了するには、executeUpdate(String sql) メソッドを使用します。操作の例:

Statement statement = connection.createStatement();
String sql = "update users set name = '' where name = ''";
int sum = statement.executeUpdate(sql);
if(sum>0){
    
    
    System.out.println("修改成功");
}

CRUD 操作 - 読み取り

データ クエリ操作を完了するには、executeQuery(String sql) メソッドを使用します。操作の例:

Statement statement = connection.createStatement();
String sql = "select * from users where id=1";
ResultSet rs = statement.executeQuery(sql);
while(rs.next()){
    
    
    //根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
コード

1. 設定ファイルの作成

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

2. 抽出ツール

package com.kuang.jdbc02.utils;

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{
    
         //反射获取类的装载器,然后在获取资源(db.properties)
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            //属性
            Properties properties = new Properties();
            //加载获取到的属性
            properties.load(in);
//            从文件把这4个信息读取出来
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //1.驱动只用加载一次
            Class.forName(driver);
        }catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
    
    
        return  DriverManager.getConnection(url, username, password);
    }
    //释放资源
    public static void release(Connection conn, Statement sta, ResultSet res) throws SQLException {
    
    
        if (res!=null){
    
    
            res.close();
        }
        if (sta!=null){
    
    
            sta.close();
        }
        if (conn!=null){
    
    
            conn.close();
        }
    }
}

3. 追加、削除、変更の書き込み

インサートを追加

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestInsert {
    
    

    public static void main(String[] args) throws SQLException {
    
    

            Connection connection = JdbcUtils.getConnection(); //通过工具类获取链接

            Statement statement = connection.createStatement();//获得SQL的执行对象
            String sql = "INSERT INTO users(id,`name`,`password`,`email`,`birthday`) VALUES(5,'fenqi','123456','[email protected]','1985-12-04')";
            int i = statement.executeUpdate(sql);
            if (i>0){
    
    
                System.out.println("插入成功");
            }
            JdbcUtils.release(null,null,null); //释放资源
    }
}


消去

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select  * from users";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);

        while(resultSet.next()){
    
    
            System.out.println("id"+resultSet.getInt("id"));
            System.out.println("name"+resultSet.getString("name"));
            System.out.println("password"+resultSet.getString("password"));
            System.out.println("email"+resultSet.getString("email"));
            System.out.println("birthday"+resultSet.getDate("birthday"));
            System.out.println("=================");
        }
        JdbcUtils.release(null,null,null);
    }
}

変更更新

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestUpdate {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "update users set name='xiugai' where id = 1";
        //执行
        int i = statement.executeUpdate(sql);

        if (i>0){
    
    
            System.out.println("更新成功");
        }
        JdbcUtils.release(null,null,null);
    }
}

チェックセレクト

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select  * from users";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);

        while(resultSet.next()){
    
    
            System.out.println("id"+resultSet.getInt("id"));
            System.out.println("name"+resultSet.getString("name"));
            System.out.println("password"+resultSet.getString("password"));
            System.out.println("email"+resultSet.getString("email"));
            System.out.println("birthday"+resultSet.getDate("birthday"));
            System.out.println("=================");
        }
        JdbcUtils.release(null,null,null);
    }
}

SQLインジェクションの問題

SQL には脆弱性があり、攻撃を受けてデータ漏洩を引き起こす可能性があります

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class SQL注入 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //正常登录
        // login("lishi","123456");
        login(" 'or' 1=1"," 'or' 1=1");

    }
    public static void login(String username,String password) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select * from users where `name` = '"+username+"' and password='"+password+"'";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
    
    
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
            System.out.println("======================");
        }
    }
}

PreparedStatement オブジェクト

PreparedStatement は SQL インジェクションを防ぎます。より良い結果

1. 新規追加

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestInsert {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //调用工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //使用? 占位符代表参数
        String sql = "insert into users(id,name,password,email,birthday)values(?,?,?,?,?)";
        //预编译SQL,先写sql,然后不执行
        PreparedStatement pr = connection.prepareStatement(sql);
        //手动给参数赋值
        pr.setInt(1,5); //第一个值为参数下标,第二个为参数 id
        pr.setString(2,"王胜");
        pr.setString(3,"123456");
        pr.setString(4,"[email protected]");
        // 注意点:sql.Date     数据库 java.sql.Date()
        //       util.Date     Java   new Date().getTime() 获得时间戳
        pr.setDate(5,new java.sql.Date(new Date().getTime()));

        //执行
        int i = pr.executeUpdate();

        if (i>0){
    
    
            System.out.println("插入成功");
        }
        JdbcUtils.release(null,null,null);
    }
}

2. 削除

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestDelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?   代表参数
        String sql = "delete from users where id = ?";
        //预编译SQL  先写sql 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动给参数赋值
        pre.setInt(1,5);
        //执行
        int i = pre.executeUpdate();

        if (i>0){
    
    
            System.out.println("删除成功");
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

3.アップデート

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestUpdate {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?  代表参数
        String sql = "update users set name = ? where  name = ?";
        //预编译SQL  先写SQL 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动给参数赋值
        pre.setString(1,"zhangsan");
        pre.setString(2,"xiugai");
        //执行
        int i = pre.executeUpdate();

        if (i>0){
    
    
            System.out.println("修改成功");
        }
        //关闭资源
        JdbcUtils.release(null,null,null);
    }
}

4. クエリ

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?  代表参数
        String sql = "select * from users where id=?";
        //预编译SQL  先写sql  然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动传递参数
        pre.setObject(1,2);
        //执行
        ResultSet resultSet = pre.executeQuery();

        while (resultSet.next()){
    
    
            System.out.println(resultSet.getInt("id"));
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

5. SQL インジェクションを防止する

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //正常登录
        // login("lishi","123456");
        login("'' or 1=1","123456");

    }
    public static void login(String username,String password) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符? 传递参数
        //PreparedStatement放置SQL注入的本质,把值传递进来的参数当作字符
        //假设其中存在转义字符,比如说 ‘ 会被直接转义
        String sql = "select * from users where name = ? and password = ?";
        //预编译Sql  先写sql 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动传递参数
        pre.setString(1,username);
        pre.setString(2,password);
        //执行
        ResultSet resultSet = pre.executeQuery();

        while(resultSet.next()){
    
    
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
            System.out.println("======================");
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

アイデアがデータベースに接続される

  1. 右側でデータベースを見つけてクリックします

  2. + 記号をクリック → データ ソースを選択 → MySql を選択

  3. 次に、ユーザー名とパスワードを入力し、「接続のテスト」をクリックします。

    • 成功すると✔が表示されます

      • 次に、「適用」をクリック→少し上の「スキーマ」をクリック→そして追加するデータベースを選択します。
    • 失敗した場合は、タイムゾーンが異常であるか、バージョンが正しく選択されていません。

      • 左側の「NySQL」をクリックします

      • クラス選択 com.musql.jdbc.Driver

      • ドライバー ファイル 対応する SQL バージョンを選択 → [適用] をクリック → アカウントとパスワードを再入力して接続します

      • タイム ゾーンの場合は、コマンド ラインで SQL を開き、タイム ゾーンを設計する必要があります。

        • -- 查看时区,显示 SYSTEM 就是没有设置时区啦。
          show variables like'%time_zone';
          
        • --设置时区 设置完需要重新连接sql重新查看
          set global time_zone = '+8:00';
          

もの

両方とも成功するか、両方とも失敗するかのどちらかです

ACIDの原則

原子性:

すべてが完了したか、まったく完了していないかのどちらかです。

一貫性:

総数は変わらない

分離:

複数のプロセスが相互に干渉しない

耐久性:

一度送信すると元に戻すことはできず、データベースに永続化されます。

分離の問題:

ダーティ リード: トランザクションが別のコミットされていないトランザクションを読み取る

非反復読み取り: 同じトランザクション内で、テーブル内のデータが繰り返し読み取られ、テーブルのデータが変更されます。

仮想読み取り (ファントム読み取り): トランザクションでは、他のユーザーによって挿入されたデータが読み取られるため、読み取り結果が不一致になります。

コード

1. トランザクションconn.setAutoCommit(false) を開きます。

2. 一連の業務執行が完了したら、取引を提出します

3. catch ステートメントに表示されるロールバック ステートメントを定義できますが、デフォルトでは失敗した場合にロールバックされます。

package com.kuang.jdbc04;

import com.kuang.jdbc02.utils.JdbcUtils;
import com.sun.org.apache.xpath.internal.objects.XNull;

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

public class TestTransation1 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
         Connection conn = null;
        PreparedStatement st = null;
        try {
    
    
            //通过工具类连接数据库
             conn = JdbcUtils.getConnection();
            //关闭数据库的自动提交,会自动开启事物
            conn.setAutoCommit(false);

            //编写SQL语句
            String sql1 = "update account set miney = miney-100 where name = 'A'";
            //预编译SQL
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            //编写SQL语句
            String sql2 = "update account set miney = miney+100 where name = 'B'";
            //预编译SQL
            st= conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("成功");
        }catch (Exception e){
    
    
            try{
    
    
                conn.rollback(); //如果失败则回滚事物
            } catch (SQLException throwables)
            {
    
    
                throwables.printStackTrace();
            }
            e.printStackTrace();
        }finally {
    
    
            //释放资源
            JdbcUtils.release(conn,st,null);
        }

    }
}

データベース接続プール

データベース接続 - 実行完了 - 解放

接続の解放はシステム リソースの無駄です

プーリング技術: 事前にいくつかのリソースを準備し、事前に準備されたリソースに接続します。

例(銀行)

例えば、銀行に営業に行く場合、ドアを開ける→処理する→ドアを閉める、そしてドアを開ける→処理する→ドアを閉めるという通常のデータベース操作ですが、非常に面倒で面倒です。

接続プールを使用してドアを開ける - 販売員を配置する - 待機 - ハンドルを配置する - 使用していないときはドアを完全に閉める

よく使用される 10 個の接続

最小接続数: 10 (最小接続数は、一般的に使用される接続数に基づいて設計されます)

最大接続数: (サービス負荷が最も高いのはオンラインです。それを超える場合は、列に並んで待つ必要があります)

待機タイムアウト:(待機時間を超えるまで待機しません)

接続プールを作成するには、DataSource インターフェイスを実装するだけで済みます。

オープンソース データ ソースの実装 (すぐに使用可能)

DBCP

C3P0

ドルイド:アリババ

これらのデータベース接続プールを使用すると、プロジェクト開発中にデータベースに接続するためのコードを記述する必要がなくなりました。

DBCP

必要なJarパッケージ

commons-dbcp-1.4、commons-pool-1.6

C3P0

Jarパッケージが必要です

c3p0-0.9.5.5、mchange-commons-java-0.2.19

結論は

どのようなデータ ソースが使用されても、本質は同じであり、DataSource インターフェイスもメソッドも変わりません #MySql

  • MySQL で使用される SQL 言語は、データベースにアクセスするために最も一般的に使用される標準化された言語です。MySQL ソフトウェアはデュアル ライセンス ポリシーを採用しており、コミュニティ バージョンと商用バージョンに分かれており、その小型、高速、総所有コストの低さ、特にオープン ソースの特性により、MySQL は一般に Web サイトのデータベースとして選択されます。中小規模のウェブサイトの開発。
  • MySQL はリレーショナル データベース管理システムです
  • スウェーデンのMySQL AB社が開発
  • 現在はOracleの製品になっています
  • MySQL は、最高のRDBMS (リレーショナル データベース管理システム、リレーショナル データベース管理システム) アプリケーション ソフトウェアの 1 つです。
  • オープンソースのデータベース ソフトウェア
  • サイズが小さく、スピードが速く、総所有コストが低く、採用コストも比較的低いため、誰もがその方法を知っておく必要があります。
  • 公式ウェブサイト:https://www.mysql.com/

MySQLをインストールする

  1. 解凍する

  2. このパッケージをコンピュータ環境のディレクトリに置きます~

  3. 環境変数を構成する

    1. 新しいコンピュータ環境のパスを作成し、インストール パス D:\mysql\mysql-8.0.21\bin をコピーします。
  4. 新しいmysql設定ファイルを作成する

    [mysqld]
    # 目录要换成自己的	
    basedir=D:\mysql\mysql-8.0.21\
    datadir=D:\mysql\mysql-8.0.21\data\
    port=3306
    skip-grant-tables
    
  5. CMDを管理者モードで起動し、mysqlのbinディレクトリに移動します。

  6. mysqlサービスをインストールする

    • mysqld -install
  7. データベースファイルの初期化

    • mysqld --initialize-insecure
  8. 起動する

    • ネットスタートmysql
  9. デフォルトのパスワードは空です。ログイン コマンド

    • mysql -uroot -p
  10. パスワード変更はMysql8.0のため、パスワード機能の使用はサポートされていません。

    • mysqlを使用するデータベースを選択します
    • パスワードを変更します。「123456」で識別されるユーザー「root」@「localhost」を変更します。
  11. 更新: 権限をフラッシュ; 更新後に終了: 終了; ログアウトして再度ログインするだけです

コマンドライン

--连接数据库
mysql -u root -p123456
--修改用户密码
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
-- 查看时区,显示 SYSTEM 就是没有设置时区啦。
show variables like'%time_zone';
--设置时区 设置完需要重新连接sql重新查看
set global time_zone = '+8:00';
--刷新权限
flush privileges;

--所有的sql语句都使用;结尾

--查看所有的数据库
show databases;
--切换数据库
use 数据库名
--查看数据库中所有的表
show tables;
--显示表中所有的信息
describe 表名

---------------------
--创建一个数据库
create database 数据库名
--退出连接
exit;
--单行注释
/*多行注释*/

データベースxxx言語

DDLデータベース制御言語

DMLデータベース操作言語

DQL データベース クエリ言語

DCL データベース制御言語

運用データベース

データベースの操作 > データベース内のテーブルの操作 > データベース内のテーブルのデータの操作

mysql キーワードは大文字と小文字を区別しません [ ] はオプションを意味します

**ディスプレイ名またはデータベース名が特殊文字の場合は、「**」を追加します。

運用データベース

  1. データベースの作成

    CREATE DATABASE [IF NOT EXISTS] 数据库名
    
  2. データベースの削除

    DROP DATABASE IF EXISTS 数据库名
    
  3. データベースを使用する

    USE `数据库名`
    
  4. データベースを見る

    SHOW DATABASE
    

データベースの列の型

数値

  • tinyint 非常に小さいデータ 1 バイト
  • smallint より小さいデータ 2 バイト
  • Mediumint 中サイズのデータ​​ 3 バイト
  • int標準整数一般的に使用される 4 バイト
  • bigint より大きなデータ 8 バイト
  • float 浮動小数点数 4 バイト
  • 倍精度浮動小数点数 8 バイト (精度の問題)
  • 10 進数 文字列形式の浮動小数点数に対して財務計算を実行する場合、通常は 10 進数が使用されます。

  • 文字列固定サイズ0~255
  • varchar変数文字列0~65535 よく使用される変数文字列
  • tinytext 小さなテキスト 2^8-1
  • テキストテキスト文字列2^16-1 大きなテキストを保存

時間日付

  • 日付 YYYY-MM-DD 日付形式
  • 時間 HH:mm:ss 時間形式
  • datetime YYYY-MM-DD HH:mm:ss最も一般的に使用される時刻形式
  • タイムスタンプ 1970.1.1 から現在までのミリ秒数も一般的に使用されます。
  • year は年を表します

ヌル

  • 値が不明です
  • 演算には null を使用しないでください。結果は null になります。

データベースフィールドの属性 (強調)

署名なし:

  • 符号なし整数
  • 列を負の数として宣言できないことが宣言されています

ゼロフィル:

  • 0 パディング
  • 桁が不足しています。0 を使用して埋めてください。int (3)、5 — 005

自己増加

  • 通常は自動インクリメントとして理解され、前のレコードに基づいて自動的に +1 (デフォルト)
  • 通常、一意の主キーを設計するために使用されます。これは整数型である必要があります。
  • 主キーの自動インクリメントの開始値とステップサイズをカスタマイズできます。

null ではありません NULL ではありません

  • デフォルト値を設定してください!
  • 性別、デフォルト値は男性です。この列の値が指定されていない場合は、デフォルト値が設定されます。

拡大する

-- 每一个表都必须存在以下五个字段,未来做项目用的,表示一个表记录存在的意义
id 主键
version 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间

データベーステーブルの作成(ポイント)

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 '密码',
  `set` 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

形式: [ ] は、存在するかどうかを判断するためのオプションの IF NOT EXISTS を示します。

CREATE TABLE [IF NOT EXISTS] `表名`(
    `字段名` 列类型 [非空] [自增] [注释] '学号',
    `字段名` 列类型 [非空] [默认值] '匿名' [注释] '姓名'.....(注意最后一行不要加,)
    )[引擎]ENGINE=INNODB[字符集]CHARSET=utf8)

共通コマンド

 -- 查看数据库的语句
SHOW CREATE DATABASE 数据库名;

-- 查看表中数据的定义语句
SHOW CREATE TABLE 表名; 

-- 显示表的结构
DESC 表名; 

テーブルの変更、削除

改訂

-- 修改表名 ALTER TABLE 旧表名 RENAME AS 新表名;
ALTER TABLE student RENAME AS student1;

-- 增加表的字段  ALTER TABLE 表名 ADD 字段名 列属性;
ALTER TABLE student1 ADD age INT(11);

-- 修改表的字段约束 ALTER TABLE 表名 MODIFY 字段名 列属性;
ALTER TABLE student1 MODIFY age VARCHAR(20);

-- 修改表字段名 ALTER TABLE 表名 CHANGE 旧字段 新字段 列属性;
ALTER TABLE student1 CHANGE age age1 INT(1);

-- 删除表字段 ALTER TABLE 表名 DROP 字段名;
ALTER TABLE student1 DROP age1;

消去

-- 删除表 (判断表存在 在删除)
DROP TABLE IF EXISTS student1;

MySQL データ管理

外部キー (理解するだけ)

方法 1: テーブルの作成時に制約を追加する (面倒で複雑)

CREATE TABLE IF NOT EXISTS `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 '密码',
  `set` 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_gradeid` (`gradeid`), --定义外键 key
  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`) -- 
)ENGINE=INNODB DEFAULT CHARSET=utf8

外部キー関係を持つテーブルを削除する場合は、まず他人を参照しているテーブル(スレーブテーブル)を削除し、次に参照されているテーブル(マスターテーブル)を削除する必要があります。

方法 2: テーブルが正常に作成された後、外部キー制約を追加します。

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

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 '密码',
  `set` 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 表名 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 哪个表(哪个字段);
ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);

DML 言語 (すべて記憶)

データベースの意味:データストレージ、データ管理

DML言語: データ操作言語

  • 入れる
  • アップデート
  • 消去

に追加

入れる

-- insert into 表名(字段1,字段2,...)values(值1),(值2)
-- 一般写插入语句,我们一定要数据和字段一一对应
 
INSERT INTO `grade`(`gradeid`,`gradename`)VALUES(1,'大一'),(2,'大二');

構文: テーブル名 (フィールド 1、フィールド 2、…) に値 (値 1)、(値 2)… を挿入します。

予防:

  1. カンマを使用してフィールドを区切ります
  2. フィールドは省略可能ですが、次の値は 1 対 1 に対応する必要があります (
    例: テーブル名に挿入) 値 (値...) 内の値は、次の値と 1 対 1 に対応する必要があります。テーブル内のすべてのフィールド。
  3. 複数のデータを同時に挿入できますが、値以降の値は区切る必要があります。

改訂

更新しました

UPDATE `grade` SET `gradename` = '大1' WHERE `gradeid` = 1;

-- 不指定条件的情况下,会改动表里的这个字段全部的值
UPDATE `grade` SET `gradename` = '大2';

-- 修改多个属性 逗号隔开
UPDATE `grade` SET `gradeid` = 11,`gradename` = '大11' WHERE `gradeid` = 1;

-- 语法
update 表名 set 字段(需要修改的哪个字段) =,.... where = 

条件: where 句の演算子 ID が特定の値に等しい、特定の値より大きい、特定の間隔内で変更された...

演算子はブール値を返します

オペレーター 意味 範囲 結果
= 等しい 5=6 間違い
<>または!= 等しくない 5<>6 真実
> 以上 5>4 真実
< 未満 5<6 真実
>= 以上 5>=4 真実
<= 以下 5<=6 真実
間…と… 2~5など一定の範囲内 [2,5]
そして 我和你&& 5>1 and 1>2 false
OR 我或你|| 5>1 or 1>2 true

语法:UPDATE 表名SET colnum_name=value,… WHERE [条件]

注意:

  • colnum_name是数据库的列,尽量带上
  • 条件,筛选的条件,如果没有指定,则会修改所有的列
  • value,是一个具体的值,也可以是一个变量
  • 多个设置的属性之间,使用英文逗号隔开

删除

delete 命令

语法:delete from 表名 [where 条件]

-- 删除数据(避免这样写,会全部删除)
DELETE FROM 数据库名;

-- 删除指定数据
DELETE FROM 数据库名 WHERE 条件;

truncate命令

作用:完全清空一个数据库表,表的结构和索引约束不会变!

-- 清空表
TRUNCATE 表名;

delete跟truncate区别

  • 相同点:都能删除数据,都不会删除表结构
  • 不同:
    • turncate 重新设置自增列 计数器会归零
    • turncate 不会影响事物

了解即可:delete删除问题,重启数据库现象

  • innoDB 自增列会从1开始(存在内存当中的,断电即失)
  • MylSAM 继续从上一个自增量开始(存在文件中,不会丢失)

DQL查询数据(最重点)

DQL (数据查询语言:)

  • 所有的查询操作都用它 Select
  • 简单的查询,复杂的查询它都能做
  • 数据库中最核心的语言,最重要的语句
  • 使用频率最高的语句

select 语法 [ ] 代表可选的 { } 代表必选的

select [all | distinct] -- 去重
{
   
   * | table.* | [table.field1[as alias1],[,table.field2[as alias2]][....]} -- 要查询的字段
from table_name [as table_alias] -- (from 表名  as取别名)
   [left | right | inner join table_name2] -- 联合查询 (... join 要连接的表  on 等值判断)
   [where ...]  -- 指定结果需满足的条件(具体的值,子查询语句)
   [group by ...] -- 指定结果按照哪几个字段来分组(通过哪个字段来进行分组)
   [having]  -- 过滤分组的记录必须满足的次要条件 (过滤分组后的信息,条件和where是一样的,就是上下位置不同)
   [order by ...]  -- 指定查询记录按一个或多个条件排序 (通过哪个字段排序)[升序/降序]
   [limit {
   
   [offset,]row_count | row_countOFFSET offset}]; -- 指定查询的记录从哪条至哪条 (起始下标值,页面有多少条记录)
               
-- 查询表中全部信息   
-- SELECT * FROM 表名;
SELECT * FROM `student`;

-- 查询指定字段 
-- SELECT 字段1,字段2... FROM 表名;
SELECT `StudentName`,`Address` FROM `student`;

-- 别名 给结果起一个别名 
-- SELECT 字段1 AS 别名,字段2 AS 别名 FROM 表名;
SELECT `StudentName` AS 姓名,`Address`AS 地区 FROM `student`;

-- 函数 concat(a,b)拼接
SELECT CONCAT('姓名:',StudentName) AS 名字 FROM `student`;

语法:select 字段,…from 表名

有的时候,列名字不是那么的见名知意。就起别名 AS 字段名 as 别名

去重复 distinct

作用:去除select查询出来的结果中重复的数据,重复的数据只显示一条

-- 发现重复数据,去重 
-- SELECT DISTINCT 字段名 FROM 表名;
SELECT DISTINCT `StudentNo` FROM `result`;

数据库的列(表达式)

-- 查询系统版本
SELECT VERSION();
-- 用来计算
SELECT 100*3-1 AS 计算结果
-- 查询自增的步长
SELECT @@auto_increment_increment;

where条件子句

作用:检索数据中符合条件的值

搜索的条件由一个或多个表达式组成!结果 布尔值

逻辑运算符
运算符 语法 描述
and && a and b 或 a&&b 逻辑与
or || a or b 或 a||b 逻辑或
Not ! not a 或 !a 逻辑非

语法:

and

select 字段名 from 表名 where 字段名=5 and 字段名=6;

or

select 字段名 from 表名 where 字段名=6 or 字段名=7;

not

select 字段名 from 表名 where not 字段名=5;

模糊查询 :比较运算符
运算符 语法 描述
is null a is null 如果操作符为null,结果为真
is not null a is not null 如果操作符不为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…其中的某一个值中,结果为真
-- Like结合 %(代表0到任意一个字符) _ (表示一个字符)
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE `SubjectName` LIKE '高%';

SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE `SubjectName` LIKE 'C#__';

SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectName LIKE '%数%';

-- in (具体的一个或多个值)
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectNo IN (3,5,2,13);

-- not null 相当于不为空
SELECT `SubjectNo`,`SubjectName` FROM`subject`
WHERE SubjectNo IS NOT NULL;

联表查询

JOIN 对比

思路是必看的,很有用

-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
SELECT * FROM `student`;
SELECT * FROM `result`;
/* 思路
1.分析需求,分析查询的字段来自哪张表,如果超过一张表就使用(连接查询)
2.确定使用哪种连接查询? 有7种
确定交叉点(这两个表中哪个数据是相同的)如果没有交叉点是查不了东西的
判断的条件就是, 学生表中 StudentNo = 成绩表中 StudentNo
就是学生表拥有StudentNo  成绩表也拥有 StudentNo 共同字段
*/

-- join(连接的表) on(判断的条件)  连接查询
-- where 等值查询

-- inner join 内连接--
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult -- 因为有两个同样的字段,所以需要表名区引用,要不然不知道是哪个表的字段
FROM student AS s
INNER JOIN result AS r   -- 定义了别名,就可以用别名区访问东西了,当然表名也可以,只是会稍微繁琐
WHERE s.StudentNo = r.StudentNo  -- 判两张表是否都有这个字段

-- right join 右连接查询--
SELECT student.StudentNo,StudentName,SubjectNo,StudentResult
FROM student 
RIGHT JOIN result   -- 这是不用别名,用表名的操作,比较繁琐
ON student.StudentNo = result.StudentNo 

-- left join 左连接查询--
SELECT s.StudentNo,StudentName,SubjectNo,StudentResult
FROM student s
LEFT JOIN result r   -- 别名的 AS 是可以省略的
ON s.StudentNo = r.StudentNo
操作 描述
inner join 并集 ,只要有一张表有这个数据就可以拿到,就是多表中有一个匹配就行了
left join 左连接,会从左表中返回所有的值,即使右表中没有匹配
right join 右连接,会从右表中返回所有的值,即使左表中没有匹配
-- (查询了参加考试同学的信息:学号,学生姓名,科目名,分数)  (StudentNo StudentName SubjectName StudentResult)
/* 思路
1.分析需求,分析查询的字段来自哪张表,如果超过一张表就使用(连接查询)  来自( student , result , subject )表
2.确定使用哪种连接查询? 有7种
确定交叉点(这两个表中哪个数据是相同的)如果没有交叉点是查不了东西的
*/
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult` 
FROM `student` AS s
RIGHT JOIN `result` AS r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` AS sub
ON r.`SubjectNo` = sub.`SubjectNo`


-- 步骤
/*
我要查询哪些数据 select ....
从哪几个表中查  frominner(right,left) join 连接的表 on 交叉条件 

假设存在多张表查询,先查询两张表然后再慢慢增加

自连接

自己的表和自己的表连接,核心:一张表拆成两张一样的表即可

-- ==========自连接==============

CREATE TABLE categorg (
	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)
)ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

INSERT INTO categorg(categoryid,pid,categoryName)
VALUES(2,1,'信息技术'),
(3,1,'软件开发'),
(4,3,'数据库'),
(5,1,'美术设计'),
(6,3,'web开发'),
(7,5,'ps技术'),
(8,2,'办公信息');
-- 查询父子信息
SELECT f.categoryName AS '父栏目',z.categoryName AS '子栏目'
FROM categorg AS f,categorg AS z
WHERE f.categoryid = z.pid  
-- 就相当于 categoryid的值 = pid的值
-- 比如 办公信息的2=信息技术的2 因为1不匹配 所以是单独的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KHFF2bTB-1597917601699)(C:\Users\黄潮旬\AppData\Roaming\Typora\typora-user-images\image-20200814100757157.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JoTsi5x5-1597917601702)(C:\Users\黄潮旬\AppData\Roaming\Typora\typora-user-images\image-20200814100827000.png)]

分页和排序

排序 语法:ORDER BY 排序的字段 ASC 或 DESC

-- order by排序:升序asc,降序desc
-- 语法 ORDER BY 排序的字段  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`
ORDER BY StudentResult ASC

分页 语法: limit 起始下标值,页面有多少条记录

-- 为什么要分页?
-- 为了缓解数据库压力,给人的体验更好,  还有一种不分页的叫做瀑布流

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`
ORDER BY StudentResult ASC
LIMIT 0,5  -- 语法  limit  起始下标值,页面有多少条记录

子查询

where (这个值是计算出来的)

使用子查询 (由里及外) 适用于,后面还加条件的

本质:在 where 语句中嵌套一个子查询语句

-- 查询高等数学的所有考试结果(学号 科目名称 成绩),降序查询
 -- 方式一: 使用连接查询
 SELECT `StudentNo`,SubjectName,StudentResult
 FROM `result` AS r
 INNER JOIN `subject` sub
 ON r.`SubjectNo` = sub.`SubjectNo`
 WHERE  SubjectName LIKE '高等数学%'
 ORDER BY StudentResult DESC
 
 
 -- 方式二:使用子查询 (由里及外)  适用于,后面还加条件的
 -- 查询所有考试结果(学号 科目名称 成绩)>70分的,
 SELECT `StudentNo`,SubjectName,StudentResult
 FROM `result` AS r
 INNER JOIN `subject` sub
 ON r.`SubjectNo` = sub.`SubjectNo`
 WHERE StudentResult>=70 
 -- 在基础上增加一个 且是高等数学的
 AND SubjectName = (
	SELECT SubjectName FROM `subject`
	WHERE SubjectName = '高等数学-1'
 )
  
 -- 改造方式二:查询学生学号,学生姓名  成绩大于70分的
 SELECT StudentNo,StudentName FROM student WHERE StudentNo IN (
	SELECT StudentNo FROM result WHERE StudentResult>70 AND SubjectNo =(
		SELECT SubjectNo FROM `subject` WHERE SubjectName = '高等数学-1'
	)
 )
 

分组和过滤

-- 查询不同课程的平均分,最高分,最低分,平均分大于90
-- 核心:根据不同的课程分组    不分组的话只有一个,按照最高的 最低的来排   因为每个课程都有最高分最低分
SELECT SubjectName,AVG(StudentResult)AS 平均分,MAX(StudentResult)AS 最大值,MIN(StudentResult)AS 最小值
FROM `result` AS r 
INNER JOIN `subject` AS sub
ON r.`SubjectNo` = sub.`SubjectNo`
GROUP BY r.SubjectNo  -- 指定结果按照哪几个字段来分组
HAVING 平均分>=80  -- 过滤分组的记录必须满足的次要条件

MySQL函数

官网:https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html

常用函数

-- 数学运算
SELECT ABS(-8)  -- abs 绝对值
SELECT CEILING(9.4)  -- ceiling 向上取整
SELECT FLOOR(9.4)  -- floor 向下取整
SELECT RAND()  -- rand 返回一个0~1之间的随机数
SELECT SIGN(7)  -- sign 判断一个数的符号 负数返回-1 正数返回1


-- 字符串函数
SELECT CHAR_LENGTH('dffhf附件四')  -- char_length 字符串长度
SELECT CONCAT('热','爱','编程')  -- concat 拼接字符串
SELECT INSERT('我热爱编程helloword',2,3,'我超级喜欢')  -- insert 查询 从某个位置开始 替换某个长度
SELECT LOWER('ASDDlele')  -- lower 小写字母
SELECT UPPER('asddLELE')  -- upper 大写字母
SELECT INSTR('abcdeh','h')  -- instr 返回第一次出现的字串的索引
SELECT REPLACE('坚持就一定能成功','坚持','努力')  -- replace 替换出现的指定字符串
SELECT SUBSTR('坚持就一定能成功',4,6)  -- substr 返回指定的子字符串 从哪里开始,到哪里结束
SELECT REVERSE('坚持就一定能成功')  -- reverse 反转

		-- 查询性李的  然后替换名字 利
		SELECT REPLACE(StudentName,'李','利') FROM student
		WHERE StudentName LIKE '李%'
 
 
-- 时间和日期函数(记住)
SELECT CURRENT_DATE()  -- current_date 获取当前日期
SELECT CURDATE()  -- curdate 获取当前日期
SELECT NOW()  -- now 获取当前的时间
SELECT LOCALTIME()  -- localtime 本地时间
SELECT SYSDATE()  -- sysdate 系统时间

SELECT YEAR(NOW())  -- year 年
SELECT MONTH(NOW())  -- month 月
SELECT DAY(NOW())  -- day 日
SELECT HOUR(NOW())  -- hour 时
SELECT MINUTE(NOW()) -- minute 分
SELECT SECOND(NOW())  -- second 秒
 

-- 系统
SELECT SYSTEM_USER() -- system_user 获取当前用户
SELECT USER()	-- user 获取当前用户
SELECT VERSION()  -- version 获取当前版本

聚合函数(常用)

函数名称 描述
count() 计数
sum() 求和
avg() 平均值
max() 最大值
min() 最小值
-- ========聚合函数========
-- 都能够统计表中的数据
SELECT COUNT(`StudentNo`)FROM student;  -- count(字段) 会忽略所有的null值
SELECT COUNT(*) FROM student  -- count(*) 不会忽略null值,本质 计算行数
SELECT COUNT(1) FROM student  -- count(1) 不会忽略所有的null值,本质 计算行数

SELECT SUM(StudentResult)AS 总和 FROM result; -- sum 总和
SELECT AVG(StudentResult)AS 平均分 FROM result; -- avg 平均分 
SELECT MAX(StudentResult)AS 最高分 FROM result; -- max 最大值
SELECT MIN(StudentResult)AS 最低分 FROM result; -- min 最小值

数据库级别的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`)
)

-- 明文密码
INSERT INTO `testmd5` VALUES(1,'zhangsan','123456'),(2,'lishi','123456'),(3,'wangwu','123456');
-- 加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE id = 1;
-- 加密全部的密码
UPDATE testmd5 SET pwd = MD5(pwd);
-- 插入的时候加密
INSERT INTO testmd5 VALUES(4,'xiaoming',MD5('123456')) ;
-- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值
SELECT * FROM testmd5 WHERE `name` = 'xiaoming' AND pwd = MD5('123456')

事物

什么是事物

要么都成功,要么都失败

将一组SQL放在一批次中去执行~

事物原则:DCID原则 原子性,一致性,隔离性,持久性 (脏读,幻读…)

原子性(atomicity)

要么都成功,要么都失败

一致性(consistency)

事物前后的数据完整性要保证一致

隔离性(isolation)

事物的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事物,不能被其他事务的操作数据所干扰,事物之间要相互隔离

持久性(durability)

事物一旦提交则不可逆,被持久化到数据库中

隔离所导致的一些问题

脏读

指一个事物读取了另外一个事务未提交的数据。

不可重复读

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

虚读(幻读)

是指在一个事务内读取到了别的事物插入的数据,导致前后读取不一致。

-- =============事物
-- mysql 是默认开启事务自动提交的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认的)

-- 手动处理事物
 SET autocommit = 0 -- 关闭自动提交
 -- 事物开启
 START TRANSACTION  -- 标记一个事务的开始,从这个之后的sql都在同一个事物内
 

  -- 提交:持久化(成功)
  COMMIT
  -- 回滚:回到原来的样子(失败)
  ROLLBACK
  
  -- 事务结束
  SET autocommit = 1 -- 开启自动提交

-- 了解
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点


模拟场景

-- 转账例子
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop

CREATE 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=utf8

INSERT INTO `account`(`name`,`money`)
VALUES('A',2000.00),('B',10000.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;  -- 恢复默认值,开启自动提交

索引

mysql官方对索引的定义为:**索引(index)是帮助mysql高效获取数据的数据结构。

提取句子主干,就可以得到索引的本质:索引是数据结构

索引的分类

在一个表中,主键索引只能有一个,唯一索引可以有多个

  • 主键索引(primary key)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引(unique key)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
  • 常规索引(key)
    • 默认的,index、key关键字来设置
  • 全文索引(FullText)
    • 在特定的数据库引擎下才有,MyISAM
    • 快速定位数据 没加索引就是遍历,加了索引就是定位
-- 索引的使用
 -- 1. 在创建表的时候给字段增加索引
 -- 2. 创建完毕后,增加索引
-- 显示所有的索引信息 SHOW INDEX FROM 表名
SHOW INDEX FROM student
 
-- 增加一个全文索引(索引名) 列名
ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `StudentName`(`StudentName`);

-- explain 分析sql执行的状况
EXPLAIN SELECT * FROM student;  -- 非全文索引

EXPLAIN SELECT * FROM student WHERE MATCH(studentName)AGAINST('李')

测试索引

 
CREATE TABLE `app_user` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT '' COMMENT '用户名称',
  `email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
  `phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
  `gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男 1:女)',
  `password` VARCHAR(100) NOT NULL COMMENT '密码',
  `age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'

SHOW CREATE DATABASE `school`
SHOW  TABLES;

-- 插入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`)
	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;

SELECT mock_data();

SELECT * FROM app_user WHERE `name` = '用户500000'; -- 没创建索引之前执行6秒

-- id_表名_字段名
-- create index 索引名 no 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
SELECT * FROM app_user WHERE `id` = 500000; -- 创建索引之后执行0.007秒

索引在小数据量的时候,用处不大,但是在大数据的时候,区别十分明显

索引原则

  • 索引不是越多越好
  • 不要对进程变动数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询的字段上

索引的数据结构

Hash类型的索引

Btree:InnoDB的默认数据结构

阅读:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

权限管理和数据库备份

用户管理

SQL命令操作

用户表:mysql.user

本质:读这张表进行增删改查

-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码';
CREATE USER xun IDENTIFIED BY '123456';

-- 修改密码 (修改当前用户密码)
SET PASSWORD = PASSWORD('111111');

-- 修改密码(修改指定用户密码)
SET PASSWORD FOR xun = PASSWORD('111111');

-- 重命名 RENAME USER 原来名字 TO 新的名字;
RENAME USER xun TO xun2;

-- 用户授权 ALL PRIVILEGES 全部的权限 ,库.表
-- ALL PRIVILEGES 除了给别人权限,其他的都能干
GRANT ALL PRIVILEGES ON *.* TO xun2

-- 查询权限
SHOW GRANTS FOR xun2;  -- 查看指定用户的权限
SHOW GRANTS FOR root@localhost

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM xun2

-- 删除用户
DROP USER xun2

Mysql备份

为什么要备份:

  • 保证重要的数据不丢失
  • 数据转移

MySQL数据库备份方式

  • 直接拷贝物理文件 data文件夹
  • 在Sqlyog可视化工具手动导出
    • 在想要导出的表过着库中,右键选择备份 然后选择SQL转储
  • 使用命令行导出 mysqldump 命令行使用
# mysqldump -h主机 -u用户名 -p密码 数据库 表名 > 物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 shop account >E:/aa.sql

# 导出多个表
# mysqldump -h主机 -u用户名 -p密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名

# 导出数据库
mysqldump -h主机 -u用户名 -p密码 数据库 > 物理磁盘位置/文件名

#导入
#登录的情况下,切换到指定的数据库
# source 备份文件
source e:aa.sql

# 或
mysql -u用户名 -p密码 库名<备份文件

规范数据库设计

为什么需要设计

当数据库比较复杂的时候,我们就需要设计了

糟糕的数据库设计:

  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦,异常【屏蔽使用物理外键】
  • 程序的性能差

良好的数据库设计:

  • 节省内存空间
  • 保证数据库的完整性
  • 方便我们开发系统

软件开发中,关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求

  • 概要设计:设计关系图E-R图

设计数据库步骤:(个人博客)

  • 手机信息,分析需求
    • 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表
    • 友链表(友链信息)
    • 自定义表(系统信息,某个关键的字,或者一些主字段) key:value
  • 标识实体(把需求落地到每个字段)
  • 标识实体之间的关系
    • 写博客:user -> blog
    • 创建分类:user->category
    • 关注:user->user
    • 友链:links
    • 评论:user-user-blog

三大规范

为什么需要数据规范化

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正常显示信息
  • 删除异常
    • 丢失有效的信息

三大范式

第一范式(1NF)

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

第二范式(2NF)

前提:满足第一范式

每张表只描述一件事情

第三范式(3NF)

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

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关

(规范数据库的设计)

规范性 和 性能的问题

关联查询的表不得超过三张表

  • 考虑商业化的的需求和目标,(成本,用户体验!)数据库的性能更加重要
  • 在规范性能的问题的时候,需要适当的考虑一下 规范性!
  • 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
  • 故意增加一些计算列(从大数据量降低为小数据量的查询 :索引)

JDBC(重点)

数据库驱动

驱动:声卡、显卡、数据库 都是需要驱动才能运行的

应用程序 会先连接数据库的驱动 后 再从驱动连接数据库 而不是能直接连接数据库

JDBC

SUN公司为了简化开发人员的(对数据库的统一) 操作,提供了一个(Java操作数据库的)规范,俗称JDBC

这些规范的实现由具体的厂商去做

对于开发人员来说,我们只需要掌握JDBC接口的操作即可!

需要导入 java.sql javax.sql 还需要导入一个数据库驱动包 mysql-connector-java-5.1.47.jar

第一个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(60),
  `email` VARCHAR(60),
  `birthday` DATE
  );
  
 INSERT INTO users(id,`name`,`password`,email,birthday) 
 VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lishi','123456','[email protected]','1985-12-04'),
(3,'wangwu','123456','[email protected]','1981-12-04');
  1. 创建一个项目

  2. 导入数据库驱动,自己下载jar包导入也行 用maven导入也行(推荐) mysql-connector-java-5.1.47.jar

  3. 编写测试代码

    package com.kuang.jdbc01;
    
    import java.sql.*;
    
    // 第一个JDBC程序
    public class test01 {
          
          
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
          
          
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
    
            //2.用户信息和url
            //"jdbc:mysql://localhost:3306/数据库名?支持中文编码&设置中文字符集=utf8&use使用安全的一个连接";
            String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
            //用户名
            String username = "root";
            //密码
            String password = "123456";
    
            //3.连接成功  后,会返回 数据库对象
            //驱动管理DriverManager  获得连接getConnection   代表数据库connection
            Connection connection = DriverManager.getConnection(url, username, password);
    
            //4.执行SQL的对象     用statement执行sql对象
            Statement statement = connection.createStatement();
    
            //5.执行SQL对象 去 执行SQL, 可能存在结果,查看返回结果
            String sql = "SELECT * FROM users";
            // 查询 sql
            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"));
                System.out.println("============================");
            }
            //6.释放连接
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    

    步骤总结: 只有查询才有结果集

    1. 加载驱动 Class.forName()
    2. 连接数据库 DriverManager
    3. 获得执行sql的对象 Statement
    4. 获得返回的结果集
    5. 释放连接

    DriverManager

     // DriverManager.registerDriver(new com.mysql.jdbc.Driver());
     Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
    
     // connection 代表数据库
    //数据库设计自动提交
    //事务提交
    //事物回滚
            connection.rollback();
            connection.commit();
            connection.setAutoCommit();
    

    URL

    String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
    //mysql  -- 3306
    // sTRING URL = 协议://主机地址+端口号/数据库名?参数1&参数2&参数3
    
    // oralce --1521
    // jdbc:oracle:thin:@localhost:1521:sid
    

    Statement执行SQL的对象

    String sql = "SELECT * FROM users"; //编写SQL
    
    statement.executeQuery();  //查询操作 返回ResultSet(结果集)
    statement.execute();        //执行任何sql
    statement.executeUpdate();  //更新、插入、删除、都使用这个,返回一个受影响的行数
    

    ResultSet 查询的结果集:封装了所有的查询结果

    获得指定的数据类型

            resultSet.getObject();// 在不知道列类型的情况下使用
            //如果知道列的类型就使用指定的类型
            resultSet.getString();
            resultSet.getInt();
            resultSet.getFloat();
            resultSet.getTime();
    		...
    

    遍历,指针

            resultSet.beforeFirst();//移动到最前面
            resultSet.afterLast();//移动到最后面
            resultSet.next();//移动到下一个数据
            resultSet.previous();//移动到下一行
            resultSet.absolute(row);//指定到移动行
    

    释放资源

    resultSet.close();
    statement.close();
    connection.close();
    //耗资源 ,用完关掉
    

statement对象

jdbc中的 statement 对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可

Statement 对象的 executeUpdate 方法,用于向数据库发送增、删、改的sql语句,executeUpdate 执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。

Statement.executeQuery 方法用于向数据库发送查询语句,executeQuery 方法返回代表查询结果的ResultSet对象

CRUD操作-create

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

Statement statement = connection.createStatement();
String sql = "insert into users(...)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 users where id=1";
int sum = statement.executeUpdate(sql);
if(sum>0){
    
    
    System.out.println("删除成功!!!");
}

CRUD操作-update

使用executeUpdate(String sql)方法完成数据修改操作,示例操作:

Statement statement = connection.createStatement();
String sql = "update users set name = '' where name = ''";
int sum = statement.executeUpdate(sql);
if(sum>0){
    
    
    System.out.println("修改成功");
}

CRUD操作-read

使用 executeQuery(String sql)方法完成数据查询操作,实例操作:

Statement statement = connection.createStatement();
String sql = "select * from users where id=1";
ResultSet rs = statement.executeQuery(sql);
while(rs.next()){
    
    
    //根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
代码实现

1、创建配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

2、提取工具类

package com.kuang.jdbc02.utils;

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{
    
         //反射获取类的装载器,然后在获取资源(db.properties)
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            //属性
            Properties properties = new Properties();
            //加载获取到的属性
            properties.load(in);
//            从文件把这4个信息读取出来
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //1.驱动只用加载一次
            Class.forName(driver);
        }catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
    
    
        return  DriverManager.getConnection(url, username, password);
    }
    //释放资源
    public static void release(Connection conn, Statement sta, ResultSet res) throws SQLException {
    
    
        if (res!=null){
    
    
            res.close();
        }
        if (sta!=null){
    
    
            sta.close();
        }
        if (conn!=null){
    
    
            conn.close();
        }
    }
}

3、编写增删改

增 insert

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestInsert {
    
    

    public static void main(String[] args) throws SQLException {
    
    

            Connection connection = JdbcUtils.getConnection(); //通过工具类获取链接

            Statement statement = connection.createStatement();//获得SQL的执行对象
            String sql = "INSERT INTO users(id,`name`,`password`,`email`,`birthday`) VALUES(5,'fenqi','123456','[email protected]','1985-12-04')";
            int i = statement.executeUpdate(sql);
            if (i>0){
    
    
                System.out.println("插入成功");
            }
            JdbcUtils.release(null,null,null); //释放资源
    }
}


删 Delete

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select  * from users";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);

        while(resultSet.next()){
    
    
            System.out.println("id"+resultSet.getInt("id"));
            System.out.println("name"+resultSet.getString("name"));
            System.out.println("password"+resultSet.getString("password"));
            System.out.println("email"+resultSet.getString("email"));
            System.out.println("birthday"+resultSet.getDate("birthday"));
            System.out.println("=================");
        }
        JdbcUtils.release(null,null,null);
    }
}

改 Update

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestUpdate {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "update users set name='xiugai' where id = 1";
        //执行
        int i = statement.executeUpdate(sql);

        if (i>0){
    
    
            System.out.println("更新成功");
        }
        JdbcUtils.release(null,null,null);
    }
}

查 Select

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select  * from users";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);

        while(resultSet.next()){
    
    
            System.out.println("id"+resultSet.getInt("id"));
            System.out.println("name"+resultSet.getString("name"));
            System.out.println("password"+resultSet.getString("password"));
            System.out.println("email"+resultSet.getString("email"));
            System.out.println("birthday"+resultSet.getDate("birthday"));
            System.out.println("=================");
        }
        JdbcUtils.release(null,null,null);
    }
}

sql注入问题

sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接or

package com.kuang.jdbc02;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class SQL注入 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //正常登录
        // login("lishi","123456");
        login(" 'or' 1=1"," 'or' 1=1");

    }
    public static void login(String username,String password) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //获得SQL的执行对象
        Statement statement = connection.createStatement();
        //编写SQL语句
        String sql = "select * from users where `name` = '"+username+"' and password='"+password+"'";
        //执行
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
    
    
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
            System.out.println("======================");
        }
    }
}

PreparedStatement对象

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

1、新增

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestInsert {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //调用工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //使用? 占位符代表参数
        String sql = "insert into users(id,name,password,email,birthday)values(?,?,?,?,?)";
        //预编译SQL,先写sql,然后不执行
        PreparedStatement pr = connection.prepareStatement(sql);
        //手动给参数赋值
        pr.setInt(1,5); //第一个值为参数下标,第二个为参数 id
        pr.setString(2,"王胜");
        pr.setString(3,"123456");
        pr.setString(4,"[email protected]");
        // 注意点:sql.Date     数据库 java.sql.Date()
        //       util.Date     Java   new Date().getTime() 获得时间戳
        pr.setDate(5,new java.sql.Date(new Date().getTime()));

        //执行
        int i = pr.executeUpdate();

        if (i>0){
    
    
            System.out.println("插入成功");
        }
        JdbcUtils.release(null,null,null);
    }
}

2、删除

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestDelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?   代表参数
        String sql = "delete from users where id = ?";
        //预编译SQL  先写sql 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动给参数赋值
        pre.setInt(1,5);
        //执行
        int i = pre.executeUpdate();

        if (i>0){
    
    
            System.out.println("删除成功");
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

3、更新

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestUpdate {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?  代表参数
        String sql = "update users set name = ? where  name = ?";
        //预编译SQL  先写SQL 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动给参数赋值
        pre.setString(1,"zhangsan");
        pre.setString(2,"xiugai");
        //执行
        int i = pre.executeUpdate();

        if (i>0){
    
    
            System.out.println("修改成功");
        }
        //关闭资源
        JdbcUtils.release(null,null,null);
    }
}

4、查询

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

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

public class TestSelete {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //通过工具类获取数据库的连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符?  代表参数
        String sql = "select * from users where id=?";
        //预编译SQL  先写sql  然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动传递参数
        pre.setObject(1,2);
        //执行
        ResultSet resultSet = pre.executeQuery();

        while (resultSet.next()){
    
    
            System.out.println(resultSet.getInt("id"));
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

5、防止Sql注入

package com.kuang.jdbc03;

import com.kuang.jdbc02.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //正常登录
        // login("lishi","123456");
        login("'' or 1=1","123456");

    }
    public static void login(String username,String password) throws SQLException {
    
    
        //通过工具类获取数据库连接
        Connection connection = JdbcUtils.getConnection();
        //使用占位符? 传递参数
        //PreparedStatement放置SQL注入的本质,把值传递进来的参数当作字符
        //假设其中存在转义字符,比如说 ‘ 会被直接转义
        String sql = "select * from users where name = ? and password = ?";
        //预编译Sql  先写sql 然后不执行
        PreparedStatement pre = connection.prepareStatement(sql);
        //手动传递参数
        pre.setString(1,username);
        pre.setString(2,password);
        //执行
        ResultSet resultSet = pre.executeQuery();

        while(resultSet.next()){
    
    
            System.out.println(resultSet.getString("name"));
            System.out.println(resultSet.getString("password"));
            System.out.println("======================");
        }
        //释放资源
        JdbcUtils.release(null,null,null);
    }
}

idea连接数据库

  1. 找到右侧的Database 点击进去

  2. 点击 + 号 → 选择Data Source →选择MySql

  3. 然后输入用户名 和 密码 → 点击 Test Connection

    • 成功的话会显示✔

      • 然后 点击Apply →点击上面一点的Schemas → 然后选择要添加的数据库就可以了
    • 不成功的话,要么是时区异常要么就是版本没选好

      • 左侧NySQL点击进去

      • Class选择 com.musql.jdbc.Driver

      • Driver files 选择你对应的SQL版本 → 然后就可以点击Apply → 然后就去重新输入账号密码连接

      • 时区的话就需要打开命令行的sql然后设计时区了

        • -- 查看时区,显示 SYSTEM 就是没有设置时区啦。
          show variables like'%time_zone';
          
        • --设置时区 设置完需要重新连接sql重新查看
          set global time_zone = '+8:00';
          

事物

要么都成功,要么都失败

ACID原则

原子性:

​ 要么全部完成,要么都不完成

一致性:

​ 总数不变

隔离性:

​ 多个进程互不干扰

持久性:

​ 一旦提交不可逆,持久化到数据库

隔离性问题:

脏读:一个事务读取了另一个没有提交的事物

不可重复读:在同一个事物内,重复读取表中的数据,表数据发生了改变

虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致

代码实现

​ 1、开启事务 conn.setAutoCommit(false);

​ 2、一组业务执行完毕,提交事务

​ 3、可以在catch语句中显示的定义 回滚语句,但默认失败就会回滚

package com.kuang.jdbc04;

import com.kuang.jdbc02.utils.JdbcUtils;
import com.sun.org.apache.xpath.internal.objects.XNull;

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

public class TestTransation1 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
         Connection conn = null;
        PreparedStatement st = null;
        try {
    
    
            //通过工具类连接数据库
             conn = JdbcUtils.getConnection();
            //关闭数据库的自动提交,会自动开启事物
            conn.setAutoCommit(false);

            //编写SQL语句
            String sql1 = "update account set miney = miney-100 where name = 'A'";
            //预编译SQL
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            //编写SQL语句
            String sql2 = "update account set miney = miney+100 where name = 'B'";
            //预编译SQL
            st= conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("成功");
        }catch (Exception e){
    
    
            try{
    
    
                conn.rollback(); //如果失败则回滚事物
            } catch (SQLException throwables)
            {
    
    
                throwables.printStackTrace();
            }
            e.printStackTrace();
        }finally {
    
    
            //释放资源
            JdbcUtils.release(conn,st,null);
        }

    }
}

数据库连接池

数据库连接 - 执行完毕 - 释放

连接-释放 十分浪费系统资源

池化技术:准备一些预先的资源,过来就连接预先准备好的

例子(银行)

比如去银行办理业务,开门-办理-关门 下一个 开门-办理-关门, 这是平常数据库的操作,很繁琐麻烦

使用连接池 开门-安排业务员-等待-办理-不使用了就彻底关门

常用连接数10个

最小连接数:10(按照常用连接数设计最小连接数)

最大连接数:(业务最高承载上线,超过了就需要等待排队)

等待超时:(超过等待的时间就不等了)

编写连接池,只需要实现一个接口 DataSource

开源数据源实现(拿来即用)

​ DBCP

​ C3P0

​ Druid:阿里巴巴

使用了这些数据库连接池之后我们在项目开发中就不需要编写连接数据库的代码了!

DBCP

​ 需要用到的jar包

​ commons-dbcp-1.4、commons-pool-1.6

C3P0

需要用到的jar包

c3p0-0.9.5.5、mchange-commons-java-0.2.19

结论

どのようなデータソースを使用しても本質は同じであり、DataSource インターフェースやメソッドは変わりません。

おすすめ

転載: blog.csdn.net/qq_45316925/article/details/108129300