Differentiate SQLExceptions - list of error codes for Oracle? - java

Our application is based on Java, JPA and an Oracle database. If a database operation fails, I get a SQLException or one of it's derivates.
In my case I'd like to distinguish, whether a SQLIntegrityConstraintViolationException has been caused by a problem with a unique or a foreign key constraint.
The log shows the error code ORA-00001 for the unique constraint violation, however, I was looking for a list of the other codes in order to reacte to the right ones.
I'm aware that these codes are vendor specific and SO has an easy to find answer for MySQL. I would need the same for Oracle.

Not surprisingly, there's a list in the OracleDOcumentation:
http://docs.oracle.com/cd/B28359_01/server.111/b28278/toc.htm
but digging in from the top it's also not so easy to find. Since MySql-Answers were so much easier to find, I hope, this Q&A serves to provide an equally quick path to this information.
Unfortunately, one cant't easily search inside the list because it has been spread across multiple pages without much indication on which range contains what kinds of errors.
However, I managed to find the codes for my specific problem: UQ violation is ORA-00001, where as the foreign key errors are found under ORA-02290 (missing parent) and ORA-02291 (attempted delete with dependant children existing).

This problem might be even broader. Error handling is vendor specific and JDBC does not handle vendor specific stuff.
For example JBOSS has class in it called: ExceptionSorter see OracleExceptionSorter. This class lists all the critical error codes describing the situation that the error is on "connection level". So the connection has to be closed and (after some time) a new one has to be created.
Then there are errors on "transaction level". Obviously it is a deadlock "ORA-0060" and then some crazy error returned by concurrent "MERGE" statements. These error can be usually solved by rollback a re-trying the whole transaction.
The rest of the errors are usually related to data integrity, and these can not be re-tried.
I'm not aware of any exception sorted implementation, which covers all classes of error. Maybe it is not even possible to implement, as it can depend on application needs.

Related

Handling Transaction management in a large application

I have a situation like in a Java application like , "if an there is an entry in a table and simultaneously there is a delete request also how will we handle such a scenario".
Could anybody suggest me on how to deal with issues like these which could work on small as well as large applications?
I think the question is how the UI/UX should be handled when such scenario occurs. Besides the concurrency issue described in question, there can be other scenarios like user 1 opens edit person page, in the mean time, user2 deletes that record from another login. What should happen when user1 tries to save the record?
You should probably return an error message to the user stating the details of the error(record deleted, updated by someone else etc.).
Your question is very wide and such is the aswer.
I will narrow the problem a bit, by assuming you are using spring(boot). If so then It is very easy to answer.
Use the #Transactional annotation above the methods that contain the logic to either save or delete. And include required libraries ofc.
With the methods annontated in such a way, the spring(boot) application will guarantee that both operations will occur in the order that is required to maintain a consistent database.
If an error occurs, you can handle this in higher levels of your application or just show an error to the user.

Netbeans Entity Manager not updating Derby Database

I am currently using the automatically created class and Entity manager which is created when a table is bound to a database from NetBeans to get and set values to a derby database.
However when I want to update/edit the field using:
LessonTb Obj = new LessonTb();
Obj.setAdditionalResources(Paths);
Obj.setDescription(LessonDescription);
Obj.setLessonName(LessonName);
Obj.setLessonPath(LessonName + ".txt");
Obj.setRecommendedTest(RecommendedTest);
EUCLIDES_DBPUEntityManager.getTransaction().begin();
EUCLIDES_DBPUEntityManager.getTransaction().commit();
lessonTbList.clear();
lessonTbList.addAll(lessonTbQuery.getResultList());
The current Entry does not update in the database despite knowing that the code worked in other projects. I use the same get and set methods from the same LessonTb class which works to add a new entry and delete and entry.
What could possibly be wrong and how do I solve my problem? No exceptions are thrown.
Here's several possibilities. Perhaps you can do more research to rule at least some of them out:
You're using an in-memory database, and you didn't realize that all the database contents are lost when your application terminates.
You're not in auto-commit mode, and your application failed to issue a commit statement after making your update
You're not actually issuing the update statement that you think you're issuing. For some reason, your program flow is not reaching that code.
Your update statement has encountered an error, but it's not the sort of error that results in an exception. Instead, there's an error code returned, but no exception is thrown.
There are multiple copies of the database, or multiple copies of the schema within the database, and you're updating one copy of the database but querying a different one.
One powerful tool for helping you diagnose things more deeply is to learn how to use -Dderby.language.logStatementText=true and read in derby.log what actual SQL statements you're issuing, and what the results of those statements are. Here's a couple links to help you get started doing that: https://db.apache.org/derby/docs/10.4/tuning/rtunproper43517.html and http://apache-database.10148.n7.nabble.com/How-to-log-queries-in-Apache-Derby-td136818.html

Is hibernate search remote indexing possible?

We are migrating a whole application originally developed in Oracle Forms a few years back, to a Java (7) web based application with Hibernate (4.2.7.Final) and Hibernate Search (4.1.1.Final).
One of the requirements is: as users are using the new migrated version, they able to use the Oracle Forms version - so Hibernate Search indexes will be out of sync. Is it feasable to implement a servlet so that some PL-SQL accesses some link that updates the local indexes in the application server (AS)?
I thought of implementing a some sort clustering mechanism for hibernate, but as I read through the documentation I realised that as clustering may be a good option for scalabillity and performance, for maintaining legacy data in sync may be a bit overkill.
Does anyone have any idea of how to implement a service, accessible via servlet, to update local AS indexes in a given model entity with a given ID?
I don't know what exactly you mean by the clustering part, but anyways:
It seems like you are facing a similar problem like me. I am currently in the works of creating a Hibernate-Search adaption for JPA providers (that are not Hibernate-ORM, meaning EclipseLink, TopLink, etc.) and I am working on an automatic reindexing feature at the moment. Since JPA doesn't have a event system suitable for reindexation with Hibernate-Search I came up with the idea to use triggers on a database level to keep track of everything.
For a basic OneToOne relationship it's pretty straight forward and for other things like relation-tables or anything that is not stored in the main table of an entity it gets a bit trickier, but once you got a system for OneToOne relationships it's not that hard to get to that next step. Okay, Let's start:
Imagine two Entities: Place and Sorcerer in the Lord of the rings universe. In order to keep things simple let's just say they are in a (quite restrictive :D) 1:1 relationship with each other. Normally you end up with 2 tables named SORCERER and PLACE.
Now you have to create 3 triggers (one for CREATE, one for DELETE and one for UPDATE) on each Table (SORCERER and PLACE) that store information about what entity (only the id, for mapping tables there are always multiple ids) has changed and how (CREATE, UPDATE, DELETE) into special UPDATE tables. Let's call these PLACE_UPDATES and SORCERER_UPDATES.
In addition to the ID of the original Object that has changed and the event-type these will need an ID field that is needed to be UNIQUE among all UPDATE tables. This is needed because if you want to feed information from the Update tables to the Hibernate-Search index you have to make sure the events are in the right order or you will break your index. How such an UNIQUE ID can be created on your database should be easy to find on the internet/stackoverflow.
Okay. Now that you have set up the triggers correctly you will just have to find a way to access all the UPDATES tables in a feasible fashion (I do this via querying from multiple tables at once and sorting each query by our UNIQUE id field and then just comparing the first result of each query with the others) and then update my index.
This can be a bit tricky and you have to find the correct ways of dealing with the specific update event but it can be done (that's what I am currently working on).
If you're interested in that part, you can find it here:
https://github.com/Hotware/Hibernate-Search-JPA/blob/master/hibernate-search-db/src/main/java/com/github/hotware/hsearch/db/events/IndexUpdater.java
The link to the whole project is:
https://github.com/Hotware/Hibernate-Search-JPA/
This uses Hibernate-Search 5.0.0.
I hope this was of help (at least a little bit).
And about your remote indexing problem:
The update tables can easily be used as some kind of dump for events until you send them to the remote machine that is to be updated.

Distinguish basic SQLException types in Java?

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...");
}

Find if an SQLException was thrown because of a duplicate

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.

Categories

Resources