I have a table A_TABLE, through entityManger going to commit record using begin transction and try to commit. but in table we have combination of some value is there then throwing ORA-00001: unique constraint exception. And that transction is not active can't able to rollback.
So I deleted that record in DB, try to save same value record with new entityManger transction begin, but its try to saving the record two times, because old one got ORA-00001: unique constraint exception entity also going in this transction to DB and in console two insert is calling.
Need solution for this,
Code :
#Autowired
private EntityManager entityManger;
TableEntity entityObject = new TableEntity(); // Always creating new objects
entityObject .setYear(2018); // Combination of year and month
//if its availbe in DB its throw ORA-00001: unique constraint exception
entityObject .setMonth(01);
if (!entityManager.getTransaction().isActive()) {
entityManager.getTransaction().begin();
}
entityManager.persist(entityObject);
try{
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().commit();
}
} catch (Exception e) {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback(); // Not come to this part when ORA-00001: unique constraint exception occur
}
throw e;
}
INSERT call twice above code after delete unique record from DB, but still throwing ORA-00001: unique constraint exception occur because old one got ORA-00001: unique constraint exception entity also going in this transction to DB and in console two insert is calling.
Related
We have a Kafka consumer in a Java - Spring Boot service that has multiple instances in multiple clusters (all with same consumer group id). The consumer saves data to the database (SQL Server).
The code checks if a record exists in the ItemSet table before saving to the database. The actual data in the payload gets saved in a child table ItemValue and not the parent, ItemSet. The relational data table hierarchy is one to many in this order ItemSet -> ItemName -> ItemValue. ItemSet table has a unique constraint for department id, season combination to prevent multiple duplicate adds.
I need to do some processing after catching this exception to ensure that the incoming data still gets saved under the existing ItemSet and doesn't get lost. I am using Spring Data JPA and as soon as I catch the exception and try to retrieve the existing record I end up getting:
org.hibernate.AssertionFailure: null id in ItemSet entry (don't flush the Session after an exception occurs).
The getItemSet() in the catch block blows up.
What is the best way to overcome these race conditions?
ItemSet savedItemSet = null;
try
{
String seasonName = itemSet.getSeasonName();
Long seasonYear = itemSet.getSeasonYear();
Long departmentId = itemSet.getDepartment().getId();
List<ItemSet> itemSets = attributeSetRepository.findBySeasonNameAndSeasonYearAndDepartmentId(
seasonName, seasonYear, departmentId);
LOGGER.info("Found {} item sets corresponding to season name : {}, season year : {}, "
+ "department id : {}", itemSets.size(), seasonName, seasonYear, departmentId);
if(CollectionUtils.isEmpty(itemSets)) {
savedItemSet = itemSetRepository.save(itemSet);
}
else {
return new CreatedItemSet(itemSets.get(0).getId());
}
}
catch(PersistenceException | DataIntegrityViolationException e)
{
LOGGER.error("An exception occurred while saving itemSet set", e);
if (e.getCause() instanceof ConstraintViolationException)
{
String seasonName = itemSet.getSeasonName();
Long seasonYear = itemSet.getSeasonYear();
Long deptId = itemSet.getDepartment().getId();
LOGGER.info("A duplicate item set found in the database corresponding "
+ "to season name : {}, season year : {} and department : {}",
seasonName, seasonYear, deptId);
ExistingItemSet existingItemSet = getItemSet(seasonName,
seasonYear, deptId);
if(existingItemSet == null) {
LOGGER.info("No item set found");
return null;
}
return new CreatedItemSet(existingItemSet.getId());
}
}
You can't "continue". A transaction is marked for rollback and the persistence context is unusable after a constraint violation happens.
You can either try to avoid the constraint violation, by checking if the DB contains an entry before persisting/updating, or you run the rest of your code in a separate transaction if a constraint violation happens.
i have a simple loop which will insert some entities in the same transaction , into a DB2 database. The problem is that when committing the transaction and an insert fails due to duplicate ID , the exception i get from the driver is a plain message that indicates for which table the insert statement failed , but i need to find for which entity. Is there any way to translate the exception thrown from the Database??
the method is :
public final void saveAll(List<Entity> entities)
{
StatelessSession session = getSaveQuerySession();
Transaction tr = session.beginTransaction();
try
{
for(Entity entity : entities)
session.insert(entity);
tr.commit();
}
catch (Exception e)
{
e.printStackTrace();
tr.rollback();
}
finally{
session.close();
}
}
the exception i got is :
org.hibernate.exception.ConstraintViolationException: could not insert: [com.MyEntity]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2438)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2858)
EDIT
the inner exception is :
java.sql.SQLIntegrityConstraintViolationException: [SQL0803] Duplicate key value specified.
Cause . . . . . : A unique index or unique constraint *N in *N exists over one or more columns of table MYENTITY in MYSCHEMA.
The operation cannot be performed because one or more values would have produced a duplicate key in the unique index or constraint. Recovery . . . :
Change the statement so that duplicate keys are not produced.
For information on what rows contain the duplicate key values,
look at the previously listed messages in the job log (DSPJOBLOG command) or press F10 (Display messages in job log) on this display.
Im trying to create CRUD test to show my JPA program works but it is giving me strange error when i create a new entity and commit it to the database.
The Table supplier have only one contraint and that is a unique index that is autogenerated.
i will post the classes first then what i tried to do with them
Here is the SQL for the table and contraints
-- DDL for Table SUPPLIER
CREATE TABLE SUPPLIER
( SUPPLIERID INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY,
COMPANYNAME VARCHAR(40),
CONTACTNAME VARCHAR(30),
CONTACTTITLE VARCHAR(30),
ADDRESS VARCHAR(60),
CITY VARCHAR(15),
POSTALCODE VARCHAR(10),
COUNTRY VARCHAR(15),
PHONE VARCHAR(24),
FAX VARCHAR(24)
);
-- Constraints for Table SUPPLIER
ALTER TABLE SUPPLIER ALTER SUPPLIERID NOT NULL;
ALTER TABLE SUPPLIER ALTER COMPANYNAME NOT NULL;
ALTER TABLE SUPPLIER ADD CONSTRAINT PK_SUPPLIER PRIMARY KEY (SUPPLIERID);
This is my suppliers Primary key:
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "SUPPLIERID")
private Integer supplierid;
So first i create the entity and add it to my entitymanager
Supplier sup = new Supplier("Test","Test","Test","Test","Test","Test","Test","Test","Test");
em.persist(p);
Then i save it
public void Save() {
em.getTransaction().begin();
em.getTransaction().commit();
}
And then i get the error below even thought the only constraint that can be broken is 2 identical pk but those are auto generated.
I know that my setup works because my 2 other tests ( inserting other new entities works fine).
I also close and reopen connection between each test.
[EL Warning]: 2014-09-09 17:17:33.67--UnitOfWork(1407675409)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'PK_SUPPLIER' defined on 'SUPPLIER'.
Error Code: -20001
Call: INSERT INTO SUPPLIER (ADDRESS, CITY, COMPANYNAME, CONTACTNAME, CONTACTTITLE, COUNTRY, FAX, PHONE, POSTALCODE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [9 parameters bound]
Query: InsertObjectQuery(Peristency.Supplier[ supplierid=null ])
The save method irritates me a little. Like it is written above, it performs an empty transaction, doesn't it? Shouldn't it be something like this:
public void Save() {
...
em.getTransaction().begin();
...
Supplier sup = new Supplier("Test","Test","Test","Test","Test","Test","Test","Test","Test");
em.persist(p);
...
em.getTransaction().commit();
...
}
Could it be, that the coding for the question has been shortened too much, thus scrumbling the picture? Could you provide us please with the complete coding from starting the whole transaction until committing?
I remember once a while, I had a similar problem. Main point was, that I tried to persist twice in one transaction - and that was not possible - complaining about a duplicated key problem. May be that this is a hint for your case.
Okay after alot of Wall to face action i have found the cause of my problem
If you try to commit(entitymanager.getTransaction.commit()) a entity with a null pk to the database it wont work even if the database is supposed to provide the id.
What i had to do everytime i need a new object in a state where it can be saved to the db
public void addEmployee(Employee p) {
em.getTransaction().begin();
em.persist(p);
//Doesn't have an id
System.out.println(p.getEmployeeid());
em.flush();
//now it has an id!
System.out.println(p.getEmployeeid());
em.getTransaction().commit();
}
Then later i can merge and commit at my leasure but i feel like i made a ineffecient solution with the database transaction i have.
I've got tables like this:
Table A:
`id | name`
Table B:
`id | A_id | ....`
A_id is a foreign key to Table A, the Engine is InnoDB
This is the code that fails:
String[] cleanupQueries = new String[] { "DELETE FROM B WHERE A_id = (SELECT id FROM A WHERE name = 'test')",
"DELETE FROM A WHERE name = 'test'" };
Connection connection;
try {
connection = DriverManager.getConnection(getConnectionString());
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException("Error establishing a database connection!");
}
try {
for(String cleanupQuery : cleanupQueries) {
PreparedStatement statement = connection.prepareStatement(cleanupQuery);
statement.executeUpdate(); //FAILS WHEN EXECUTING THE SECOND QUERY
}
} catch(SQLException e) {
throw new RuntimeException("Error while executing the queries in the transactional context!");
}
try {
connection.commit();
} catch (SQLException e) {
rollback(connection);
throw new RuntimeException("Error while comitting!");
}
The Exception i get is:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ('DATABASE/TABLE', CONSTRAINT 'FK_B_A' FOREIGN KEY ('FK_A') REFERENCES 'A' ('ID') ON DEL)
The database doesn't let me delete A while there are still B's left, but the first query deleted all B's. I want to delete all B's and the A they reference only completely.
I don't want to change the Tables to have cascading deletes. What shall i do to get the code working?
Cause for error is
The Foreign Key has referenced to the table A id so if you would like to delete the F_Key , first you should delete the Child references values of that foreign keys then only its possible to delete the parent.
Correct me if 'm wrong..
Simply add the cascade is true while deleting the foreign key constraint.The child table entry is automatically deleted when you delete the original parent entry.
Try:
"DELETE FROM B WHERE A_id = (SELECT id FROM A WHERE name IN 'test')"
Since the child rows are deleted in the same transaction, the deleted rows are still visible and thus the parent rows could not be deleted.
This may be because of the transaction isolation setting on the connection. I would try different levels and see which one allows it.
I am using Hibernate and MySql.
I have a 2 tables:
User: id, name, type
City: id, name, type
type: id, name
Where user.type has foreign key to user_type.id. and as well city.
I would like before deleting a row in user_type table, to check if any row from any table is related to it.
my columns are mapped for example:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "type_id")
How can I do it?
You said
I have around 100 tables like User and City mapped to this value
ok. Hibernate with JPA book says
You may have removed all other references manually
Which implies you should query manually any related Table. But it says if other entity references Type, database constraints prevent any inconsistency and you see a foreign key constraint exception. I Think it is the best way you can check out what you want. Otherwise, you should query manually for any related Table.
try {
userType = (Type) session.load(Type.class, id);
session.delete(userType);
/**
* or JDBCException
* e.getCause()
* e.getErrorCode() - vendor-specific
*/
} catch (HibernateException e) {
// checkout Exception right here e.getCause();
}
All exceptions thrown by Hibernate are fatal. This means you have to roll back the database transaction and close the current Session. So you may want To open a new session.
use native SQL with Hibernate together:
boolean canDeleteType(ind type_id){
Session s = HibernateUtil.getSessionFactory();
s.beginTransaction();
Query q = s.createQuery("SELECT User.type_id From User");
List l = q.list();
if(l.contains(type_id){
return false;
}
return false;
}
and do the same for your City table too.