亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

數據庫MYSQL學習系列二

發布時間:2020-07-12 19:59:57 來源:網絡 閱讀:2111 作者:輕狂書生999 欄目:MySQL數據庫

                        數據庫MYSQL學習系列二

一.MYSQL數據庫對象與應用

2.1-MySQL數據類型

Number不止一種

· ×××

· 浮點型

×××

· INT

· SMALLINT

· MEDIUMINT

· BIGINT

type

Storage

Minumun Value

Maximum Value


(Bytes)

(Signed/Unsigned)

(Signed/Unsigned)

TINYINT

1

-128

127



0

255

SMALLINT

2

-32768

32767



0

65535

MEDIUMINT

3

-8388608

8388607



0

16777215

INT

4

-2147483648

2147483647



0

4294967295

BIGINT

8

-9223372036854775808

9223372036854775807



0

18446744073709551615

老生常談的問題

int(11) VS int(21) 存儲空間,還是存儲范圍有區別?

答案是:兩者完全一樣,只是在顯示的時候補全0的位數不一樣。

可以通過下面的例子來驗證:

create table t(a int(11) zerofill, b int(21) zerofill);insert into t values (1, 1);select * from t;

MySQL默認是不帶0補全的。

只是在一些特殊情況下兩者顯示有區別,其本質完全一樣。

浮點型

· FLOAT(M, D)

· DOUBLE(M, D)

屬性

存儲空間

精度

精確性

Float

4 bytes

單精度

非精確

Double

8 bytes

雙精度

比Float精度高

精度丟失問題

· 精度丟失

一個例子:

create table t(a int(11), b float(7, 4));insert into t values (2, 123.12345);select * from t;

定點數-更精確的數字類型

· DECIMAL

高精度的數據類型,常用來存儲交易相關的數據

DECIMAL(M,N).M代表總精度,N代表小數點右側的位數(標度)

1 < M < 254, 0 < N < 60;

存儲空間變長

性別、省份信息

一般使用tinyint、char(1)、enum類型。

經驗之談

· 存儲性別、省份、類型等分類信息時選擇TINYINT或者ENUM

· BIGINT存儲空間更大,INT和BIGINT之間通常選擇BIGINT

· 交易等高精度數據選擇使用DECIMAL

存儲用戶名的屬性

· CHAR

· VARCHAR

· TEXT

CAHR與VARCHAR

· CHAR和VARCHAR存儲的單位都是字符

· CHAR存儲定長,容易造成空間的浪費

· VARCHAR存儲變長,節省存儲空間

字符與字節的區別

編碼\輸入字符串

網易

netease

gbk(雙字節)

varchar(2)/4 bytes

varchar(7)/7 bytes

utf8(三字節)

varchar(2)/6 bytes

varchar(7)/7 bytes

utf8mb4(四字節)

varchar(2) ?

varchar(7)/7 bytes

對于utf8mb4號稱占用四字節但是并不絕對。如果在utf8可以覆蓋到的范圍則仍然占用3字節。

utf8mb4最有優勢的應用場景是用于存儲emoji表情

emoji表情

· MySQL版本 > 5.5.3

· JDBC驅動版本 > 5.1.13

· 庫和表的編碼設為utf8mb4

TEXT與CHAR和VARCHAR的區別

· CHAR和VARCHAR存儲單位為字符

· TEXT存儲單位為字節,總大小為65535字節,約為64KB

· CHAR數據類型最大為255字符

· VARCHAR數據類型為變長存儲,可以超過255個字符

· TEXT在MySQL內部大多存儲格式為溢出頁,效率不如CHAR

一個例子:

create table t (a char(256));create table t (a varchar(256));

存儲頭像

· BLOB

· BINARY

性能太差,不推薦

經驗之談

· CHAR與VARCHAR定義的長度是字符長度不是字節長度

· 存儲字符串推薦使用VARCHAR(N),N盡量小

· 雖然數據庫可以存儲二進制數據,但是性能低下,不要使用數據庫存儲文件音頻等二進制數據

存儲生日信息

· DATE

· TIME

· DATETIME

· TIMESTAMP

· BIGINT

時間類型的區別在哪里

· 

存儲空間上的區別

· 

DATE三字節,如:2015-05-01

TIME三字節,如:11:12:00

TIMESTAMP,如:2015-05-01 11::12:00

DATETIME八字節,如:2015-05-01 11::12:00

· 

存儲精度的區別

· 

DATE精確到年月日

TIME精確到小時分鐘和秒

TIMESTAMP、DATETIME都包含上述兩者

TIMESTAMP VS DATETIME

· 存儲范圍的區別

TIMESTAMP存儲范圍:1970-01-01 00::00:01 to 2038-01-19 03:14:07

DATETIME的存儲范圍:1000-01-01 00:00:00 to 9999-12-31 23:59:59

MySQL在5.6.4版本之后,TimeStamp和DateTime支持到微妙

· 字段類型與市區的關聯關系

TIMESTAMP會根據系統時區進行轉換,DATETIME則不會

字段類型和時區的關系

· 國際化的系統

一個例子:

create table test (a datetime, b timestamp);select now();insert into test values (now(), now());select * from test;set time_zone = '+00:00';select * from test;

BIGINT如何存儲時間類型

· 應用程序將時間轉換為數字類型

2.2-MySQL數據對象

MySQL常見的數據對象有哪些

· DataBase/Schema

· Table

· Index

· View/Trigger/Function/Procedure

庫、表、行層級關系

· 一個DataBase對應一個Schema

· 一個Schema包含一個或多個表

· 一個表里面包含一個或多個字段

· 一個表里包含一條或多條記錄

· 一個表包含一個或多個索引

DataBase用途

· 業務隔離

· 資源隔離

表上有哪些常用的數據對象

· 索引

· 約束

· 視圖、觸發器、函數、存儲過程

什么是數據庫索引

· 讀書的時候如何快速定位某一章節

查找書籍目錄

在自己喜歡的章節加書簽,直接定位

· 索引就是數據庫中的數據的目錄(索引和數據是分開存儲的)

索引和數據是兩個對象

索引主要是用來提高數據庫的查詢效率

數據庫中數據變更同樣需要同步索引數據的變更

如何創建索引(一)

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name

  [index_type]

  ON tbl_name (index_col_name,...)

  [index_option]

  [algorithm_option | lock_option] ...

 

index_col_name:

  col_name [(length)] [ASC | DESC]

 

index_type:

  USING {BTREE | HASH}

如何創建索引(二)

ALTER [IGNORE] TABLE tbl_name

  [alter_specification [, alter_specification] ...]

  [partition_options]

 

alter_specification:

    table_options

  | ADD [COLUMN] col_name column_definition

        [FIRST | AFTER col_name]

    ADD [COLUMN] (col_name column_definition,...)

    ADD {INDEX|KEY} [index_name]

        [index_type] (index_col_name,...) [index_option] ...

  | ADD [CONSTRAINT [symbol]] PRIMARY KEY

        [index_type] (index_col_name,...) [index_option] ...

  | ADD [CONSTRAINT [symbol]]

        UNIQUE [INDEX|KEY] [index_name]

約束

· 生活中的約束有哪些

每個人的指紋信息必須唯一

每個人的×××要求唯一

網上購物需要先登錄才能下單

· 唯一約束

對一張表的某個字段或者某幾個字段設置唯一鍵約束,保證在這個表里對應的數據必須唯一,如:用戶ID、手機號、×××等。

創建唯一約束

· 唯一約束是一種特殊的索引

· 唯一約束可以是一個或者多個字段

· 唯一約束可以在創建表的時候建好,也可以后面再補上

· 主鍵也是一種唯一約束

唯一約束

以如下這張表為例

CREATE TABLE `order` (

  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `orderid` int(10) unsigned NOT NULL,

  `bookid` int(10) unsigned NOT NULL DEFAULT '0',

  `userid` int(10) unsigned NOT NULL DEFAULT '0',

  `number` tinyint(3) unsigned NOT NULL DEFAULT '0',

  `address` varchar(128) NOT NULL DEFAULT '',

  `postcode` varchar(128) NOT NULL DEFAULT '',

  `orderdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',

  `status` tinyint(3) unsigned zerofill DEFAULT '000',

  PRIMARY KEY (`id`),

  UNIQUE KEY `idx_orderid` (`orderid`),

  UNIQUE KEY `idx_uid_orderid` (`userid`, `orderid`),

  KEY `bookid` (`bookid`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

· 索引有哪些

主鍵索引 ID

單鍵索引 orderid

單鍵索引 bookid

組合索引 (userid + orderid)

· 唯一約束有哪些

主鍵約束 (ID)

單鍵唯一索引 (orderid)

組合唯一索引 (userid + orderid)

添加唯一約束

· 添加主鍵

alter table `order` add primary key (id);

· 添加唯一索引

alter table `order` add unique key idx_uk_orderid (orderid);

外鍵約束

· 外鍵指兩張表的數據通過某種條件關聯起來

創建外鍵約束

· 將用戶表和訂單表通過外鍵關聯起來

alter table `order` add CONSTRAINT constraint_uid FOREIGN KEY (userid) REFERENCES user(userid);

· 使用外鍵的注意事項

必須是INNODB表,Myisam和其他引擎不支持外鍵

相互約束的字段類型必須要求一樣

主表的約束字段要求有索引

約束名稱必須要唯一,即使不在一張表上

View

· 產品需求

假如有其他部門的同事想查詢我們數據庫里的數據,但是我們并不想暴露表結構,并且只提供給他們部分數據

View的作用

· 視圖將一組查詢語句構成的結果集,是一種虛擬結構,并不是實際數據

· 視圖能簡化數據庫的訪問,能夠將多個查詢語句結構化為一個虛擬結構

· 視圖可以隱藏數據庫后端表結構,提高數據庫安全性

· 視圖也是一種權限管理,只對用戶提供部分數據

創建View

· 創建已完成訂單的視圖

create view order_view as select * from `order` where status=1;

Trigger

· 產品需求

隨著客戶個人等級的提升, 系統需要自動更新用戶的積分,其中一共有兩張表,分別為:用戶信息表和積分表

· Trigger俗稱觸發器,指可以在數據寫入表A之前或者之后可以做一些其他動作

· 使用Trigger在每次更新用戶表的時候出發更新積分表

除此之外還有哪些

· Function

· Procedure

2.3-MySQL權限管理

連接MySQL的必要條件

· 網絡要通暢

· 用戶名和密碼要正確

· 數據庫需要加IP白名單

· 更細粒度的驗證(庫、表、列權限類型等等)

數據有哪些權限

show privileges命令可以查看全部權限

權限粒度

· Data Privileges

DATA: SELECT, INSERT, UPDATE, DELETE

· Definition Privileges

DataBase: CREATE, ALTER, DROP

Table: CREATE, ALTER, DROP

VIEW/FUNCTION/TRIGGER/PROCEDURE: CREATE, ALTER, DROP

· Administrator Privileges

Shutdown DataBase

Replication Slave

Replication Client

File Privilege

MySQL賦權操作

GRANT

  priv_type [(column_list)]

    [, priv_type [column_list]] ...

  ON [object_type] priv_level

  TO user_specification [, user_specification] ...

  [REQUIRE {NONE | ssl_option [[AND] ssl_option] ...}]

  [WITH with_option ...]GRANT PROXY ON user_specification

  TO user_specification [, user_specification] ...

  [WITH GRANT OPTION]

如何新建一個用戶并賦權

· 使用MySQL自帶的命令

CREATE USER 'netease'@'localhost' IDENTIFIED BY 'netease163';

GRANT SELECT ON *.* TO 'netease'@'localhost' WITH GRANT OPTION;

其他方法

· 更改數據庫記錄

首先向User表里面插入一條記錄,根據自己的需要選擇是否向db和table_pirv表插入記錄

執行flush privileges命令,讓權限信息生效

更簡單的辦法

· GRANT語句會判斷是否存在該用戶,如果不存在則新建

GRANT SELECT ON *.* TO 'NETEASE'@'localhost' IDENTIFIED BY 'netease163' WITH GRANT OPTION;

查看用戶的權限信息

· 查看當前用戶的權限

show grants;

· 查看其它用戶的權限

show grants for netease@'localhost';

如何更改用戶的權限

· 回收不需要的權限

revoke select on *.* from netease@'localhost';

· 重新賦權

grant insert on *.* to netease@'localhost';

如何更改用戶密碼

· 用新密碼,grant語句重新授權

· 更改數據庫記錄,Update User表的Password字段

注意:用這種辦法,更改完需要flush privileges刷新權限信息,不推薦

刪除用戶

DROP USER user [, user] ...

With Grant Option

· 允許被授予權利的人把這個權利授予其他的人

MySQL權限信息存儲結構

· MySQL權限信息是存在數據庫表中

· MySQL賬號對應的密碼也加密存儲在數據庫表中

· 每一種權限類型在元數據里都是枚舉類型,表明是否有該權限

有哪些權限相關的表

· user

· db

· table_pirv

· columns_pirv

· host

權限驗證流程

查詢時從user->db->table_pirv->columns_pirv依次驗證,如果通過則執行查詢。

小結

· MySQL權限信息都是以數據記錄的形式存儲在數據庫的表中。

· MySQL的權限驗證相比網站登錄多了白名單環節,并且粒度更細,可以精確到表和字段。

MySQL權限上有哪些問題

· 使用Binary二進制安裝管理用戶沒有設置密碼

· MySQL默認的test庫不受權限控制,存在安全風險

mysql_secure_installation

· You can set a Password for root accounts.

· You can remove root accounts that are accessible from outside the localhost.

· You can remove anonymous-user accounts.

· You can remove the test database.

小結

· 權限相關的操作不要直接操作表,統一使用MySQL命令。

· 使用二進制安裝MySQL安裝后,需要重置管理用戶(root)的密碼。

· 線上數據庫不要留test庫

實踐課:數據庫對象

何為表結構設計

· 表結構設計需要在正式進行開發之前完成

· 根據產品需求將復雜的業務模型抽象出來

設計表的時候需要注意哪些

· 理解各個表的依賴關系

· 理解各個表的功能特點

字段之間的約束、索引

字段類型、字段長度

收集表屬性

· 昵稱

· 生日

· 性別

· 手機號碼

· 住宅號碼

· 郵編

· 住宅地址

· 注冊地址

· 登錄IP

· 上一次登錄時間

· 郵件地址

理解表的功能特點——數據用途

create table tb_account(

  account_id int not null auto_increment primary key,

  nick_name varchar(20),

  true_name varchar(20),

  sex char(1),

  mail_address varchar(50),

  phone1 varchar(20) not null,

  phone2 varchar(20),

  password varchar(30) not null,

  create_time datetime,

  account_state tinyint,

  last_login_time datetime,

  last_login_ip varchar(20)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

create table tb_goods(

  good_id bigint not null auto_increment primary key,

  goods_name varchar(100) not null,

  pic_url varchar(500) not null,

  store_quantity int not null,

  goods_note varchar(4096),

  producer varchar(500),

  category_id int not null

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

create table tb_goods_category(

  category_id int not null auto_increment primary key,

  category_level smallint not null,

  category_name varchar(500),

  upper_category_id int not null

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

create table tb_order(

  order_id bigint not null auto_increment primary key,

  account_id int not null,

  create_time datetime,

  order_amount decimal(12,2),

  order_state tinyint,

  update_time datetime,

  order_ip varchar(20),

  pay_method varchar(20),

  user_notes varchar(500)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

create table tb_order_item(

  order_item_id bigint not null auto_increment primary key,

  order_id bigint not null,

  goods_id bigint not null,

  goods_quantity int not null,

  goods_amount decimal(12,2),

  uique key uk_order_goods(order_id, goods_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

數據類型——命名規范

· 所有表名,字段名全部使用小寫字母

· 不同業務,表名使用不同前綴區分。

· 生成環境表名字段名要有實際意義

· 單個字段盡量使用字段全名;多個字段之間用下劃線分隔

字段設計規范

· 字段類型選擇,盡量選擇能滿足應用要求的最小數據類型

· 盡量使用×××代替字符型。×××在字段長度、索引大小等方面開銷小效率更高,如郵編字段,手機號碼等

· 注釋,每個字段必須以comment語句給出字段的作用

· 經常訪問的大字段需要單獨放到一張表中,避免降低sql效率,圖片、電影等大文件數據禁止存數據庫

· 新業務統一建議使用utf8mb4字符集

用戶賦權

· 理解用戶到底需要什么權限

普通用戶只有數據讀寫權限

系統管理員具有super權限

· 權限粒度要做到盡可能的細

普通用戶不要設置with grant option屬性

權限粒度:系統層面>庫層面>表層面>字段層面

· 禁止簡單密碼

線上密碼要求隨機

2.4-SQL語言進階

本課程涉及建表SQL

-- ------------------------------ Table structure for `play_fav`-- ----------------------------DROP TABLE IF EXISTS `play_fav`;CREATE TABLE `play_fav` (

  `userid` bigint(20) NOT NULL COMMENT '收藏用戶id',

  `play_id` bigint(20) NOT NULL COMMENT '歌單id',

  `createtime` bigint(20) NOT NULL COMMENT '收藏時間',

  `status` int(11) DEFAULT '0' COMMENT '狀態,是否刪除',

  PRIMARY KEY (`play_id`,`userid`),

  KEY `IDX_USERID` (`userid`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='歌單收藏表';

-- ------------------------------ Records of play_fav-- ----------------------------INSERT INTO play_fav VALUES ('2', '0', '0', '0');INSERT INTO play_fav VALUES ('116', '1', '1430223383', '0');INSERT INTO play_fav VALUES ('143', '1', '0', '0');INSERT INTO play_fav VALUES ('165', '2', '0', '0');INSERT INTO play_fav VALUES ('170', '3', '0', '0');INSERT INTO play_fav VALUES ('185', '3', '0', '0');INSERT INTO play_fav VALUES ('170', '4', '0', '0');INSERT INTO play_fav VALUES ('170', '5', '0', '0');

-- ------------------------------ Table structure for `play_list`-- ----------------------------DROP TABLE IF EXISTS `play_list`;CREATE TABLE `play_list` (

  `id` bigint(20) NOT NULL COMMENT '主鍵',

  `play_name` varchar(255) DEFAULT NULL COMMENT '歌單名字',

  `userid` bigint(20) NOT NULL COMMENT '歌單作者賬號id',

  `createtime` bigint(20) DEFAULT '0' COMMENT '歌單創建時間',

  `updatetime` bigint(20) DEFAULT '0' COMMENT '歌單更新時間',

  `bookedcount` bigint(20) DEFAULT '0' COMMENT '歌單訂閱人數',

  `trackcount` int(11) DEFAULT '0' COMMENT '歌曲的數量',

  `status` int(11) DEFAULT '0' COMMENT '狀態,是否刪除',

  PRIMARY KEY (`id`),

  KEY `IDX_CreateTime` (`createtime`),

  KEY `IDX_UID_CTIME` (`userid`,`createtime`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='歌單';

-- ------------------------------ Records of play_list-- ----------------------------INSERT INTO play_list VALUES ('1', '老男孩', '1', '1430223383', '1430223383', '5', '6', '0');INSERT INTO play_list VALUES ('2', '情歌王子', '3', '1430223384', '1430223384', '7', '3', '0');INSERT INTO play_list VALUES ('3', '每日歌曲推薦', '5', '1430223385', '1430223385', '2', '4', '0');INSERT INTO play_list VALUES ('4', '山河水', '2', '1430223386', '1430223386', '5', null, '0');INSERT INTO play_list VALUES ('5', '李榮浩', '1', '1430223387', '1430223387', '1', '10', '0');INSERT INTO play_list VALUES ('6', '情深深', '5', '1430223388', '1430223389', '0', '0', '1');

-- ------------------------------ Table structure for `song_list`-- ----------------------------DROP TABLE IF EXISTS `song_list`;CREATE TABLE `song_list` (

  `id` bigint(20) NOT NULL COMMENT '主鍵',

  `song_name` varchar(255) NOT NULL COMMENT '歌曲名',

  `artist` varchar(255) NOT NULL COMMENT '藝術節',

  `createtime` bigint(20) DEFAULT '0' COMMENT '歌曲創建時間',

  `updatetime` bigint(20) DEFAULT '0' COMMENT '歌曲更新時間',

  `album` varchar(255) DEFAULT NULL COMMENT '專輯',

  `playcount` int(11) DEFAULT '0' COMMENT '點播次數',

  `status` int(11) DEFAULT '0' COMMENT '狀態,是否刪除',

  PRIMARY KEY (`id`),

  KEY `IDX_artist` (`artist`),

  KEY `IDX_album` (`album`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='歌曲列表';

-- ------------------------------ Records of song_list-- ----------------------------INSERT INTO song_list VALUES ('1', 'Good Lovin\' Gone Bad', 'Bad Company', '0', '0', 'Straight Shooter', '453', '0');INSERT INTO song_list VALUES ('2', 'Weep No More', 'Bad Company', '0', '0', 'Straight Shooter', '280', '0');INSERT INTO song_list VALUES ('3', 'Shooting Star', 'Bad Company', '0', '0', 'Straight Shooter', '530', '0');INSERT INTO song_list VALUES ('4', '大象', '李志', '0', '0', '1701', '560', '0');INSERT INTO song_list VALUES ('5', '定西', '李志', '0', '0', '1701', '1023', '0');INSERT INTO song_list VALUES ('6', '紅雪蓮', '洪啟', '0', '0', '紅雪蓮', '220', '0');INSERT INTO song_list VALUES ('7', '風柜來的人', '李宗盛', '0', '0', '作品李宗盛', '566', '0');

-- ------------------------------ Table structure for `stu`-- ----------------------------DROP TABLE IF EXISTS `stu`;CREATE TABLE `stu` (

  `id` int(10) NOT NULL DEFAULT '0',

  `name` varchar(20) DEFAULT NULL,

  `age` int(10) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- ------------------------------ Records of stu-- ----------------------------

-- ------------------------------ Table structure for `tbl_proc_test`-- ----------------------------DROP TABLE IF EXISTS `tbl_proc_test`;CREATE TABLE `tbl_proc_test` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `num` int(11) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;

-- ------------------------------ Records of tbl_proc_test-- ----------------------------INSERT INTO tbl_proc_test VALUES ('11', '1');INSERT INTO tbl_proc_test VALUES ('12', '2');INSERT INTO tbl_proc_test VALUES ('13', '6');INSERT INTO tbl_proc_test VALUES ('14', '24');INSERT INTO tbl_proc_test VALUES ('15', '120');INSERT INTO tbl_proc_test VALUES ('16', '720');INSERT INTO tbl_proc_test VALUES ('17', '5040');INSERT INTO tbl_proc_test VALUES ('18', '40320');INSERT INTO tbl_proc_test VALUES ('19', '362880');INSERT INTO tbl_proc_test VALUES ('20', '3628800');INSERT INTO tbl_proc_test VALUES ('21', '1');INSERT INTO tbl_proc_test VALUES ('22', '2');INSERT INTO tbl_proc_test VALUES ('23', '6');INSERT INTO tbl_proc_test VALUES ('24', '24');INSERT INTO tbl_proc_test VALUES ('25', '1');INSERT INTO tbl_proc_test VALUES ('26', '2');INSERT INTO tbl_proc_test VALUES ('27', '6');INSERT INTO tbl_proc_test VALUES ('28', '24');INSERT INTO tbl_proc_test VALUES ('29', '120');

-- ------------------------------ Table structure for `tbl_test1`-- ----------------------------DROP TABLE IF EXISTS `tbl_test1`;CREATE TABLE `tbl_test1` (

  `user` varchar(255) NOT NULL COMMENT '主鍵',

  `key` varchar(255) NOT NULL,

  `value` varchar(255) NOT NULL,

  PRIMARY KEY (`user`,`key`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='行列轉換測試';

-- ------------------------------ Records of tbl_test1-- ----------------------------INSERT INTO tbl_test1 VALUES ('li', 'age', '18');INSERT INTO tbl_test1 VALUES ('li', 'dep', '2');INSERT INTO tbl_test1 VALUES ('li', 'sex', 'male');INSERT INTO tbl_test1 VALUES ('sun', 'age', '44');INSERT INTO tbl_test1 VALUES ('sun', 'dep', '3');INSERT INTO tbl_test1 VALUES ('sun', 'sex', 'female');INSERT INTO tbl_test1 VALUES ('wang', 'age', '20');INSERT INTO tbl_test1 VALUES ('wang', 'dep', '3');INSERT INTO tbl_test1 VALUES ('wang', 'sex', 'male');

-- ------------------------------ Procedure structure for `proc_test1`-- ----------------------------

DROP PROCEDURE IF EXISTS `proc_test1`;

DELIMITER ;;

CREATE DEFINER=`root` PROCEDURE `proc_test1`(IN total INT,OUT res INT)BEGIN   

    DECLARE i INT;  

    SET i = 1;

    SET res = 1;

    IF total <= 0 THEN   

        SET total = 1;   

    END IF;   

    WHILE i <= total DO

        SET res = res * i;

        INSERT INTO tbl_proc_test(num) VALUES (res);  

        SET i = i + 1;

    END WHILE;

END

;;

DELIMITER ;

說明

· 本課程介紹以MySQL SQL語法為基礎,不同數據庫SQL語法存在差異,并未完全遵照ANSI標準。

· 本課程結合一個實際項目(云音樂),介紹各種SQL語言在實際應用中如何實現業務功能。

SQL進階語法——order by

場景1:歌單按時間排序

-- 查看全部歌單select * from play_list;

-- 按創建時間排序select * from play_list order by createtime;-- MySQL默認升序,如果按降序排列,則使用如下語句。select * from play_list order by createtime desc;-- 也可以按照多個字段來排序select * from play_list order by bookedcount, trackcount;

SQL進階語法——distinct

場景2:統計云音樂創建歌單的用戶

-- 有重復select userid from play_list;

-- 去重select distinct userid from play_list;

-- 多個字段select distinct userid, play_name from play_list;

· distinct用于返回唯一不同的值

· 可以返回多列的唯一組合

· 底層實現使用排序,如果數據量大會消耗較多的IO和CPU

SQL進階語法——group by

場景3-1:統計云音樂創建歌單的用戶列表和每人創建歌單的數量。

-- 每個用戶歌單的最大訂閱數select userid, max(bookedcount) from play_list group by userid;

-- 每個用戶歌單的數量select userid, count(*) from play_list group by userid;

· group by 根據單列或多列對數據進行分組,通常結合聚合函數使用,如count(*).

SQL進階語法——group by having

場景3-2:統計云音樂創建歌單的用戶列表和每人創建歌單的數量,并且只顯示歌單數量排序大于等于2的用戶

select userid, count(*) from play_list group by userid having count(*) >= 2;

· having 是對結果進行過濾

SQL進階語法-like

select * from play_list where play_name like '%男孩%';

通配符

描述

%

代替一個或多個字符

_

代替單個字符

[charlist]

中括號中的任何一個字符

[^charlist] 或者 [!charlist]

不在中括號中的任何單一字符

· 除了百分號在最右面的情況以外,他會對這個表中所有的記錄進行一次查詢匹配,而沒辦法使用索引,效率較低。大表中需要慎用like。可以使用全文檢索的手段。

SQL進階語法-limit, offset

場景4:查詢一個月內創建歌單(從第6行開始顯示10條記錄)

select * from play_list where (createtime between 1427791323 and 1430383307) limit 10 offset 6;

· offset后的值不建議太大,需要消耗的IO較大

case when

· case when 實現類似編程語言的if else功能,可以對SQL的輸出結果進行選擇判斷。

場景5:對于未錄入歌曲的歌單(trackcount = null),輸出結果時歌曲數返回0.

select case when play_name, trackcount is null then 0 else trackcount end from play_list;

select相關進階語法

SELECT

  [DISTINCT]

  select_expr [, select_expr ...]

  [FROM table_references

  [WHERE where_condition]

  [GROUP BY {col_name | expr | position}

    [ASC | DESC], ... [WITH ROLLUP]]

  [HAVING where_condition]

  [ORDER BY {col_name | expr | position}

    [ASC | DESC], ...]

  [LIMIT { [offset, ] row_count | row_count OFFSET offset}]

    [FOR UPDATE | LOCK IN SHARE MODE]]

連接-Join

連接的作用是用一個SQL語句把多個表中相互關聯的數據查出來

場景6:查詢收藏“老男孩”歌單的用戶列表

select * from play_list, play_fav where play_list.id=play_fav.play_id;select play_fav.userid from play_list, play_fav where play_list.id=play_fav.play_id and play_list.play_name='老男孩';-- 另一種寫法select f.userid from play_list lst join play_fav f on lst.id=f.play_id where lst.play_name = '老男孩';

子查詢

· MySQL還有另一種寫法,可以實現同樣的功能。

select userid from play_fav where play_id=(select id from play_list where play_name = '老男孩');

子查詢:內層查詢的結果作為外層的比較條件。一般子查詢都可以轉換成連接,推薦使用連接。

· 不利于MySQL的查詢優化器進行優化,可能存在性能問題

· 連接的實現是嵌套循環,選擇一個驅動表,遍歷驅動表,查詢內層表,依次循環。驅動表會至少查詢一邊,如果有索引等,內層表可以非常快,查詢優化器會選擇數據小的表作為驅動表。

· 子查詢由人為規定驅動表和內層表

連接- left Join

select lst.play_name from play_list lst left join play_fav f on lst.id = f.play_id where f.play_id is null;

· LEFT JOIN從左表(play_list)返回所有的行,即使在右表中(play_fav)中沒有匹配的行。

· LEFT JOIN相對應的有RIGHT JOIN關鍵字,會從右表那里返回所有的行,即使在左表中沒有匹配的行。

場景7:查詢出沒有用戶收藏的歌單

SQL進階語法-union

場景8:老板想看創建和收藏歌單的所有用戶,查詢play_list和play_fav兩表中所有的userid

select userid from play_list union select userid from play_fav;-- 默認會去重, 不想去重的話使用union all代替union。

DML進階語法

· 多值插入: insert into table values(....),(....)

可以一次插入多行數據,減少與數據庫的交互提高效率

eg: insert into A values(4, 33), (5, 33);

· 覆蓋插入: replace into table values (....)

可以簡化業務邏輯的判斷

· 忽略插入: insert ignore into table value (....)

可以簡化業務邏輯的判斷

· 查詢插入: insert into table_a select * from table_b

常用于導表操作

· insert主鍵重復則update

INSERT INTO TABLE tbl VALUES (id, col1, col2) ON DUPLICATE KEY UPDATE col2=....;

eg: insert into A values(2, 40) on duplicate key update age=40;

可以簡化前端業務邏輯的判斷

· 連表update

A表:id, age

B表:id, name, age

A表id與B表id關聯,根據B表的age值更新A表的age。

eg: update A,B set A.age=B.age where A.id=B.id;

· 連表刪除

A表:id, age

B表:id, name, age

A表id與B表id關聯,根據B表的age值刪除A表的數據。

eg: delete A from A,B where A.id=B.id and B.name='pw';

總結

· select查詢進階語法

order by/distinct/group by having (聚合函數) /like (%前綴后綴)

· 連接語法

內連接、左連接、右連接、 Union [ALL]

· DML進階語法

insert/連表update/連表delete

2.5-內置函數

聚合函數

· 聚合函數面向一組數據,對數據進行聚合運算后返回單一的值。

· MySQL聚合函數的基本語法:SELECT function(列) from 表

· 常用聚合函數:

函數

描述

AVG()

返回列的平均值

COUNT(DISTINCT)

返回列去重后的行數

COUNT()

返回列的行數

MAX()

返回列的最大值

MIN()

返回列的最小值

SUM()

返回列的總和

GROUP_CONCAT()

返回一組值的連接字符串(MySQL獨有)

實例還是上節中的那些表

場景1:查詢每張專輯總的點播次數和每首歌的平均點播次數。

select album, sum(playcount), avg(playcount) from song_list group by album;

場景2:查詢全部歌曲中的最大的播放次數和最小的播放次數。

select max(playcount), min(playcount) from song_list;

場景2續:查詢播放次數最多的歌曲

-- 錯誤查法select song_name, max(playcount) from song_list;-- 正確查法select song_name, playcount from song_list order by playcount desc limit 1;

· select count(*) from song_list;

· select count(1) from song_list;

· select count(song_name) from song_list;

count(*)count(1)基本一樣,沒有明顯的性能差異。 count(*)count(song_name)差別在于count(song_name)會除去song_name is null的情況

場景3:顯示每張專輯的歌曲列表

select album, GROUP_CONCAT(song_name) from song_list group by album;-- 默認最大只能連接1024個字符,但是可以通過改數據庫參數來改變。

使用聚合函數做數據庫行列轉換

select user,max(case when 'key'='age' then value end) age,max(case when 'key'='sex' then value end) sex,max(case when 'key'='dep' then value end) dep,from tbl_test1group by user;

預定義函數

· 預定義函數面向單值數據,返回一對一的處理結果(聚合函數可以理解成多對一)。

· 預定義函數基本語法:

select function(列) from ;select * from  where  = function(value) ...

· 

預定義函數-字符串函數

函數

描述

LENGTH()

返回列的字節數

CHAR_LENGTH()

返回列的字符數

TRIM()/RTRIM()/LTRIM()

去除兩邊空格/去除右邊空格/去除左邊空格

SUBSTRING(str, pos, [len])

從pos位置截取字符串str,截取len長度

LOCATE(substr, str, [pos])

返回substr在str字符串中的位置

REPLACE(str, from_str, to_str)

將str字符串中的from_str替換成to_str

LOWER(), UPPER()

字符串轉換為小寫/大寫

· 字符串函數 - 實例

SELECT SUBSTRING('abcdef', 3);-- 'cdef'SELECT SUBSTRING('abcdef', -3);-- 'def'SELECT SUBSTRING('abcdef', 3, 2);-- 'cd'SELECT LOCATE('bar', 'foobarbar');-- 4SELECT LOCATE('xbar', 'foobar');-- 0SELECT LOCATE('bar', 'foobarbar', 5);-- 7

預定義函數-時間處理函數

函數

描述

CURDATE()

當前日期

CURTIME()

當前時間

NOW()

顯示當前時間日期(常用)

UNIX_TIMESTAMP()

當前時間戳

DATE_FORMAT(date, format)

按指定格式顯示時間

DATE_ADD(date, INTERVAL unit)

計算指定日期向后加一段時間的日期

DATE_SUB(date, INTERVAL unit)

計算指定日期向前減一段時間的日期

· 實例:

SELECT NOW() + INTERVAL 1 MONTH;SELECT NOW() - INTERVAL 1 WEEK;

預定義函數-數字處理函數

函數

描述

ABS()

返回數值的絕對值

CEIL()

對小數向上取整 CEIL(1.2)=2

ROUND()

四舍五入

POW(num, n)

num的n次冪 POW(2, 2)=4

FLOOR()

對小數向下取整 CELL(1.2)=1

MOD(N, M)

取模(返回n除以m的余數)=N % M

RAND()

取0~1之間的一個隨機數

算數、邏輯運算

· 比較運算

函數

描述

IS, IS NOT

判定布爾值 IS True, IS NOT False, IS NULL

>, >=

大于,大于等于

<, <=

小于,小于等于

=

等于

!=, <>

不等于

BETWEEN M AND N

取M和N之間的值

IN, NOT IN

檢查是否在或不在一組值之中

實例:查詢一個月內userid為1,3,5的用戶創建的歌單

select * from play_list where (createtime between 1427791323 and 1430383307) and userid in (1,3,5);

· *,/,DIV,%,MOD,-,+

· NOT, AND, &&, XOR, OR, ||

2.6-觸發器與存儲過程

觸發器

· 是什么

觸發器是加在表上的一個特殊程序,當表上出現特定的事件(INSERT/UPDATE/DELETE)時觸發該程序執行。

· 做什么

數據訂正;遷移表;實現特定的業務邏輯。

觸發器-基本語法

CREATE

[DEFINER = { user | CURRENT_USER }]

TRIGGER trigger_name trigger_time

trigger_event ON tbl_name

FOR EACH ROW

trigger_body t

 

trigger_time: { BEFORE | AFTER }

trigger_event: { INSERT | UPDATE | DELETE }

觸發器-實例

學生表:

CREATE TABLE `stu` (

  `name` varchar(50),

  `course` varchar(50),

  `score` int(11),

  PRIMARY KEY (`name`)

) ENGINE=InnoDB;

用于更正成績的觸發器:

DELIMITER //CREATE TRIGGER trg_upd_score

BEFORE UPDATE ON `stu`

FOR EACH ROWBEGIN

  IF NEW.score < 0 THEN

    SET NEW.score = 0;

  ELSEIF NEW.score > 100 THEN

    SET NEW.score = 100;

  END IF;

END; //

DELIMITER ;

注意事項

· 觸發器對性能有損耗,應慎重使用。

· 同一類事件在一個表中只能創建一次。

· 對于事務表,觸發器執行失敗則整個語句回滾。

· Row格式的主從復制,觸發器不會在從庫上執行。

· 使用觸發器時應防止遞歸執行。

存儲過程

· 定義:存儲過程是存儲在數據庫的一組SQL語句集,用戶可以通過存儲過程名和傳參多次調用的程序模塊。

· 特點:

使用靈活,可以使用流控制語句,自定義變量等完成復雜的業務邏輯。

提高數據安全性,屏蔽應用程序直接對表的操作,易于進行審計。

減少網絡傳輸。

提高代碼維護的復雜度,實際使用中要評估場景是否適合。

存儲過程-基本語法

CREATE

  [DEFINER = { user | CURRENT_USER }]

  PROCEDURE sp_name ([proc_parameter[,...]])

  [characteristic ...] routine_body

 

proc_parameter:

  [ IN | OUT | INOUT ] param_name type

type:

  Any valid MySQL data type

characteristic:

    COMMENT 'string'

  | [NOT] DETERMINISTIC

routine_body:

  Valid SQL routine statement

存儲過程-實例

CREATE PROCEDURE proc_test1

(IN total INT, OUT res INT)BEGIN

  DECLARE i INT;

  SET i = 1;

  SET res = 1;

  IF total <= 0 THEN

    SET total = 1;

  END IF;

  WHILE i <= total DO

    SET res = res * i;

    INSERT INTO tbl_proc_test(num) VALUES (res);

    SET i = i + 1;

  END WHILE;

END;

存儲過程-流控制語句

流控制

描述

IF

IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list][ELSE statement_list] END IF

CASE

CASE case_value WHEN when_value THEN statement_list [ELSE statement_list] END CASE

WHILE

WHILE search_condition DO statement_list END WHILE

REPEAT

REPEAT statement_list UNTIL search_condition END REPEAT

存儲過程-調用

set @total=10;set @res=1;

call proc_test1(@total, @res);select @res;

自定義函數

· 自定義函數與存儲過程類似,但是必須帶有返回值(RETURN)。

· 自定義函數與sum(), max()等MySQL原生函數使用方法類似:

SELECT func(val);SELECT * from tbl where col=func(val);

· 

· 由于自定義函數可能在遍歷數據中使用,要注意性能損耗

自定義函數-基本語法

CREATE

  [DEFINER = { user | CURRENT_USER}]

  FUNCTION sp_name ([func_parameter[,...]])

  RETURNS type

  [characteristic ...] routine_body

func_parameter:

  param_name type

type:

  Any valid MySQL data type

characteristic:

    COMMENT 'string'

  | [NOT] DETERMINISTIC

routine_body:

  Valid SQL routine statement

自定義函數-實例

CREATE FUNCTION func_test1 (total INT)

RETURNS INTBEGIN

  DECLARE i INT;

  DECLARE res INT;

  SET i = 1;

  SET res = 1;

  IF total <= 0 THEN

    SET total = 1;

  END IF;

  WHILE i < total DO

    SET res = res * i;

    SET i = i + 1;

  END WHILE;

  RETURN res;

END;

自定義函數-調用

select func_test1(4);

小結

· 知識點:觸發器、存儲過程、自定義函數

· 互聯網場景:觸發器和存儲過程不利于水平擴展,多用于統計和運維操作中。

2.7-MySQL字符集

字符集基礎

· 字符集:數據庫中的字符集包含兩層含義

各種文字和符號的集合,包括各國家文字、標點符號、圖形符號、數字等。

字符的編碼方式,即二進制數據與字符的映射規則。

字符集-分類

· ASCII:美國信息互換標準編碼;英語和其他西歐語言;單字節編碼,7位表示一個字符,共128字符。

· GBK:漢字內碼擴展規范;中日韓漢字、英文、數字;雙字節編碼;共收錄了21003個漢字,GB2312的擴展。

· UTF-8:Unicode標準的可變長度字符編碼;Unicode標準(統一碼),業界統一標準,包括世界上數十種文字的系統;UTF-8使用一至四個字節為每個字符編碼。

· 其他常見字符集:UTF-32,UTF-16,Big5,latin1

MySQL字符集

· 查看字符集

SHOW CHARACTER SET;

· 新增字符集

# 編譯時加入: --with-charset=

./configure --prefix=/usr/local/mysql3 --with-plugins=innobase --with-charset=gbk

字符集與字符序

· charset和collation

collation:字符序,字符的排序與比較規則,每個字符集都有對應的多套字符序。

不同的字符序決定了字符串在比較排序中的精度和性能不同。

查看字符序

show collation;

mysql的字符序遵從命名慣例:以_ci(表示大小寫不敏感),以_CS(表示大小寫敏感),以_bin(表示用編碼值進行比較)。

字符集設置級別

· charset和collation的設置級別:

服務器 >> 數據庫級 >> 表級 >> 列級

· 服務器級

系統變量(可動態設置):

§ character_set_server:默認的內部操作字符集

§ character_set_system:系統元數據(各字段名等)字符集

字符集設置級別

· 服務器級

配置文件

 

[mysqld]

character_set_server=utf8

collation_server=utf8_general_ci

· 數據庫級

CREATE DATABASE db_name CHARACTER SET latin1 COLLATE latin1_swedish_ci;

· character_set_database:當前選中數據庫的默認字符集

主要影響load data等語句的默認字符集,CREATE DATABASE的字符集如果不設置,默認使用character_set_server的字符集。

· 表級

CREATE TABLE tbl1 (....) DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_bin;

· 列級

CREATE TABLE tbl1 (col1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_german1_ci);

字符集設置級別

· 數據存儲字符集使用規則:

使用列集的CHARACTER SET設定值;

若列級字符集不存在,則使用對應表級的DEFAULT CHARACTER SET設定值;

若表級字符集不存在,則使用數據庫級的DEFAULT CHARACTER SET設定值;

若數據庫級字符集不存在,則使用服務器級character_set_server設定值。

-- 查看字符集

show [global] variables like 'character%';

show [global] variables like 'collation%';

-- 修改字符集set global character_set_server=utf8; -- 全局alter table xxx convert to character set xxx; -- 表

客戶端連接與字符集

· 連接與字符集

character_set_client:客戶端來源數據使用的字符集。

character_set_connection:連接層字符集。

character_set_results:查詢結果字符集。

mysql > set names utf8;

 

配置文件設置:

[mysql]

default-character-set=utf8

· 字符轉換過程

client > character_set_client > character_set_connection > Storage > character_set_results >client

推薦使用統一的字符集

· 

常見亂碼原因:

· 

數據存儲字符集不能正確編碼(不支持)client發來的數據:client(utf8)->Storage(latin1)

程序連接使用的字符集與通知mysql的character_set_client等不一致或不兼容。

· 

使用建議

· 

創建數據庫/表時顯式的指定字符集,不使用默認。

連接字符集與存儲字符集設置一致,推薦使用utf8。

驅動程序連接時顯式指定字符集(set names XXX).

· 

mysql CAPI:初始化數據庫句柄后馬上用mysql_options設定MYSQL_CHARSET_NAME屬性為utf8.

· 

· 

mysql php API:連接到數據庫以后顯式用SET NAMES語句設置一次連接字符集。

· 

· 

mysql JDBC: url="jdbc:mysql://localhost:3306/blog_dbo?user=xx&password=xx&userUnicode=true&characterEncoding=utf8"

· 

小結

· 字符集:表示的字符集和/字符編碼方式

· 字符的設置級別:服務器/數據庫/表/列

· 客戶端字符集:亂碼產生的原因與解決方式

2.8程序連接MySQL

程序連接MySQL基本原理

JDBC客戶端應用 -> java.sql.*或javax.sql.* -> 驅動程序 -> SQLserver/Oracle/MySQL

Java代碼示例

結構:

DriverManager -> Driver(是驅動程序對象的接口,指向具體數據庫驅動程序對象)=DriverManager.getDriver(String URL) -> Connectinon(是連接對象接口,指向具體數據庫連接對象)=DriverManager.getConnection(String URL) -> Statement(執行靜態SQL語句接口)=Connection.CreateStatement() -> ResultSet(是指向結果集對象的接口)=Statement.excuteXXX()

import java.sql.*;

/** * 使用JDBC連接MySQL */public class DBTest {

 

    public static Connection getConnection() throws SQLException,

            java.lang.ClassNotFoundException

    {

        //第一步:加載MySQL的JDBC的驅動

        Class.forName("com.mysql.jdbc.Driver");

 

        //設置MySQL連接字符串,要訪問的MySQL數據庫 ip,端口,用戶名,密碼

        String url = "jdbc:mysql://localhost:3306/blog";        

        String username = "blog_user";

        String password = "blog_pwd";

 

        //第二步:創建與MySQL數據庫的連接類的實例

        Connection con = DriverManager.getConnection(url, username, password);        

        return con;        

    }

 

 

    public static void main(String args[]) {

        Connection con = null;

        try

        {

            //第三步:獲取連接類實例con,用con創建Statement對象類實例 sql_statement

            con = getConnection();            

            Statement sql_statement = con.createStatement();

 

            /************ 對數據庫進行相關操作 ************/                

            //如果同名數據庫存在,刪除

            sql_statement.executeUpdate("drop table if exists user;");            

            //執行了一個sql語句生成了一個名為user的表

            sql_statement.executeUpdate("create table user (id int not null auto_increment," +

                    " name varchar(20) not null default 'name', age int not null default 0, primary key (id) ); ");

 

            //向表中插入數據

            System.out.println("JDBC 插入操作:");

            String sql = "insert into user(name,age) values('liming', 18)";

 

            int num = sql_statement.executeUpdate("insert into user(name,age) values('liming', 18)");

            System.out.println("execute sql : " + sql);

            System.out.println(num + " rows has changed!");

            System.out.println("");

 

            //第四步:執行查詢,用ResultSet類的對象,返回查詢的結果

            String query = "select * from user";            

            ResultSet result = sql_statement.executeQuery(query);

 

            /************ 對數據庫進行相關操作 ************/

 

            System.out.println("JDBC 查詢操作:");

            System.out.println("------------------------");

            System.out.println("userid" + " " + "name" + " " + "age ");

            System.out.println("------------------------");

 

            //對獲得的查詢結果進行處理,對Result類的對象進行操作

            while (result.next())

            {

                int userid =   result.getInt("id");

                String name    =   result.getString("name");

                int age        =   result.getInt("age");

                //取得數據庫中的數據

                System.out.println(" " + userid + " " + name + " " + age);                

            }

 

            //關閉 result,sql_statement

            result.close();

            sql_statement.close();

 

            //使用PreparedStatement更新記錄

            sql = "update user set age=? where name=?;";

            PreparedStatement pstmt = con.prepareStatement(sql);

 

            //設置綁定變量的值

            pstmt.setInt(1, 15);

            pstmt.setString(2, "liming");

 

            //執行操作

            num = pstmt.executeUpdate();

 

            System.out.println("");

            System.out.println("JDBC 更新操作:");

            System.out.println("execute sql : " + sql);

            System.out.println(num + " rows has changed!");

 

            //關閉PreparedStatement

            pstmt.close();

 

 

            //流式讀取result,row-by-row

            query = "select * from user";            

            PreparedStatement ps = (PreparedStatement) con.prepareStatement

            (query,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);  

 

            ps.setFetchSize(Integer.MIN_VALUE);  

 

            result = ps.executeQuery();  

 

            /************ 對數據庫進行相關操作 ************/

 

            System.out.println("JDBC 查詢操作:");

            System.out.println("------------------------");

            System.out.println("userid" + " " + "name" + " " + "age ");

            System.out.println("------------------------");

 

            //對獲得的查詢結果進行處理,對Result類的對象進行操作

            while (result.next())

            {

                int userid =   result.getInt("id");

                String name    =   result.getString("name");

                int age        =   result.getInt("age");

                //取得數據庫中的數據

                System.out.println(" " + userid + " " + name + " " + age);                

            }

 

            //關閉 result,ps

            result.close();

            ps.close();

            con.close();

 

        } catch(java.lang.ClassNotFoundException e) {

            //加載JDBC錯誤,所要用的驅動沒有找到

            System.err.print("ClassNotFoundException");

            //其他錯誤

            System.err.println(e.getMessage());

        } catch (SQLException ex) {

            //顯示數據庫連接錯誤或查詢錯誤

            System.err.println("SQLException: " + ex.getMessage());

        }

 

 

    }

 

}

JDBC使用技巧

· Statement與PreparedStatement的區別

· connection, Statement與ResultSet關閉的意義

· jdbc連接參數的使用

· ResultSet游標的使用(setFetchSize)

Statement與PreparedStatement的區別

· PreparedStatement在數據庫端預編譯,效率高,可以防止SQL注入。

· 對數據庫執行一次性存取的時候,用Statement對象進行處理。

· 線上業務推薦使用PreparedStatement.

PreparedStatement背后的故事

PREPARE -> EXECUTE -> DEALLOCATE PREPARE

PREPARE stmt1 FROM 'SELECT productCode, productName                    From products                    WHERE productCode = ?';SET @pc = 'S10_1678';

EXECUTE stmt1 USING @pc;

 

DEALLOCATE PREPARE stmt1;

connection, Statement與ResultSet關閉的意義

· MySQL數據庫端為connection與ResultSet維護內存狀態,一直不關閉會占用服務端資源。

· MySQL最大連接數受max_connections限制,不能無限創建連接,所以用完要及時關閉。

· JDBC connection關閉后ResultSet, Statement會自動關閉。但是如果使用連接池將不會關閉,因此推薦主動關閉。

jdbc連接參數的使用

· 字符集設置:

url="jdbc:mysql://localhost:3306/blog_dbo?userUnicode=true&characterEncoding=utf8";

· 超時設置:

url="jdbc:mysql://localhost:3306/blog_dbo?connectionTimeout=1000&socketTimeout=30000";

ResultSet游標的使用

· 默認的ResultSet對象不可更新,僅有一個向前移動的指針。因此,只能迭代它一次,并且只能按從第一行到最后一行的順序進行。可以生成可滾動和/或可更新的ResultSet對象。

· setFetchSize()是設置ResultSet每次向數據庫取的行數,防止數據返回量過大將內存爆掉。

Python連接MySQL

· Python:腳本語言,無需編譯、易開發

· DBA使用Python的一般場景是編寫自動化運維工具、報表、數據遷移

· Python MySQL驅動:python-mysqldb

import MySQLdb

# 建立和mysql數據庫的連接

conn = MySQLdb.connect(host='localhost', port=3306,user='bloguser',passwd='xxxx')# 獲取游標

curs = conn.cursor()

# 選擇數據庫

conn.select_db('blog')

# 執行SQL,創建一個表

curs.execute("create table blog (id int, name varchar(200))")

# 插入一條記錄

value = [1, 'user1']

curs.execute("insert into blog values(%s, %s)", value)

# 插入多條記錄

values = [(2, "user2"), (3, "user3")]

curs.executemany("insert into blog values(%s, %s)", values)

# 提交

conn.commit()

# 關閉游標

curs.close()# 關閉連接

conn.close()

2.9-DAO框架的使用

DAO框架

· 在應用程序中使用數據訪問對象(DAO),使我們可以將底層數據訪問邏輯與業務邏輯分離開來。DAO框架構建了為每一個數據源提供CRUD(創建、讀取、更新、刪除)操作的類。

· DAO模式是標準J2EE設計模式之一。開發人員用這種模式將底層數據訪問操作與高層業務邏輯分離開。一個典型的DAO框架實現有以下組操作:

一個DAO工廠類

一個DAO接口(select/insert/delete/update)

一個實現了DAO接口的具體類

數據傳輸對象

DAO框架的特點

· 屏蔽底層數據訪問細節,實現業務邏輯和數據訪問邏輯的分離。

· 簡化代碼開發,提高代碼復用率。

· 相較于原生的SQL可能會帶來額外的 性能損耗(利用反射機制封裝對象,SQL轉換等)

MyBatis簡介

· MyBatis是一個主流的DAO框架,是apache的一個開源項目iBatis的升級版。

· MyBatis支持普通SQL查詢,存儲過程和高級映射,消除就幾乎所有JDBC代碼和參數的手工設置以及結果集的檢索。

· 接口豐富、使用簡單

· 相較于hibernate更加輕量級,支持原生的sql語句。

· 支持查詢緩存

MyBatis代碼示例

· 環境搭建,數據源于映射配置文件的編寫

· 單值、多值查詢

· 增刪改數據

· 連表查詢

示例代碼在sorence/DAO框架代碼示例.rar

MyBatis工作流程

· 加載配置并初始化,內部生成MappedStatement對象。

· 調用MyBatis提供的API(SqlSession.select/insert....),將SQL ID與數據對象傳遞給處理層。

· 處理層解析MappedStatement對象,獲取MySQL的連接,執行相應的SQL語句,接收返回結果。

· MyBatis將接收到的返回結果封裝成對應的數據對象返回。

MyBatis使用技巧

· 區分#{}${}的不同應用場景: #{}會生成預編譯SQL,會正確的處理數據的類型,而${}僅僅是文本替換。

· 注意MyBatis封裝數據時的性能損耗: 只返回需要的行數和字段。

· 使用MyBatis自帶的連接池功能: <dataSource type="POOLED">

 

 


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

陆川县| 城市| 望江县| 子洲县| 喀喇沁旗| 亳州市| 开江县| 沿河| 定襄县| 嘉义县| 墨竹工卡县| 谢通门县| 平南县| 谷城县| 桦南县| 尼玛县| 章丘市| 黄陵县| 吉林省| 康马县| 滁州市| 越西县| 鄂伦春自治旗| 门头沟区| 铜陵市| 石首市| 虞城县| 二连浩特市| 来凤县| 廉江市| 东源县| 惠来县| 拉萨市| 昭平县| 桦南县| 壶关县| 车险| 长顺县| 吉安市| 乌兰浩特市| 景谷|