在MySQL 3.23.44版本後,InnoDB引擎類型的表支持了外鍵約束。 node
外鍵的好處:可使得兩張表關聯,保證數據的一致性和實現一些級聯操做; mysql
1,有外鍵約束的表,必須是innodb型
2,外鍵約束的二個表,原本就相關係的表,而且要有索引關係,若是沒有,建立外鍵時也能夠建立索引。
3,不支持對外鍵列的索引前綴。這樣的後果之一是BLOB和TEXT列不被包括在一個外鍵中,這是由於對這些列的索引必須老是包含一個前綴長度。
4,mysql外鍵的名子在數據庫內要是惟一的 sql
外鍵的定義語法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
該語法 能夠在 CREATE TABLE 和 ALTER TABLE 時使用,若是不指定CONSTRAINT symbol,MYSQL會自動生成一個名字。
ON DELETE、ON UPDATE表示事件觸發限制,可設參數:
RESTRICT(限 制外表中的外鍵改動)
CASCADE(跟隨外鍵改動)c
SET NULL(設空值)
SET DEFAULT(設默認值)
NO ACTION(無動做,默認的) 數據庫
1,CASCADE: 從父表刪除或更新,將自動刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE均可用。在兩個表之間,你不該定義若干在父表或子表中的同一列採起動做的ON UPDATE CASCADE子句。
2,SET NULL: 從父表刪除或更新行,並設置子表中的外鍵列爲NULL。若是外鍵列沒有指定NOT NULL限定詞,這就是惟一合法的。ON DELETE SET NULL和ON UPDATE SET NULL子句被支持。
3,NO ACTION: 在ANSI SQL-92標準中,NO ACTION意味這不採起動做,就是若是有一個相關的外鍵值在被參考的表裏,刪除或更新主要鍵值的企圖不被容許進行(Gruber, 掌握SQL, 2000:181)。 InnoDB拒絕對父表的刪除或更新操做。
4,RESTRICT: 拒絕對父表的刪除或更新操做。NO ACTION和RESTRICT都同樣,刪除ON DELETE或ON UPDATE子句。(一些數據庫系統有延期檢查,而且NO ACTION是一個延期檢查。在MySQL中,外鍵約束是被當即檢查的,因此NO ACTION和RESTRICT是一樣的)。
5,SET DEFAULT: 這個動做被解析程序識別,但InnoDB拒絕包含ON DELETE SET DEFAULT或ON UPDATE SET DEFAULT子句的表定義 網絡
搞個例子,簡單演示一下使用,作dage和xiaodi兩個表,大哥表是主鍵,小弟表是外鍵:
建表: app
提示:不行呀,有約束的,大哥下面還有小弟,可不能扔下咱們無論呀! ssh
插入一個新的小弟: ui
提示:小子,想造反呀!你還沒大哥呢! this
把外鍵約束增長事件觸發限制: spa
得,這回對應的小弟也沒了,沒辦法,誰讓你跟我on delete cascade了呢!
可是刪除小弟,大哥並無刪除
咱們有三個表
env表:
CREATE TABLE `env` ( `id` varchar(36) NOT NULL,
`env_name` varchar(50) NOT NULL,
`env_username` varchar(30) DEFAULT NULL COMMENT '環境用戶名',
`env_password` varchar(30) DEFAULT NULL COMMENT '環境用戶密碼',
`ssh_port` int(11) DEFAULT '22',
`state` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
node表:
CREATE TABLE `node` (
`id` varchar(36) NOT NULL,
`env_id` varchar(36) NOT NULL COMMENT '環境id',
`node_name` varchar(50) NOT NULL,
`ip_str` varchar(50) DEFAULT NULL COMMENT '節點IP',
`node_username` varchar(30) DEFAULT NULL COMMENT '節點用戶名',
`node_password` varchar(30) DEFAULT NULL COMMENT '節點用戶密碼',
`ssh_port` int(11) DEFAULT '22',
`state` varchar(30) DEFAULT NULL,
`sortIndex` int(11) DEFAULT NULL,
`is_dm` tinyint(1) DEFAULT '0' COMMENT '是不是管理節點',
`globalCfg_taskid` int(11) DEFAULT NULL COMMENT '節點全局配置任務id',
`netcfg_taskid` int(11) DEFAULT NULL COMMENT '節點網絡配置任務id',
`isImport` int(1) DEFAULT '0' COMMENT '節點是否爲導入',
`ip_change` int(1) DEFAULT '0' COMMENT '是否節點ip發生變化',
`nodeType` varchar(20) DEFAULT NULL COMMENT '節點類型:x86,ppc',
`oldIp` varchar(50) DEFAULT NULL COMMENT '網絡變化前的節點IP',
PRIMARY KEY (`id`),
UNIQUE KEY `ip_str` (`ip_str`),
KEY `fk_node_env_id` (`env_id`),
CONSTRAINT `fk_node_env_id` FOREIGN KEY (`env_id`) REFERENCES `env` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
app表
CREATE TABLE `app` (
`id` varchar(36) NOT NULL,
`node_id` varchar(36) DEFAULT NULL COMMENT '節點id',
`recipe_id` int(11) DEFAULT NULL COMMENT '配方id',
`groupId` varchar(50) DEFAULT NULL COMMENT '集羣的組序號',
`config_state` varchar(30) DEFAULT NULL COMMENT '應用配置狀態',
`start_state` varchar(30) DEFAULT NULL COMMENT '應用啓動狀態',
`deploy_state` varchar(30) DEFAULT NULL COMMENT '應用部署狀態',
`upgrade_state` varchar(30) DEFAULT NULL COMMENT '應用升級狀態',
`action_state` varchar(30) DEFAULT NULL COMMENT '動做狀態狀態',
`upgrade_version` varchar(40) DEFAULT NULL COMMENT '可升級版本號',
`degrade_version` varchar(40) DEFAULT NULL COMMENT '可降級版本號',
`fail_reason` varchar(250) DEFAULT NULL COMMENT '失敗緣由',
`sortIndex` int(11) DEFAULT NULL,
`actioning` varchar(30) DEFAULT NULL COMMENT 'app執行的動做',
`bak_flag` int(11) DEFAULT '0' COMMENT '應用是不是升級備份,1爲升級備份應用',
`guid` varchar(50) DEFAULT NULL,
`parentId` varchar(36) DEFAULT NULL COMMENT '父應用-容器id',
`to_delete` int(1) DEFAULT '0' COMMENT '是否待刪除',
`commonId` varchar(36) NOT NULL COMMENT 'app生命週期中惟一不變的值',
`update_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最後修改時間',
`oldGroupId` varchar(50) DEFAULT NULL,
`scanAppFlag` tinyint(1) DEFAULT NULL COMMENT '掃描標誌',
PRIMARY KEY (`id`),
KEY `fk_app_node_id2` (`node_id`),
KEY `fk_app_recipe_id2` (`recipe_id`),
CONSTRAINT `fk_app_node_id2` FOREIGN KEY (`node_id`) REFERENCES `node` (`id`),
CONSTRAINT `fk_app_recipe_id2` FOREIGN KEY (`recipe_id`) REFERENCES `recipe` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
從這三個表能夠看得出,node表有一個鍵是env表的id,而node表的id是app表的外鍵,如今碰到一個問題,我用JdbcTemplate刪除node表的一條數據,
sql語句以下:
private static final String DELETE_NODE_BYID_IMPORT = "delete from node where id=?";
/**
* 根據id刪除node
* @param nodeId
*/
public void deleteNodeById(String nodeId) {
try {
this.getSimpleJdbcTemplate().update(DELETE_NODE_BYID_IMPORT, nodeId);
} catch (DataAccessException e) {
throw new ValidateException("", "必須所有刪除該節點下的全部子節點,error:" + e.getMessage());
}
}
這樣一執行就會報錯:
很正常,由於app表對應的沒有刪掉,且沒有級聯刪除,因此這兒刪報錯很正常,可是使用以下刪除結果就正確了:
private static final String DELETE_NODE_BYID = "delete from node where id=? and env_id=?"; /** 刪除節點信息,若是節點下有應用,刪除失敗 */ public void deleteNodeById(String nodeId, String envId) { try { this.getSimpleJdbcTemplate().update(DELETE_NODE_BYID, nodeId, envId); } catch (DataAccessException e) { throw new ValidateException("", "必須所有刪除該節點下的全部子節點,error:" + e.getMessage()); } } 就多加了一個envId就是node表的外鍵,結果就成功了,按理說刪除只和app表相關的。真是百思不得其解。望各位大神解答一下。