编辑:我想我需要代码代替我...
关于我的问题的一个简单例子。
在数据库中创建用户,电子邮件和用户名是唯一的。如果未通过唯一性检查,我需要确切地知道哪个字段/列/导致错误的任何内容。
我想实施的内容
void createUser(String email, String username, String password)
throws EmailExistingException, UsernameExistingException
{
//TODO: Create the user or throw exception according to error.
}
糟糕的做法
void createUser(String email, String username, String password)
throws EmailExistingException, UsernameExistingException
{
//Do some query first.
if (emailExists(email)) throw EmailExistingException;
if (usernameExists(username)) throw UsernameExistingException;
//TODO: Create the user.
}
出了什么问题 - 插入之前的典型检查,永远不会被接受。
不是那么糟糕的方法
//During database creation
db.users.setUnique("email", true);
db.users.setUnique("username", true);
void createUser(String email, String username, String password)
throws UserCreationException
{
try {
//TODO: Create the user.
} catch (SomeSortOfDatabaseException e) {
throw UserCreationException("some message", e);
}
}
什么不太好 - 我可能只是遇到错误代码和字符串消息的异常。但我需要让用户知道重复的字段,以便他们可以相应地修改它,我不能用这个代码来做。也许一些db驱动程序的错误可以给你非常具体的细节,但我认为依赖驱动程序不是一个好方法,因为如果你想在将来更改数据库它会杀了你。
我的方法
//During database creation
db.users.setUnique("email", true);
db.users.setUnique("username", true);
void createUser(String email, String username, String password)
throws EmailExistingException, UsernameExistingException
{
try {
//TODO: Create the user.
} catch (SomeSortOfDatabaseException e) {
if (emailExists(email)) throw EmailExistingException;
if (usernameExists(username)) throw UsernameExistingException;
throw ServerException("some message", e);
}
}
它实际上变得越来越好但我不喜欢我当前的方法那么多(在现实世界中许多独特的领域都可以改变,你知道我在说什么)。所以我只是好奇在实际生产中这个问题的常见方法是什么。任何意见将不胜感激。
答案 0 :(得分:0)
使用具有内置原子检查的insert sql:
insert into mytable (col1, col2, ...)
select *
from (select 'foo', 'bar', ... from dual) x -- postgress, mysql, etc doesn't need "from dual"
left join mytable
on col1 = 'foo'
and col2 = 'bar'
...
where col1 is null -- only selects something when there's no match
答案 1 :(得分:0)
刚刚找到了Java解决方案。
//During database creation, make restrictions.
void createUser(String email, String username, String password)
throws EmailExistingException, UsernameExistingException
{
String email_intern = email.intern();
String username_intern = username.intern();
synchronized(email_intern) {
synchronized(username_intern) {
//Do some query first.
if (emailExists(email)) throw EmailExistingException;
if (usernameExists(username)) throw UsernameExistingException;
//TODO: Create the user.
}
}
}
似乎很有希望。 String.intern()确保相同的字符串值在同一实例上同步。这种方法对吞吐量的影响非常小,同时它消除了所有可能的并发问题这种方法。
值得注意的事情