我应该通过数据库错误强制执行业务逻辑吗?
我最近一直在考虑一个有趣的设计决策。假设我正在将用户名添加到表中,并且我想确保没有重复的用户名。用户名列是NOT NULL UNIQUE
。我可以:
- 在插入之前查询数据库以确保没有重复的名称,或者
- 只是
INSERT
,并捕获来自数据库引擎的任何异常。
假设我正在使用的数据库能够强制执行约束,我想知道这些选择分别适合什么情况。
There's an interesting design decision I've been thinking about lately. Let's say I'm adding usernames to a table, and I want to make sure there are no duplicates. The username column is NOT NULL UNIQUE
. I could either:
- Query the database before inserting to make sure there are no duplicate names, or
- Just
INSERT
, and catch any exceptions that come from the database engine.
Assuming the DB I'm using is capable of enforcing constraints, I was wondering what situations each of these choices is appropriate in.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
执行选项 2 似乎总是一个好主意。我不会推荐选项 1,因为您实际上已经使执行插入所需的时间加倍(它们都需要首先读取)。此外,一些新的开发人员只是在某个时候提交而不进行检查,那么它就会被破坏。
另一件需要考虑的事情是,停机时间多长合适?这是一个关键任务应用程序吗?如果业务逻辑损坏会发生什么?如果是这样,工厂会倒闭吗?或者只是一些烦人的错误。
你不能因为一些你没有想到的异常导致你的服务器崩溃而让你的工厂关闭。因此,也许每晚或每周检查一次数据的正确性在这种情况下也会有所帮助。然而,我认为数据库强制唯一性的能力(以及可能的其他强制措施)是合适的方法。
It almost always seems like a good idea to do option 2. I wouldn't recommend option 1 because you've effectively doubled the amount of time required to do inserts (they all require reads first). Besides, some new developer is going to just commit sometime and not to the check, and it will get broken.
Another thing to consider is how much downtime is appropriate? Is this a mission critical app? What happens if the business logic is corrupt? Will factories shut down if it is? Or will it just be some annoying bugs.
You can't afford to have your factories shut down because some exception you didn't think of crashed your server. So, perhaps a nightly or weekly check on the data correctness can also help in this case. However, I feel the DB capabilities to enforce uniqueness (and potentially other enforcements) are the appropriate way to go.
是否可以缓存用户名列表并在应用程序端检查而不需要去数据库?您仍然应该对数据库有唯一的约束,以确保没有坏数据进入(始终首先保护数据库级别的数据),但是如果您可以从缓存进行检查,则可以节省到数据库的整个往返过程。当有人选择与现有用户相同的用户名时,数据库会执行此操作。现在,这可能取决于您需要缓存的数据的大小以及缓存必须更新的频率。不了解你的系统,我不能说它是否实用,但我至少会考虑这样做。
Can you cache the username list and check it on the application side without going to the database? You should still have the unique constraint on the database to ensure no bad data gets in (always protect the data at the database level first and foremost) but if you can do the check from a cache, you could save a whole round trip to the database when someone selects the same username as an existing user. Now this may depend o nthe size of the data you would need to cache and how often the cache would have to be updated. Not knowing your system, I can't say if it is practical, but I would at least look into doing it.
您认为新用户名可能是唯一的吗?或者它有可能是重复的吗?如果用户名可能是唯一的,则执行插入并捕获异常会更有效。如果用户名可能重复,则检查重复项(并可能查找相似但尚未采用的用户名)比尝试捕获异常会更有效。显然,不同的数据库和这些数据库的不同版本在相对概率上有不同的盈亏平衡点。但一般来说,如果您正在为一家公司构建一个系统,其中每个人都有一个唯一的用户名,请执行插入并捕获异常。如果您正在构建 Hotmail,请首先检查是否有重复项。
一个快速演示(在 Oracle 11.2.0.1 上)显示,执行失败的插入并处理异常的成本大约是插入前进行检查然后写入数据的 7 倍。
Do you expect that the new username is likely to be unique? Or is it likely that it will be a duplicate? If the username is likely to be unique, doing the insert and catching the exception would be more efficient. If the username is likely to be a duplicate, it will be more efficient to check for duplicates (and potentially look for a similar but not yet taken username) rather than trying to catch the exception. Obviously different databases and different versions of those databases have a different breakeven point on the relative probabilities. But in general, if you're building a system for a company where everyone has a unique username anyway, do the insert and catch the exception. If you're building Hotmail, check for duplicates first.
A quick demo (on Oracle 11.2.0.1) shows that it's roughly 7 times as expensive to do an insert that fails and to handle the exception than it is to do a check before the insert and then write the data.