@Table 是類級別的注解,用於聲明實體映射到數據庫中的具體的表。
| 參數 | 類型 | 描述 |
|---|---|---|
| name | String | 表的名稱,默認為實體名稱(參考 @Entity 注解的 name 參數說明),因此如果實體名稱與映射的表名稱一致時,@Table 注解常常可以省略。 |
| catalog | String | 默認為數據庫系統缺省的 catalog。 |
| schema | String | 默認為用戶缺省的 schema。 |
| uniqueConstraints | UniqueConstraint[] | 表的唯一約束(除了由 @Column 和 @JoinColumn 注解指定的約束以及主鍵的約束之外的約束),通過使用 @UniqueConstraint 注解來聲明,僅在允許自動更新數據庫表結構的場景中起到作用,默認沒有其他額外的約束條件。 |
| indexes | Index[] | 表的索引,通過使用 @Index 注解來聲明,僅在允許自動更新數據庫表結構的場景中起到作用,默認沒有其他額外的索引。 |
1 catalog 和 schema 的區別
catalog 和 schema 主要用來解決數據庫系統命名沖突的問題。一個數據庫系統可以包含多個 catalog,每個 catalog 可以包含多個 schema,而每個 schema 又可以包含多個數據庫對象(表、視圖等)。不同的數據庫系統對 catalog 和 schema 的支持方式有所不同,常見的數據庫系統:
| 數據庫系統 | catalog | schema |
|---|---|---|
| MySQL | 不支持 | 數據庫名 |
| Oracle | 不支持 | 用戶 ID |
| SQLServer | 數據庫名 | 對象屬主名 |
| DB2 | 指定數據庫對象時,Catalog 可以省略 | Catalog 屬主名 |
| Sybase | 數據庫名 | 數據庫屬主名 |
2 唯一約束和索引的區別
唯一約束是用來確保數據的正確性,它不允許表中存在重復的數據,若新插入的數據在表中已經存在,則更新操作失敗。在數據庫系統中,創建一個唯一約束的同時,也會為該約束所指定的所有列創建一個唯一索引,即約束包含索引。
索引是用來優化數據庫表數據的檢索性能的。通常,出現在查詢 SQL 的 WHERE 子句和 JOIN 子句中的列可以考慮為其建立索引。
3. @UniqueConstraint
用於聲明表的唯一約束,這些僅在允許自動更新數據庫表結構的場景中起到作用。
| 參數 | 類型 | 描述 |
|---|---|---|
| name | String | 約束名稱,如果不指定,默認使用數據庫提供商所生成的值。 |
| columnNames | String[] | 約束的列名稱 |
4. @Index
用於聲明表的索引,這些僅在允許自動更新數據庫表結構的場景中起到作用。另外,不需要為表的主鍵指定索引,因為主鍵索引會自動被創建。
| 參數 | 類型 | 描述 |
|---|---|---|
| name | String | 索引名稱,如果不指定,默認使用數據庫提供商所生成的值。 |
| columnList | String | 要包含在索引中的列名稱。 |
| unique | boolean | 索引是否唯一,默認為 false。 |
5. @Table
5.1 唯一約束
name 列、mail 列的值必須是唯一的,不允許出現重復的值:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Entity(name = "person") @Table(uniqueConstraints = { @UniqueConstraint(name = "unique_name", columnNames = "name"), @UniqueConstraint(name = "unique_mail", columnNames = "mail") }) public class Person implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String mail; // getters and setters } |
產生的 DDL 語句(MySQL):
| 1 2 3 4 5 6 7 8 |
CREATE TABLE `person` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `mail` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_name` (`name`), UNIQUE KEY `unique_mail` (`mail`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
5.2 聯合唯一約束
多列聯合唯一約束,name 列和 mail 列不能同時出現相同的值:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Entity(name = "person") @Table(uniqueConstraints = @UniqueConstraint(name = "unique_name_mail", columnNames = {"name", "mail"})) public class Person implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String mail; // getters and setters } |
產生的 DDL 語句(MySQL):
| 1 2 3 4 5 6 7 |
CREATE TABLE `person` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `mail` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_name_mail` (`name`,`mail`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
5.3 單列索引
為 name 列和 mail 列分別建立索引:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Entity(name = "person") @Table(indexes = { @Index(name = "index_name", columnList = "name"), @Index(name = "index_mail", columnList = "mail") }) public class Person implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String mail; // getters and setters } |
產生的 DDL 語句(MySQL):
| 1 2 3 4 5 6 7 8 |
CREATE TABLE `person` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `mail` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`), KEY `index_mail` (`mail`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
5.4 多列索引
為 name 列和 mail 列建立多列索引:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Entity(name = "person") @Table(indexes = @Index(name = "index_name_mail", columnList = "name,mail")) public class Person implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String mail; // getters and setters } |
產生的 DDL 語句(MySQL):
| 1 2 3 4 5 6 7 |
CREATE TABLE `person` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `mail` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name_mail` (`name`,`mail`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
5.5 單列索引和多列索引的區別
當 SQL 查詢條件中包含 name 和 mail 時:
| 1 |
SELECT * FROM PERSON WHERE NAME = 'U79028' AND MAIL = '79029@163.com' |
如果為 name 和 mail 列分別建立索引,當執行查詢時,MySQL 只能使用一個索引。如果發現有多個單列索引可用,MySQL 會試圖選擇一個限制最嚴格的索引來檢索,而其他索引則利用不上。
使用分析器分析查詢 SQL:
| 1 |
EXPLAIN SELECT * FROM PERSON WHERE NAME = 'U79028' AND MAIL = '79029@163.com' |
結果如下:
| 1 2 3 4 5 |
+----+-------------+--------+------+-----------------------+------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+-----------------------+------------+---------+-------+------+-------------+ | 1 | SIMPLE | PERSON | ref | index_name,index_mail | index_mail | 768 | const | 1 | Using where | +----+-------------+--------+------+-----------------------+------------+---------+-------+------+-------------+ |
MySQL 優化器如果發現可以使用多個索引查找后的交集/並集定位數據,那么 MySQL 優化器就會嘗試使用 index merge(索引合並)的方式來查詢:
| 1 |
EXPLAIN SELECT * FROM PERSON WHERE NAME = 'U79028' AND MAIL = '79028@163.com' |
結果如下:
| 1 2 3 4 5 |
+----+-------------+--------+-------------+-----------------------+-----------------------+---------+------+------+------------------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------------+-----------------------+-----------------------+---------+------+------+------------------------------------------------------------------+ | 1 | SIMPLE | PERSON | index_merge | index_name,index_mail | index_name,index_mail | 768,768 | NULL | 1 | Using intersect(index_name,index_mail); Using where; Using index | +----+-------------+--------+-------------+-----------------------+-----------------------+---------+------+------+------------------------------------------------------------------+ |
對於多列索引,由於索引文件以B樹的數據結構存儲,MySQL 能夠快速轉到合適的 name,然后再轉到合適的 mail。在建立多列索引時,應該將嚴格的索引放在前面,這樣篩選數據的時候力度會更大,效率更高。
使用分析器分析查詢 SQL:
| 1 |
EXPLAIN SELECT * FROM PERSON WHERE NAME = 'U79028' AND MAIL = '79028@163.com' |
結果如下:
| 1 2 3 4 5 |
+----+-------------+--------+------+-----------------+-----------------+---------+-------------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+-----------------+-----------------+---------+-------------+------+--------------------------+ | 1 | SIMPLE | PERSON | ref | index_name_mail | index_name_mail | 1536 | const,const | 2 | Using where; Using index | +----+-------------+--------+------+-----------------+------------- |
