1、創(chuàng)建表格時添加: create table table1(id int auto_increment primary key,…)
創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供南江網(wǎng)站建設(shè)、南江做網(wǎng)站、南江網(wǎng)站設(shè)計、南江網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、南江企業(yè)網(wǎng)站模板建站服務(wù),10多年南江做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
2、創(chuàng)建表格后添加: alter table table1 add id int auto_increment primary key 自增字段,一定要設(shè)置為primary key.
附:mysql 中的alter table mysql alter table employee change depno depno int(5) not null;
加索引 mysql alter table 表名 add index 索引名 (字段名1[,字段名2 …]);
例子: mysql alter table employee add index emp_name (name);
加主關(guān)鍵字的索引 mysql alter table 表名 add primary key (字段名);
例子: mysql alter table employee add primary key(id);
加唯一限制條件的索引 mysql alter table 表名 add unique 索引名 (字段名);
例子: mysql alter table employee add unique emp_name2(cardnumber);
查看某個表的索引 mysql show index from 表名; 例子: mysql show index from employee;
刪除某個索引 mysql alter table 表名 drop index 索引名; 例子: mysqlalter table employee drop index emp_name;
修改表:增加字段:mysql ALTER TABLE table_name ADD field_name field_type;
查看表:mysql SELECT * FROM table_name;
修改原字段名稱及類型:mysql ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
刪除字段:ALTER TABLE table_name DROP field_name;
MYSQL的自增列在實際生產(chǎn)中應(yīng)用的非常廣泛,相信各位所在的公司or團(tuán)隊,MYSQL開發(fā)規(guī)范中一定會有要求盡量使用自增列去充當(dāng)表的主鍵,為什么DBA會有這樣的要求,各位在使用MYSQL自增列時遇到過哪些問題?這些問題是由什么原因造成的呢?本文由淺入深,帶領(lǐng)大家徹底弄懂MYSQL的自增機(jī)制。
1.? 通過auto_increment關(guān)鍵字來指定自增的列,并指定自增列的初始值為1。
[root@localhost][test1]Create table t(id int auto_increment ,namevarchar(10),primary key(id))auto_increment=1;
QueryOK, 0 rows affected (0.63 sec)
2.? 自增列上必須有索引,將t表的主鍵索引刪除掉,會報錯
[root@localhost][test1]alter table t drop primary key;
ERROR1075 (42000): Incorrect table definition; there can be only one auto column andit must be defined as a key
3.? 設(shè)定auto_increment_increment參數(shù),可以調(diào)整自增步長,該參數(shù)有session級跟global級,在分庫分表以及雙主or多主的模式下比較有用。
4.? 一個表上只能有一個自增列
5.? Mysql5.7及以下版本,innodb表的自增值保存在內(nèi)存中,重啟后表的自增值會設(shè)為max(id)+1,而myisam引擎的自增值是保存在文件中,重啟不會丟失。Mysql8.0開始,innodb的自增id能持久化了,重啟mysql,自增ID不會丟。
首先:表中自增列的上限是根據(jù)自增列的字段類型來定的。
若設(shè)定了自增id充當(dāng)主鍵,當(dāng)達(dá)到了自增id的上限值時,會發(fā)生什么樣的事情呢?還是以上面創(chuàng)建的 t表為例, 先回顧它的表結(jié)構(gòu):
CREATETABLE `t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_binDEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
無符號的int類型,上限是2147483647。這里我們將表的自增值設(shè)為2147483647,再插入兩行數(shù)據(jù):
[root@localhost][test1]alter table t auto_increment=2147483647;
QueryOK, 0 rows affected (0.01 sec)
Records:0? Duplicates: 0? Warnings: 0
[root@localhost][test1]insert into t(name) values ('test');??????????
QueryOK, 1 row affected (0.01 sec)
[root@localhost][test1]insert into t(name) values ('test');
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'
可以看到,第一個插入沒問題,因為自增列的值為2147483647,這是達(dá)到了上限,還沒有超過,第二行數(shù)據(jù)插入時,則報出主鍵重復(fù),在達(dá)到上限后,無法再分配新的更大的自增值,也沒有從1開始從頭分配,在這里表的auto_increment值會一直是2147483647。
對于寫入量大,且經(jīng)常刪除數(shù)據(jù)的表,自增id設(shè)為int類型還是偏小的,所以我們?yōu)榱吮苊獬霈F(xiàn)自增id漲滿的情況,這邊統(tǒng)一建議自增id的類型設(shè)為unsigned bingint,這樣基本可以保障表的自增id是永遠(yuǎn)夠用的。
這里內(nèi)容比較多,innodb是索引組織表,所以涉及到索引的知識,但這不是本文的重點(diǎn),我們快速回顧索引知識:
1.? Innodb索引分為主鍵跟輔助索引,主鍵即全表,輔助索引葉子節(jié)點(diǎn)保存主鍵的值,而主鍵的葉子節(jié)點(diǎn)保存數(shù)據(jù)行,中間節(jié)點(diǎn)存著葉子節(jié)點(diǎn)的路由值。
2.? Innodb存儲數(shù)據(jù)(索引)的單位是頁,這里默認(rèn)是16K,這也意味著,數(shù)據(jù)本身越小,一個頁中能存數(shù)據(jù)的量越多,而檢索效率不僅僅由索引的層數(shù)來決定,更是由一次能夠緩存的數(shù)據(jù)量來定,也就是說數(shù)據(jù)本身越小,則一次IO能夠提取到緩沖區(qū)的數(shù)據(jù)越多(OS每次IO的量是固定的4K),查詢的效率越好。
其實能夠理解索引的結(jié)構(gòu)及索引寫入插入、更新的原理,則自然就明白為何建議使用自增id。這里我直接列出使用自增id 當(dāng)主鍵的好處吧:
1.? 順序?qū)懭?,避免了葉的分裂,數(shù)據(jù)寫入效率好
2.? 縮小了表的體積,特別是相比于UUID當(dāng)主鍵,甚至組合字段當(dāng)主鍵時,效果更明顯
3.? 查詢效率好,原因就是我上面說到索引知識的第二點(diǎn)。
4.? 某些情況下,我們可以利用自增id來統(tǒng)計大表的大致行數(shù)。
5.? 在數(shù)據(jù)歸檔or垃圾數(shù)據(jù)清理時,也可方便的利用這個id去操作,效率高。
容易出現(xiàn)不連續(xù)的id
有的同志會發(fā)現(xiàn),自己的表中id值存在空洞,如類似于1、2、3、8、9、10這樣,有的適合有想依賴于自增id的連續(xù)性來實現(xiàn)業(yè)務(wù)邏輯,所以會想方設(shè)法去修改id讓其變的連續(xù),其實,這是沒有必要的,這一塊的業(yè)務(wù)邏輯交由MySQL實現(xiàn)是很不理智的,表的記錄小還好,要是表的數(shù)據(jù)量很大,修改起來就糟糕了。那么,為什么自增id會容易出現(xiàn)空洞呢?
自增id的修改機(jī)制如下:
在MySQL里面,如果字段id被定義為AUTO_INCREMENT,在插入一行數(shù)據(jù)的時候,自增值的行為如下:
1. 如果插入數(shù)據(jù)時id字段指定為0、null 或未指定值,那么就把這個表當(dāng)前的
AUTO_INCREMENT值填到自增字段;
2. 如果插入數(shù)據(jù)時id字段指定了具體的值,就直接使用語句里指定的值。
根據(jù)要插入的值和當(dāng)前自增值的大小關(guān)系,自增值的變更結(jié)果也會有所不同。假設(shè),某次要插入的值是X,當(dāng)前的自增值是Y。
1. 如果XY,那么這個表的自增值不變;
2. 如果X≥Y,就需要把當(dāng)前自增值修改為 新的自增值 。
新的自增值生成算法是:從auto_increment_offset開始,以auto_increment_increment為步長,持續(xù)疊加,直到找到第一個大于X的值,作為新的自增值。
Insert、update、delete操作會讓id不連續(xù)。
Delete、update:刪除中間數(shù)據(jù),會造成空動,而修改自增id值,也會造成空洞(這個很少)。
Insert:插入報錯(唯一鍵沖突與事務(wù)回滾),會造成空洞,因為這時候自增id已經(jīng)分配出去了,新的自增值已經(jīng)生成,如下面例子:
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
|? 1| aaa? |
|? 2| aaa? |
|? 3| aaa? |
|? 4| aaa? |
+----+------+
4 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
|????????????? 5 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] begin;
Query OK, 0 rows affected (0.00 sec)
[root@localhost][test1] insert intot(name) values('aaa');
Query OK, 1 row affected (0.00 sec)
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
|? 1| aaa? |
|? 2| aaa? |
|? 3| aaa? |
|? 4| aaa? |
|? 5| aaa? |
+----+------+
5 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
|????????????? 6 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] rollback;
Query OK, 0 rows affected (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
|????????????? 6 |
+----------------+
1 row in set (0.01 sec)
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
|? 1| aaa? |
|? 2| aaa? |
|? 3| aaa? |
|? 4| aaa? |
+----+------+
4 rows in set (0.00 sec)
可以看到,雖然事務(wù)回滾了,但自增id已經(jīng)回不到從前啦,唯一鍵沖突也是這樣的,這里就不做測試了。
在批量插入時(insert select等),也存在空洞的問題??聪旅鎸嶒灒?/p>
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
|? 1| aaa? |
|? 2| aaa? |
|? 3| aaa? |
|? 4| aaa? |
+----+------+
4 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
|????????????? 5 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] insert intot(name) select name from t;??????????????????????
Query OK, 4 rows affected (0.04 sec)
Records: 4?Duplicates: 0? Warnings: 0
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
|? 1| aaa? |
|? 2| aaa? |
|? 3| aaa? |
|? 4| aaa? |
|? 5| aaa? |
|? 6| aaa? |
|? 7| aaa? |
|? 8| aaa? |
+----+------+
8 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
|???????????? 12 |
+----------------+
1 row in set (0.00 sec)
可以看到,批量插入,導(dǎo)致下一個id值不為9了,再插入數(shù)據(jù),即產(chǎn)生了空洞,這里是由mysql申請自增值的機(jī)制所造成的,MySQL在批量插入時,若一個值申請一個id,效率太慢,影響了批量插入的速度,故mysql采用下面的策略批量申請id。
1.? 語句執(zhí)行過程中,第一次申請自增id,會分配1個;
2.? 1個用完以后,這個語句第二次申請自增id,會分配2個;
3.? 2個用完以后,還是這個語句,第三次申請自增id,會分配4個;
4.? 依此類推,同一個語句去申請自增id,每次申請到的自增id個數(shù)都是上一次的兩倍。
在對自增列進(jìn)行操作時,存在著自增鎖,mysql的innodb_autoinc_lock_mode參數(shù)控制著自增鎖的上鎖機(jī)制。該參數(shù)有0、1、2三種模式:
0:語句執(zhí)行結(jié)束后釋放自增鎖,MySQL5.0時采用這種模式,并發(fā)度較低。
1:mysql的默認(rèn)設(shè)置。普通的insert語句申請后立馬釋放,insert select、replace insert、load data等批量插入語句要等語句執(zhí)行結(jié)束后才釋放,并發(fā)讀得到提升
2:所有的語句都是申請后立馬釋放,并發(fā)度大大提升!但是在binlog為statement格式時,主從數(shù)據(jù)會發(fā)生不一致。這一塊網(wǎng)上有很多介紹,我不做介紹了。
在徹底了解了MYSQL的自增機(jī)制以后,在實際生產(chǎn)中就能靈活避坑,這里建議不要用自增id值去當(dāng)表的行數(shù),當(dāng)需要對大表準(zhǔn)確統(tǒng)計行數(shù)時,可以去count(*)從庫,如果業(yè)務(wù)很依賴大表的準(zhǔn)確行數(shù),直接弄個中間表來統(tǒng)計,或者考慮要不要用mysql的innodb來存儲數(shù)據(jù),這個是需要自己去權(quán)衡。另外對于要求很高的寫入性能,但寫入量又比較大的業(yè)務(wù),自增id的使用依然存在熱點(diǎn)寫入的問題,存在性能瓶頸,這時候可通過分庫分表來解決。
this.employee_id = employee_id;}} 其它幾個屬性的getter和setter省略,這里我們要用到ejb3-persistence.jar,JPA的注解類就在這個包中,下面詳細(xì)說明上面使用到的注解。 @Entity:通過@Entity注解將一個類聲明為一個實體bean @Table:通過 @Table注解可以為實體bean映射指定表,name屬性表示實體所對應(yīng)表的名稱,如果沒有定義 @Table,那么系統(tǒng)自動使用默認(rèn)值:實體的類名(不帶包名) @Id:用于標(biāo)記屬性的主鍵 @Column:表示持久化屬性所映射表中的字段,如果屬性名與表中的字段名相同,則可以省略@Column注解,另外有兩種方式標(biāo)記,一是放在屬性前,另一種是放在getter方法前,例如: @Column(name = EMPLOYEE_NAME) private String employee_name; 或者 @Column(name = EMPLOYEE_NAME) public String getEmployee_name() { return employee_name; } 這兩種方式都是正解的,根據(jù)個人喜好來選擇。大象偏向于第二種,并且喜歡將屬性名與字段名設(shè)成一樣的,這樣可以省掉@Column注解,使代碼更簡潔。 @TableGenerator:表生成器,將當(dāng)前主鍵的值單獨(dú)保存到一個數(shù)據(jù)庫表中,主鍵的值每次都是從指定的表中查詢來獲得,這種生成主鍵的方式是很常用的。這種方法生成主鍵的策略可以適用于任何數(shù)據(jù)庫,不必?fù)?dān)心不同數(shù)據(jù)庫不兼容造成的問題。大象推薦這種方式管理主鍵,很方便,集中式管理表的主鍵,而且更換數(shù)據(jù)庫不會造成很大的問題。各屬性含義如下: name:表示該表主鍵生成策略的名稱,這個名字可以自定義,它被引用在@GeneratedValue中設(shè)置的generator值中 table:表示表生成策略所持久化的表名,說簡單點(diǎn)就是一個管理其它表主鍵的表,本例中,這個表名為GENERATOR_TABLE pkColumnName:表生成器中的列名,用來存放其它表的主鍵鍵名,這個列名是與表中的字段對應(yīng)的 pkColumnValue:實體表所對應(yīng)到生成器表中的主鍵名,這個鍵名是可以自定義滴 valueColumnName:表生成器中的列名,實體表主鍵的下一個值,假設(shè)EMPLOYEE表中的EMPLOYEE_ID最大為2,那么此時,生成器表中與實體表主鍵對應(yīng)的鍵名值則為3 allocationSize:表示每次主鍵值增加的大小,例如設(shè)置成1,則表示每次創(chuàng)建新記錄后自動加1,默認(rèn)為50@GeneratedValue:定義主鍵生成策略,這里因為使用的是TableGenerator,所以,主鍵的生成策略為GenerationType.TABLE,生成主鍵策略的名稱則為前面定義的”tab-store”。 這里大象想說下,網(wǎng)上有很多文章寫的是strategy = GenerationType.AUTO或是strategy = GenerationType.SEQUENCE,采用SEQUENCE序列是因為Oracle數(shù)據(jù)中不支持identity自動增長,要想使用它,還得在數(shù)據(jù)庫中創(chuàng)建一個序列,如果要更換數(shù)據(jù)庫,那將是一個非常麻煩的事情。SEQUENCE生成方式我們暫且不談,這里說下采用AUTO和IDENTITY的生成方式,本例采用的是SQL Server 2000作為數(shù)據(jù)庫,所以如果想使用AUTO或是IDENTITY生成策略,則一定要對主鍵加上identity標(biāo)識,如identity(1,1)。不過對于AUTO來說,是根據(jù)不同的數(shù)據(jù)庫選擇最合適的自增主鍵生成策略。如果使用MySQL,則主鍵要定義AUTO_INCREMENT,如果是Oracle,則要創(chuàng)建Sequence來實現(xiàn)自增。不管采用何種生成策略,增、刪、改這些方法中一定要加入事務(wù),否則數(shù)據(jù)是不會添加到數(shù)據(jù)庫中滴~~~這是大象反復(fù)測試過的結(jié)果!