Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Database - handling of unique constraint violation

Tags:

database

mysql

I have a user creation screen that takes various user details along with first name and mobile number. I have a corresponding USER table in which the First Name and the Mobile number form a composite unique key. There are other integrity constraints defined on this table as well.

When user data is entered on the Create User screen that violates this constraint, user needs to be shown an 'user friendly' error message.

When such a violation occurs, the exception that I get from the MySQL database is:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key `uk_FIRST_NAME__MOBILE_idx`

There are two options to show a meaningful message (for example: "ERROR: User name already exists for the given mobile number, please change either one of them").

Option 1: In the catch block of this exception, parse the MySQL exception's message and look for 'uk_FIRST_NAME__MOBILE_idx'. If present, show the user friendly message as mentioned above.

Option 2: Write a DAO level API that will take first name and mobile number as the only two parameters, fire a database query to see if there is an existing record matching this first name/mobile combination. If true, show the error message to the user; else, run an insert query to insert the user of record into the USER table.

I do NOT like the option 1, as it needs me to 'parse' the exception message, which is not a clean solution. I do NOT like the Option 2 as well, as it needs me to run 'two queries' on the database which is less efficient than the option 1, which is a single query solution.

Question: Are there any other options which are better than these two? If not, which one is the right approach among the above two?

like image 427
PhantomReference Avatar asked Dec 22 '13 07:12

PhantomReference


People also ask

How do you handle unique constraint violations?

To handle unique constraint violations: Catch uniqueness exceptions thrown by the database at the lowest level possible — in the UnitOfWork class. Convert them into Result.

How do I fix unique constraints in Oracle?

The option(s) to resolve this Oracle error are: 1) Drop the unique constraint. 2) Change the constraint to allow duplicate values. 3) Modify your SQL so that a duplicate value is not created.

What will happen if a column has unique key constraint?

When we will add a UNIQUE constraint on the same column multiple times then MySQL will create the index on that column for a number of times we have added the UNIQUE constraint.


1 Answers

I think "option 2" (manually checking constraint before attempting to insert) is horrible, not just because of the race hazard (which could be avoided with locking reads), but also (as you note) because of the additional load on the database: after all, to manually check the constraints completely negates the purpose and benefit of using constraints within the database.

I agree that parsing error message strings feels "dirty", but the strings are well defined. One could even refer to the underlying errmsg.txt or source header files.

Once one has extracted the key name from the error message, one can use the KEY_COLUMN_USAGE information schema to identify the offending columns:

public static final int ER_DUP_ENTRY = 1062;
public static final int ER_DUP_ENTRY_WITH_KEY_NAME = 1586;

public static final String REGEX_DUP_ENTRY_WITH_KEY_NAME =
  "Duplicate entry '(.*)' for key '(.*)'";

// ...


try {
// ...
} catch (MySQLIntegrityConstraintViolationException e) {
  switch (e.getErrorCode()) {
    case ER_DUP_ENTRY:
    case ER_DUP_ENTRY_WITH_KEY_NAME:
      Pattern p = Pattern.compile(REGEX_DUP_ENTRY_WITH_KEY_NAME);
      Matcher m = p.matcher(e.getMessage());

      SQLQuery query = session.createSQLQuery(
      " SELECT COLUMN_NAME" +
      " FROM   INFORMATION_SCHEMA.KEY_COLUMN_USAGE" +
      " WHERE  CONSTRAINT_SCHEMA = :schema" +
      "    AND CONSTRAINT_NAME   = :key"
      );
      query.setString("schema", "my_schema");
      query.setString("key"   , m.group(2));

      showDuplicateError(query.list());

      break;
  }
}
like image 56
eggyal Avatar answered Sep 17 '22 18:09

eggyal