I understand that if I try to insert a record using JPA and if it violates unique constrain, it throws an exception which contains cause MySQLIntegrityConstraintViolationException.
I want to show user friendly message to the user. So I would like to get the field name for which violation occured. I can get the message using cause which gives message something like Duplicate entry '1' for key 'DOCUMENT_NUMBER'.
But I feel relying on message(e.getCause().getCause().getMessage()) is not a good idea.
The entity may contain several other unique constraints like emailid, vat number etc.
So I would like to get the field name for which constraint violation occured.
Could some one please help how to get the field name?
Thanks in advance,
Kitty
you can try below code
try{
//here your code
...
}catch (ConstraintViolationException e) {
for(ConstraintViolation violation : e.getConstraintViolations()) {
System.out.println(violation.getMessage());
}
}
Also for detail explanation of ConstraintViolationException see Java doc.
Related
I am dealing with insert statements into a database on Mysql. I have a users table where I have a unique key on the username and on the email. This way I can get an SQLIntegrityConstraintViolationException when I try inserting a new user into the database. The problem is if both the username and email throw the same exception if there are duplicate entries, how can I tell which one is throwing the exception.
The end goal I want to tell the user whether that username is already taken.. or if that username is already registered.
Thanks,
Usually the exception message contains the object name of the violated constraint. Whenever an SQLIntegrityConstraintViolationException is thrown, you can check which constraint name is within the exception message and set display message based on that.
I am building a java project. I want to check if a primary key already exist in my table. For example I have the below code:
private void AddProductActionPerformed(java.awt.event.ActionEvent evt)
{
String query="INSERT INTO Products(Pro_Id ,Pro_Name,Pro_Price,Pro_Quantity,Pro_Supplier_id)VALUES ('"+Pro_Id.getText()+" ','"+Pro_Name.getText()+" ','"+Pro_Price.getText()+" ','"+Pro_Quantity.getText()+" ','"+Pro_Supplier_id.getText()+" ') ";
executeSQLQuery(query,"Inserted");
}
How can I get a message that tells me to change the entry of primary key if it already exists?
You can put your code inside try catch block.
Inside catch block check for SQLException
public static final int MYSQL_DUPLICATE_PK = 1062; // Replace 1062 with exception no. you are getting in case it is different for different database
try{
String query="INSERT INTO Products(Pro_Id ,Pro_Name,Pro_Price,Pro_Quantity,Pro_Supplier_id)VALUES ('"+Pro_Id.getText()+" ','"+Pro_Name.getText()+" ','"+Pro_Price.getText()+" ','"+Pro_Quantity.getText()+" ','"+Pro_Supplier_id.getText()+" ') ";
executeSQLQuery(query,"Inserted");
} catch(SQLException e){
if(e.getErrorCode() == MYSQL_DUPLICATE_PK ){
System.out.println("Primary key already used");
}
}
How can I get a message that tells me to change the entry of primary
key if it already exists?
Make sure you have marked Pro_Id as PRIMARY KEY while defining your table structure which will make sure this behavior and if you try to insert duplicate value it will throw error.
You would get an error if you try your code and the key already exists. Depending on this error for your program to work during a normal flow is not a good idea, as exceptions are always expensive in terms of performance. What you should do is check if the primary key exists already before trying to insert. This can be done by executing a SELECT query.
SELECT 1 FROM Products WHERE Pro_Id = :yourDesiredPk;
When the result of the query is not empty it would mean that it already exists.
A better idea is to consider using a sequence and using the next value aka auto increment, check it out on google (What is a sequence (Database)? When would we need it?). That way you can avoid having duplicate PK problems. But maybe your PK is not a number and has some business logic behind it, in that case a sequence is not an option.
Before insert record do one thing do count(*) and if count is 0 then and then insert the same otherwise show popup for duplicate query.
Consider an hypothetical User table:
-- postgres, but it could have been any other SQL database
CREATE TABLE User(
id SERIAL PRIMARY KEY,
mail VARCHAR(32) UNIQUE NOT NULL
);
Let's assume I attempt to add two users with the same mail:
session.save(new User(1, "xpto#gmail.com"));
session.save(new User(2, "xpto#gmail.com"));
and execute it through Hibernate. Hibernate will throw me an ConstraintViolationException:
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
...
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "users_mail_key"
Detail: Key (mail)=(xpto#gmail.com) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
...
What I'd like to know is if there's some good way, other than having to manually parse the Exception's output text, to gather what is the reason of the error so I may correctly interpret and react to the problem.
I realize that this may actually be more of a Postgres Driver's problem than actually an Hibernate one, but I'm unsure at this stage so I thought it may opportune to ask in Hibernate's context.
So if you are able to get a value from getSQLState, you can handle the exception:
"All messages emitted by the PostgreSQL server are assigned five-character error codes that follow the SQL standard's conventions for "SQLSTATE" codes. Applications that need to know which error condition has occurred should usually test the error code, rather than looking at the textual error message."
From: http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
23505 = unique_violation
Note: In this link there is also the list.
Well, after looking at Postgres Driver's source code it seems the problem lies with Postgres and not with Hibernate. PSQLException will contain some information, although it certainly isn't as polished as I first assumed :(
} catch (PSQLException e) {
ServerErrorMessage m = e.getServerErrorMessage();
System.out.println(m.getColumn());
System.out.println(m.getConstraint());
System.out.println(m.getDatatype());
System.out.println(m.getDetail());
System.out.println(m.getFile());
System.out.println(m.getHint());
System.out.println(m.getInternalPosition());
System.out.println(m.getInternalQuery());
System.out.println(m.getLine());
System.out.println(m.getMessage());
System.out.println(m.getPosition());
System.out.println(m.getRoutine());
System.out.println(m.getSchema());
System.out.println(m.getSeverity());
System.out.println(m.getSQLState());
System.out.println(m.getTable());
System.out.println(m.getWhere());
}
prints
null
users_mail_key
null
Key (mail)=(xpto#gmail.com) already exists.
nbtinsert.c
null
0
null
398
duplicate key value violates unique constraint "users_mail_key"
0
_bt_check_unique
public
ERROR
23505
users
null
I am using JDBC, and am running a query. Is there a way to get the reason it failed from the SQLException object returned?
In particular, I want to know if my query violated a foreign key constraint (and which one), or a key constraint.
Would this result be vendor-specific? Just in case, I am using the postgresql-8.4-701.jdbc4.jar driver. If it is vendor-specific, where would I find the codes?
EDIT: I want to do this dynamically - i.e.
if(violated foreign key constraint on attribute x) {
return 5;
} else if (violated primary key constraint) {
return 7;
} else {
return 0;
}
Or something like that.
EDIT: According to this post, there are no vendor-specific error codes for PostgreSQL JDBC. Dunno if that's still valid.
You can process the error code from the SQLException object.
sqlException.getErrorCode()
This retrieves the vendor-specific exception code for this SQLException object. By using the vendor-specific error code, you can branch to the required block of code.
try printing the stack trace (e is of SQLException type)
e.printStackTrace()
or getting the Message
e.getMessage()
These may give you some explanation of why the query failed
I need to apply a check so that a user cannot register using an email id which already exists in the database.
Put a constraint on the email column, or select before insert.
There are indeed basically two ways to achieve this:
Test if record exists before inserting, inside the same transaction. The ResultSet#next() of the SELECT should return false. Then do INSERT.
Just do INSERT anyway and determine if SQLException#getSQLState() of any catched SQLException starts with 23 which is a constraint violation as per the SQL specification. It can namely be caused by more factors than "just" a constraint violation. You should namely not handle every SQLException as a constraint violation.
public static boolean isConstraintViolation(SQLException e) {
return e.getSQLState().startsWith("23");
}
I would opt for the first way as it is semantically more correct. It is in fact not an exceptional circumstance. You namely know that it is potentially going to happen. But it may potentially fail in heavy concurrent environment where transactions are not synchronized (either unawarely or to optimize performance). You may then want to determine the exception instead.
That said, you normally don't want to put a PK on an email field. They are namely subject to changes. Rather use a DB-managed autogenerated PK (MySQL: BIGINT UNSIGNED AUTO_INCREMENT, Oracle/PostgreSQL: SERIAL, SQLServer: IDENTITY) and give the email field an UNIQUE key.
Probably something like this DAO method :
public boolean isDuplicateEntry(String email) {
Session session = getSession();
try {
User user = (User) session.get(User.class, email);
session.close();
return (null != user);
} catch (RuntimeException e) {
log.error("get failed", e);
session.close();
throw e;
}
}
Put a unique constraint on the relevant column in the database table. For example (MySQL):
ALTER TABLE Users ADD UNIQUE (Email)
edit - If the e-mail field is already a primary key as you write in a comment above, then you don't need this, because primary keys are by definition unique. Then in Java you could catch the SQLException that you get if you'd insert a record with a primary key that already exists, or you can do a SELECT ... WHERE Email=? before you try the insert to see if there is already a record with that e-mail address.
You may:
make the email field unique, try to insert and catch the exception
or
make a select before each insert