SQL进攻式编程

一般的建议是进行防御式编程(code defensively),在开始处理之前先检查所有参数的合法性。
但实际上,对数据库编程而言,尽量同时做几件事情的进攻式编程有切实的优势。
有个很好的例子:进行一连串检查,每当其中一个检查所要求的条件不符时就产生异常。信用
卡付款的处理中就涉及类似步骤。例如,检查所提交的客户身份和卡号是否有效,以及两者是
否匹配;检查信用卡是否过期;最后,检查当前的支付额是否超过了信用额度。如果通过了所

有检查,支付操作才继续进行。
为了完成上述功能,不熟练的开发者会写出下列语句,并检查其返回结果:

select count(*)
from customers
where customer_id = provided_id

select card_num, expiry_date, credit_limit
from accounts
where customer_id = provided_id

之后,他才会处理金融交易。
相反,熟练的开发者更喜欢像下面这样编写代码(假设today()返当前日期):

update accounts
set balance = balance - purchased_amount

客户是否存在是毫无意义的——因为既然该客户不存在,那么他的记录根本就不在数据库中!
所以,应该先假设没有事情会出错;但如果出错了,就在出错的地方(而且只在那个地方)采
取相应措施。有趣的是,这种方法很像一些数据库系统中采用的“乐观并发控制(optimistic
concurrency control)”,后者会假设update冲突不会发生,只在冲突真的发生时才进行控制处理。
结果,乐观方法比悲观方法的吞吐量高得多。
总结:以概论为基础进行编程。假设最可能的结果;不是的确必要,不要采用异常捕捉的处理
方式。
where balance >= purchased_amount
and credit_limit >= purchased_amount
and expiry_date > today()
and customer_id = provided_id
and card_num = provided_cardnum

接着,检查被更新的行数。如果结果为0,只需执行下面的一个操作即可判断出错原因:

select c.customer_id, a.card_num, a.expiry_date,
a.credit_limit, a.balance
from customers c
left outer join accounts a
on a.customer_id = c.customer_id
and a.card_num = provided_cardnum
where c.customer_id = provided_id

如果此查询没有返回数据,则可断定customer_id 的值是错的;如果card_num 是null,则可
断定卡号是错的;等等。其实,多数情况下此查询无需被执行。

你是否注意到,上述第一段代码中使用了count(*)呢?这是个count(*)被误用于存在性检测的绝
佳例子。
“进攻式编程”的本质特征是:以合理的可能性(reasonable probabilities)为基础。例如,检查

原文地址:https://www.cnblogs.com/chenli0513/p/1828922.html