I am working on a web application, and at a point where I submit forms that are unique to the user, a MySQLIntegrityConstraintViolationException Duplicate entry -'username'
for key 'PRIMARY'
I am well aware of why this is being thrown, because I am attempting to enter a duplicate entry into the database with the same primary key. I would appreciate no comments on this, as it might be a redundant.
What I am really asking is how should I handle this. I have attempted to catch this exception, but apparently my lack of experience has caught up to me.
I would appreciate your help with it.
Is there a better method for checking for duplicate entries in a database?
For example, should I do what I do when checking for duplicate members, and just do a check to the database for a matching username and password?
Thanks
Generally, if it's possible avoid throwing Exceptions since they are a heavy mechanism for controlling program workflow. You should only use them to trace bugs and irregular activities/situations. All that means that if you catch an exception, the only thing you can do is log some more, wrap the exception in another exception and eventually triggering some fall-back program logic.
Don't expect to catch exceptions and just check for correct user name. I suppose you will be doing this check a lot if you are developing some sort of registration form ... there are a few popular words for common users and if you implement it with exceptions, you will catch it pretty often...
Unfortunately, if your database is very large, the primary keys are many and complex objects , than you can't afford to keep some of the elements in memory to perform this check for duplicate entries.
Yes, especially in this scenario it is better to check whether another user exists with the same username before trying to insert the user.
I also got the same problem , try handling the exception with the catch (MySQLIntegrityConstraintViolationException sql) .
But don't forget there are 2 types ofMySQLIntegrityConstraintViolationException one for JDBC and one for JDBC4 .
So i recommend to catch both in two separate try catch loops.
Related
This question already has answers here:
SQL Server Insert if not exists
(13 answers)
Closed 8 years ago.
I have a table users with primary key column email.
I have a piece of code where I store the user that simply invokes userDao.store(user);
Since the constraint exists, I can catch the exception and show the error on the UI. This approach works fine.
Another solution is to check first if the user exists and then store him in the database. This would result in two consecutive queries - select and then insert. So basically if the user exists I show the error. The issue I see here that if two users with the same email try to register at the same time and provide the same email. It may happen than both threads check the existence of the user and return nothing. Then the first thread saves the user and the second throws exception.
The third approach is to use MERGE query (I use hsqldb). Basically in one query I insert the user only if he does not exist. Then I can see the result of the query. If no rows have changed then it means that the user exists and I can show the error. Either of these approaches would not violate the consistency of my data. But I am looking for the best practices on how to handle this kind of problem.
Your first instinct was correct. To protect against duplicates, define a UNIQUE constraint on that column. Then catch any exception resulting from a violation of that constraint.
SQL lacks an atomic insert-if-not-exists command. You will see code using a nested SELECT statement, but such code is not atomic, so you would still need to trap for the UNIQUE constraint violations.
This Question is basically a duplicate. Search StackOverflow for more discussion and examples.
By the way, I would recommend against using email address as a primary key. If a user wants to change their email address on their account, you will have to update all related records using that value as a Foreign Key. I suggest using a Surrogate Key instead of a Natural Key almost always.
The chance of that happening is so remote you really don't have to consider it. Especially if you use email validation before someone can use the system. If you still are worried you can minimize the chance by using a synchronize operation on the call that checks for the existence of the email. The only way this would not work is if you have a clustered environment with the code running on 2 or more load balanced servers.
Sometimes a command is expected to fail in certain situations.
Suppose I have pseudo-code
try {
// insert row
} catch(SQLException ex) {
// create table
// insert row
}
I would like to be more specific than just catching a general SQLException. I would like to distinguish between.
A normal error such as table doesn't exist or column count doesn't match.
and
A more serious error such as storage space exceeded or communication error between Java and MySQL.
How can I do this? I've looked at the various choices such as error codes or subclasses, but I'm not sure which way to do it.
My target database is MySQL, but I would like this to be cross-database if there is an easy way to do it. (such as just catching a certain class more specific than SQLException)
This is very opinion-based, but I think SQLException is too general to be used as is.
I understand that most programs accessing a database won't be faced with the task of handling cases when tables do not exist, but there are cases, such as when writing a framework or a tool when checking if the table exists IS important. For these cases it would make more sense to check also if the required columns are also present and have the right types. In these cases it makes sense to access the data dictionary. Of course only if the dictionary is available, which is not the case on certain production products.
When the data dictionary is not available then the only recourse is the error message and the error code, and both of them are vendor-specific. Which means there's no one solution fits all.
A long time ago I wrote a JDBCExceptionHandler, which would receive the SQLException, analyze its contents and would throw a more specialized Exception, even judging if the exception was recoverable or not. Eventually I moved on to Hibernate, which has a more comprehensive set of exceptions, coupled with the fact that I got tired of maintaining it as vendors changed their implementations.
But if you do want to pursue this line, then my advice is to use error codes and parsers on the error message. Subclassing will work, but only for your own set of exceptions. So, have an Exception Handler that will read the code and the message and then throw you own set of exceptions, subclassing them as you see fit.
From Class SQLException:
Direct Known Subclasses:
BatchUpdateException, RowSetWarning, SerialException, SQLClientInfoException, SQLNonTransientException, SQLRecoverableException, SQLTransientException, SQLWarning, SyncFactoryException, SyncProviderException
And:
public int getErrorCode()
Retrieves the vendor-specific exception code for this SQLException object.
Returns:
the vendor's error code
Error codes for MySQL can be found at Appendix B Errors, Error Codes, and Common Problems
You should catch the most specific exception (the appropriate subclass) and then use getErrorCode() if you require additional information.
In my opinion SQL Error codes are the way to go in this kind of scenario because they may provide actual implementation specific error codes as mentioned in Oracle docs:
SQL error code. This is an integer value identifying the error that
caused the SQLException instance to be thrown. Its value and meaning
are implementation-specific and might be the actual error code
returned by the underlying data source. Retrieve the error by calling
the method SQLException.getErrorCode.
For example, if you call the method CoffeesTable.dropTable with Java DB as your DBMS, the table COFFEES does not exist, and you remove the call to JDBCTutorialUtilities.ignoreSQLException, the output will be similar to the following:
SQLState: 42Y55
Error Code: 30000
Message: 'DROP TABLE' cannot be performed on
'TESTDB.COFFEES' because it does not exist.
Hope this helps.
you can do some thing like this
catch(SQLException e)
{
if(e.getMessage().indexOf("ORA-00001")!=-1)
JOptionPane.showMessageDialog(null,"you have add some
information not duplicated ,please click ok and try again...");
}
I am writing a database backed web server and I was wondering about the best practise/idiomatic way to implement the following:
So when a user creates account the server needs to insure that the username has not been already taken. The username field in the database is defined as a unique key. So rather than doing a two step process of checking the existence of the username and then adding it, I was hoping I could take advantage of the DBMS. By this I mean, just add the record and trust that an SQLException will be thrown.
My issue is how to find the cause of the exception. As in I certainly cannot return exception.getMessage() to the user but I need a way of identifying if it was due to a duplication in an unique key field that caused the error (and therefore let the user know) and not another type of issue that JDBC may throw (other issues should instead be logged).
I could try to parse e.getMessage() but I was hoping there would be a more full proof way to do this.
The best practice is capture the sqlexception, handle it (depends on your db provider exception codes) to transform into a new Exception like UserAlreadyExistException throwing it to the presentation layer. Finally in the presentation layer capture it and put an user-friendly message.
just a guide here, please!
I want to insert some values in my db, from java
I have my oracle prepared statement and stuff and it inserts ok, but my other requirement it's to send via email the fields that for some reason werent insert.
So, Im thinking making my method as int and return like 0 if theres an error 1 if its ok, 2 if some fields didn't insert ... etc... BUT
I'm lost figuring how to bind it, I mean if there's an error in the catch from sql in java i can put like
catch (SQLException e) {// TODO Auto-generated catch block
e.printStackTrace();
return result = 0;
And obviously i can put an error message and stuff where i call it, but how will i know in which item stops and then retrieve the rest of the fields that weren't insert...
any idea? anyone has an example?
Thanks in advance
First of all try to do as much validations possible in Java and identify the bad records before persisting them in database, you can catch those records before they hit database and send email.
In case you are worried about db level issues e.g. contrainst etc, then you need to choose Performance vs Flexibile Features
Option1 : Dont use batch insert one record at a time, whatever fails you can send email, this is bad from performance perspective but will solve your purpose
Option2 : Divide your records into batches of 50 or 100, whatever batch fails you can report that whole batch failed, this will also report some good records, but you will have information about what was not persisted.
Option3 : Divide your records into batches, if a batch fails try saving one record at a time for that particular batch, that ways you will be able to identify bad record and performance will be optimized, this will require more coding and testing.
So, you can choose what ever suits you, but I would recommend following:
Do maximum validations in Java
Split into smaller batches and use Option 3.
Cheers !!
When you have an insert you insert all fields included in the statement; or, none. So if throw an exception when running your statement, then you would send an email.
If no exception is thrown then you would assume that it has worked.
Alternatively, after running the insert, you could then attempt to do a select to check to see if the data you inserted was actually there.
If the statement failed then none of your field will be inserted, because oracle internally does a rollback to maintain consistency in your data.
I have a Java program that is agnostic from the database and I need to know, while inserting, if an SQLException was thrown because of a duplicate key.
If I was using a single database driver I would simply use the ErrorCode, but since I can be using very different engines the ErrorCode are not the same.
Has anyone done this before? Any ideas?
Many TIA!
Edit: I have a configuration file where I store the driver class (ie: org.apache.derby.jdbc.ClientDriver) and some other needed information (ie: username, password, url...). The connection is always passed as a "java.SQL.Connection" so I don't really care what drivers is being used.
This is exactly what SQLException.getSQLState() is for. Acoording to Google, "23000" indicates a unique constraint violation in at least MySQL, PostgreSQL, and Oracle.
With basic JDBC, there really isn't a way to do what you are saying in a cross-database manner. As you mentioned getErrorCode could be used, but required vendor-specific error codes.
The only three ways I see to get around this is:
Use some sort of framework that does all of the translating from error code to meaningful exceptions (Hibernate would probably do this, someone else mentioned that Spring does)
Check for the duplicate manually (with a select) prior to doing your insert. (This wouldn't be 100%, as its technically possible that someone could have done an insert after your query).
After you get any sql exception on the insert, try to query for that id. If you can actually find the match - you can be fairly sure that the error you received was due to a duplicate primary key. (Although its possible that there was multiple problems, and that wasn't actually the one that was thrown).
My recommendation would be to write your code to avoid the problem as much as possible, and then (if absolutely necessary), use #3.
You could "train" the program on startup (or config) by inserting a known duplicate key, and recording the thrown error code.
I think the ideal solution would be to have the data layer throw a specific exception in this case, perhaps a subclass of SQLException for DuplicateKeyException or something similar.
If you want to be able to treat different exceptions differently, then you have to throw different exception types (or sub-types) to begin with.
I think this is an area where the Spring Framework gets things really right: they provide a very rich hierarchy of "database exceptions" all of which extend DataAccessException , with sub-trees of types for "recoverable exceptions", "transient exceptions", "data integrity exceptions", etc etc. This leaves your client code free to catch any (or none) of the exception types which it can handle or care about: exceptions that indicate an error that may not be repeatable if you re-run the transaction, a fatal non-recoverable error, or you can simply catch the root type.
Well, if you can't rely on the exception to tell you why it was thrown, you could test by following the exception with a "select count(*) from table where key = #keyfailedtoinsert;"
Unfortunately, the exception isn't guaranteed to give you the table name and key name. In some cases, the java code that called called the JDBC driver may never have had them, e.g., if the insert happened wihin a stored procedure, or as in a trigger.
So you're back to having to trust each JDBC driver's vendor.
Am I missing something? If you're using JDBC you should get back a duplicate key exception, regardless of the DB being used.
Or did you ask how you would determine a dupkey BEFORE you tried teh insert?
I believe a simple and reliable way is to check if the key exists prior to doing the insert. As you have rightly pointed out, each database has it's own way of reporting the error.
If you are using spring, set your unique KEY name as UK_user_id for example and catch the DataIntegrityViolationException. You can then compare ex.getCause().getConstraintName() with UK_user_id.
Maybe it's not the right way to solve this problem, but I have the same issue and I resolved with the following code:
try{
//here goes your code
//Conection to DB, stmt, ...
}catch (SQLException sqlEx){
//Check if the SQLException message contains the words "duplicate entry" and "for key"
if(sqlEx.getMessage().contains("Duplicate entry")
&& sqlEx.getMessage().contains("for key")){
System.out.println("This Key already exists in the database");
}else {
//if your Exception is not due to the duplicate key, print your SQLException
System.out.println("Error SQL:" + sqlEx.getMessage());
}
}
I hope this solution can be helpful to someone!!
I'm assuming you aren't using JDBC or this would be a very simple error lookup.
Do you have a different set of classes for accessing the different databases? If so, you could catch the exception in the database specific classes and throw your own exception type that is shared among all the database types.