假设我们有以下的数据库结构和相应的网页:用户输入验证和数据库约束
该数据库包含两个表,t1
和t2
的。表t2
由两列组成,其中一列被称为id_bar
,它只是一个唯一的ID,另一个被称为name
,用于存储由UI使用的一些字符串。另一个表t1
有两列,一个叫做id_foo
,它只是一个唯一的ID,一个叫做id_bar
,它必须指向t2
中的某一行(即它是一个外键)。
相关部分从web页面(在伪代码):
Form form = new Form();
form.build_and_add_select_from_db_table("t2", "field1");
form.add_submit_button();
if (request.is_post() && form.is_valid(request.get_post_data())) {
Add a new row to t1, using the data from the request
response.redirect(<somewhere>);
}
print form.render(); // this will display validation errors as well
所以,Form
类将呈现form
由来自t2
行为option
个select
元素,和input
用于提交表单。
现在的问题,还假设网站的其他部分允许用户删除行从t2
,则以下是可能的:
- 用户A请求含有上述形式的网页由行(1,“a”),(2,“b”)和(3,“c”)组成的
t2
,其中例如(1,“a”)意味着id_bar
= 1和name
=“a”。 - 用户A从
select
元件选择(1,“A”) - 用户A提交表单
- 服务器侧脚本开始验证数据,看到它的有效进入
if
的真实分支声明(但尚未将新行插入数据库中) - 某些其他用户B使用网站的某些其他部分从
t2
(即(1,“a”))中删除所选行 - 步骤5中的服务器脚本继续并尝试将数据插入到数据库中,但这会导致违反约束条件se id 1不再引用行
t2
所以看起来服务器脚本也必须处理这种情况;即重新呈现表单并通知用户A所选择的选项不再可用。还有其他类似的由这种非原子性引起的情况,例如,如果我们有一个名为user
表,其中每个用户都应该有一个唯一的用户名,以同样的理由如上,我们不能简单地说:
if (check if the username already exists in the database)
display_error();
else
insert_new_user_into_database();
一个解决方案(在这两种情况下)是乐观地尝试插入新行然后以某种方式确定违反了什么约束,以及为什么,并由此推断(我猜)解析错误消息和错误代码,通知用户出了什么问题。然而,这感觉非常混乱:
try {
if (request.is_post() && form.is_valid(request.get_post_data())) {
Add a new row to t1, using the data from the request
response.redirect(<somewhere>);
} catch (DatabaseException e) {
if (e.is_some_constraint_violation()) {
// Find out what field caused the violation
// and generate an appropriate error message,
// possibly also removing alternatives from some form fields,
// it will rethrow the exception or something if it can't
// figure out what happened.
form.handle_database_constraint_violation(e);
} else
throw;
}
另一种解决方案可能是某种锁定?
if (request.is_post())
lock_everything();
Build form ...
if (request.is_post() && form.is_valid(request.get_post_data())) {
Insert the new row into the database
unlock_everything();
response.redirect(<some other page>);
} else
unlock_everything();
这似乎是一个非常普遍的问题(例如,需要一个唯一的用户名),所以有像这些情况下,一些知名的标准溶液这里介绍?这样做的