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
Related
I am connecting to a MySQL table using JPA Hibernate. But I am getting error in my Java code:
org.hibernate.HibernateException: Missing table
My table is present in MySQL database schema. I am not getting why missing table exception is thrown here. This is a newly created table. All other existing tables in the same schema are accessible from Hibernate. I saw similar posts with same error. But the answers there didn't help my cause. Can you please let me know what can be the issue here.
If table is present, then most likely it is user permission issue. This happens if you have created the table using a different MySQL user. Make sure the MySQL username/password that you are using in Hibernate is having access to the table. To test, login to MySQL console directly using Hibernate credential & run a select query on the table. If you see similar error as below, then you need to grant access to the table for the Hibernate user.
ERROR 1142 (42000): SELECT command denied to user
Source: http://www.w3spot.com/2020/10/how-to-solve-caused-by-hibernateexception-missing-table.html
Make sure the user has access to the table
Make sure names are equals in terms of case sensitivity
Make sure the schema name and table name are not misspelled
If you share more information about the issue, it would be easier to pinpoint the problem.
Chances are there is an inheritance scenario with a physical table that you assumed to be abstract.
To dig deeper you can put a breakpoint in org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl#getTablesInformation which calls extractor.getTable to see why your table is not returned as part of schema tables.
Rerun the app with the specified breakpoint and step through lines to get to the line which queries table names from the database metadat.
#Override
public TableInformation getTableInformation(QualifiedTableName tableName) {
if ( tableName.getObjectName() == null ) {
throw new IllegalArgumentException( "Passed table name cannot be null" );
}
return extractor.getTable(
tableName.getCatalogName(),
tableName.getSchemaName(),
tableName.getTableName()
);
}
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.
#Override
public Application getApplicationForId(Long applicationId) {
List<Application> applications = executeNamedQuery("applicationById", Application.class, applicationId);
return applications.isEmpty() ? null : applications.get(0);
}
while debugging in eclipse
return applications.isEmpty() ? null : applications.get(0);
these expression getting evaluated as
applications.isEmpty() -> false
applications.get(0) -> (id=171)
applications.size() -> 1
but after the execution of this line its throwing error
org.hibernate.HibernateException: More than one row with the given identifier was found: 263536,
Even its size is showing as 1, then still why and how its getting multiple rows after the execution.
I'm quite sure that this is due to eager fetching. So check you entity and remove the fetch=FetchType.EAGER.
Actually this is not caused by duplicate rows in the database, as it's obviously not possible to have duplicate primary keys. Instead this was caused by Hibernate looking up an object, and eagerly filling in a relationship. Hibernate assumed a single row would come back, but two came back because there were two objects associated with that relationship.
In my case the issue was,
while debugging when the execution is in the middle of the transaction, may be the purpose got served and forcibly stopped the server in the middle of the execution itself, as this has been forcibly stopped server, that cannot led the transaction to get rolledback and that end up in making the data dirty or corrupt in the database because before terminating the server some data might got inserted in db (chance of autoincrement of the primarykey).
Resetting the AutoIncrement value for the primary key of the table, resolved the issue.
1.Identify the table with dirty data (refer to stack trace )
2.Sort the column(primary key), check the highest value in the column(say somevalue).
3.use command
ALTER TABLE tablename AUTO_INCREMENT = somevalue+1
I'm using jOOQ 3.8.4 and PostgreSQL 9.5 in a Spring 4 application. I have the following table and type definition
CREATE DOMAIN shop.money_amount AS numeric(6,2) DEFAULT 0 NOT NULL CHECK (value > 0::numeric);
CREATE TYPE shop.money AS (
m_amount shop.money_amount,
m_currency shop.currency,
m_country shop.site_country
);
CREATE TYPE shop.money_mapping AS (
mm_moneys shop.money []
);
CREATE TABLE shop.article
(
a_id bigserial NOT NULL,
a_price shop.money_mapping NOT NULL,
CONSTRAINT a_pk_id PRIMARY KEY (a_id)
);
Then I tried an insert using jOOQ, i.e.:
MoneyMappingRecord priceMoneyMapping = new MoneyMappingRecord();
priceMoneyMapping.setMoneys(new MoneyRecord[]{
new MoneyRecord().setAmount(new BigDecimal("11")).setCountry(SiteCountry.US).setCurrency(Currency.USD),
new MoneyRecord().setAmount(new BigDecimal("14")).setCountry(SiteCountry.DE).setCurrency(Currency.EUR)
});
dsl.insertInto(ARTICLE)
.set(ARTICLE.A_PRICE, priceMoneyMapping)
.returning(ARTICLE.A_ID).fetchOne().getId();
Then I get:
Caused by: org.springframework.jdbc.BadSqlGrammarException: jOOQ;
bad SQL grammar [insert into "shop"."article" ("a_price") values
(row(?::money[])) returning "shop"."article"."a_id"]; nested
exception is org.postgresql.util.PSQLException:
ERROR: cannot cast type record to shop.money_mapping
Detail: Cannot cast type money[] to shop.money[] in column 1.
What am I doing wrong?
UPDATE
I tried to rename the shop.money type as suggested by Lukas (from shop.money to shop.localized_money), but I believe that the problem is related to the schema. See the updated error.
Caused by: org.springframework.jdbc.BadSqlGrammarException:
jOOQ; bad SQL grammar [insert into "shop"."article" ("a_price")
values (row(?::localized_money[])) returning "shop"."article"."a_id"]; nested exception is
org.postgresql.util.PSQLException: ERROR: type "localized_money[]" does not exist
Maybe the type in type is an issue!
There seems to be a problem related to casting of nested array of types in jOOQ 3.8. I've created an issue for this: https://github.com/jOOQ/jOOQ/issues/5571
The problem is that your custom type array type needs to be fully qualified when bound as a bind variable. If it isn't fully qualified, then the type isn't found by PostgreSQL. One possible workaround is described in this question: Permanently Set Postgresql Schema Path
You can add the shop schema on your user's search path:
ALTER ROLE <your_login_role> SET search_path TO shop;
... which means that elements inside of the shop schema no longer need to be fully qualified. Which can also be a bad thing, so be careful! :)
I am using Spring's JdbcDaoSupport class with a DriverManagerDataSource using the MySQL Connector/J 5.0 driver (driverClassName=com.mysql.jdbc.driver). allowMultiQueries is set to true in the url.
My application is an in-house tool we recently developed that executes sql scripts in a directory one-by-one (allows us to re-create our schema and reference table data for a given date, etc, but I digress). The sql scripts sometime contain multiple statements (hence allowMultiQueries), so one script can create a table, add indexes for that table, etc.
The problem happens when including a statement to add a foreign key constraint in one of these files. If I have a file that looks like...
--(column/constraint names are examples)
CREATE TABLE myTable (
fk1 BIGINT(19) NOT NULL,
fk2 BIGINT(19) NOT NULL,
PRIMARY KEY (fk1, fk2)
);
ALTER TABLE myTable ADD CONSTRAINT myTable_fk1
FOREIGN KEY (fk1)
REFERENCES myOtherTable (id)
;
ALTER TABLE myTable ADD CONSTRAINT myTable_fk2
FOREIGN KEY (fk2)
REFERENCES myOtherOtherTable (id)
;
then JdbcTemplate.execute throws an UncategorizedSqlException with the following error message and stack trace:
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ THE SQL YOU SEE ABOVE LISTED HERE ];
SQL state [HY000]; error code [1005]; Can't create table 'myDatabase.myTable' (errno: 150); nested exception is java.sql.SQLException: Can't create table 'myDatabase.myTable' (errno: 150)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
and the table and foreign keys are not inserted.
Also, especially weird: if I take the foreign key statements out of the script I showed above and then place them in their own script that executes after (so I now have 1 script with just the create table statement, and 1 script with the add foreign key statements that executes after that) then what happens is:
tool executes create table script, works fine, table is created
tool executes add fk script, throws the same exception as seen above (except errno=121 this time), but the FKs actually get added (!!!)
In other words, when the create table/FK statements are in the same script then the exception is thrown and nothing is created, but when they are different scripts a nearly identical exception is thrown but both things get created.
Any help on this would be greatly appreciated. Please let me know if you'd like me to clarify anything more.
Some more info:
1) This only happens on my box. My coworker does not get the same problem.
2) The script that forces the tool to error works fine when executed from the mysql command line using the "script" command
My God.
http://bugs.mysql.com/bug.php?id=41635
and
[2nd link removed because spam filter isn't letting me add 2 links. Search Google for "mysql connector / j errno 150" and it's the 3rd result]
...
Looks like mySql5.1 has a bug with its jdbc connector where it bombs where an alter statement to add a FK is in a script with any other statement.
When I broke out my 3 statements into 3 scripts, it worked (the way I was trying before with the 2 fk statements in their own script still bombed because they were sharing a script!!). Also, my coworker is using MySql5.0, so it didn't affect him.
Holy Cow, that was a fun 5 hours.