性能是关键:在数据库内部级联删除/更新更好还是让 Hibernate/JPA 处理它更好?
如果级联位于 DBMS 内部,这会影响查询数据的能力吗?
如果这很重要,我正在使用 HSQLDB。
在级联更新的情况下,如果数据库中有外键约束,则根本无法在应用程序空间中执行此操作。
示例:假设您有一个美国各州的查找表,主键是两个字母的缩写。然后你有一个用于引用它的邮寄地址的表格。有人告诉您,您错误地将蒙大拿州的缩写“MO”而不是“MT”,因此您需要在查找表中更改它。
CREATE TABLE States (st CHAR(2) PRIMARY KEY, state VARCHAR(20) NOT NULL);
INSERT INTO States VALUES ('MO', 'Montana');
CREATE TABLE Addresses (addr VARCHAR(20), city VARCHAR(20), st CHAR(2), zip CHAR(6),
FOREIGN KEY (st) REFERENCES States(st));
INSERT INTO Addresses VALUES ('1301 East Sixth Ave.', 'Helena', 'MO', '59620');
现在您可以在不借助数据库端级联更新的情况下修复错误。下面是一个使用 MySQL 5.0 的测试(假设没有密苏里州的记录,它实际上使用了缩写“MO”)。
UPDATE States SET st = 'MT' WHERE st = 'MO';
ERROR 1451 (23000): Cannot delete or update a parent row:
a foreign key constraint fails (`test/addresses`,
CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`st`) REFERENCES `states` (`st`))
UPDATE Addresses SET st = 'MT' WHERE st = 'MO';
ERROR 1452 (23000): Cannot add or update a child row:
a foreign key constraint fails (`test/addresses`,
CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`st`) REFERENCES `states` (`st`))
UPDATE Addresses JOIN States USING (st)
SET Addresses.st = 'MT', States.st = 'MT'
WHERE States.st = 'MO';
ERROR 1451 (23000): Cannot delete or update a parent row:
a foreign key constraint fails (`test/addresses`,
CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`st`) REFERENCES `states` (`st`))
没有应用程序端的查询可以解决这种情况。您需要在数据库中进行级联更新,以便在执行参照完整性约束之前以原子方式在两个表中执行更新。
也就是说,在这种情况下,正确性和性能几乎肯定会齐头并进,因为数据库是对数据完整性施加(和强制)硬约束的正确位置,并且在严重的删除级联中它会明显更快,因为它:
更新:看起来类似的问题已经在这里回答了When/Why to use Cascading in SQL Server?
IMO对您的问题的正确答案将像往常一样“视情况而定”。如果您使用数据库作为敏感信息的存储(例如财务、医疗等),或者如果您的应用程序之外的其他人可以访问数据库,我将投票支持 Hibernate/JPA 方法。如果您的数据库用于记录(例如网站流量等),或者如果您正在开发带有嵌入式数据库的软件,您可以相对安全地使用级联操作。
2. 在大多数情况下,我会投票支持 Hibernate/JPA 方法,因为它更易于管理和预测。
我给你讲一个故事。前段时间,年轻的国家决定改变本国货币(这发生在年轻的国家)。几年后,新的 DBA 在货币表行中看到过时的货币并决定将其删除(谁知道为什么)。猜猜发生了什么?由于级联删除操作,30% 的数据库被删除。具有级联操作的 IMO,您必须非常小心地从一方面删除/更新语句,另一方面您将失去约束(即外键)的能力以进行数据库验证。