问题
In my code I am doing a batch insert. For an example think that I have five rows to insert, and one of those fails when inserting. Then hibernate prevent inserting all the rows.
In my case I want to insert other four records which contains no errors. Is this possible in Hibernate?
Following is a simplified version of my code.
void save() {
Session session1 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session1.beginTransaction();
for (int i = 0; i < 5; i++) {
BatchSizeConf r = new BatchSizeConf();//This is my entity
r.setId(i);
r.setDispatchType("Disp");
r.setBatchSize(500);
Serializable z = session1.save(r);
System.out.println(z);//prints ids
}
session1.flush();
session1.clear();
session1.getTransaction().commit();
session1.close();
}
EDIT:
According to following answers below I changed my code and solved my main problem. Now my code is like this.
void save() {
for (int i = 0; i < 5; i++) {
Session session1 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session1.beginTransaction();
BatchSizeConf r = new BatchSizeConf();//This is my entity
r.setId(i);
r.setDispatchType("Disp");
r.setBatchSize(500);
try {
session1.save(r);
transaction.commit();
} catch (HibernateException e) {
System.out.println("Failed: " + i);
}
session1.flush();
session1.clear();
session1.close();
}
}
I Now I have another two questions.
- Is it ok to create multiple session objects like above? (I have more than 100000 records.)
- Do I need to call
flush(),clear()andclose()methods as above?
回答1:
You can do something like this
Transaction tx = session.beginTransaction();
...
for (BatchSizeConf b: BatchSizeConfList) {
...
tx.commit();
}
Refer Avaoid transaction exception
回答2:
That's not possible, transaction will be marked as rollback by any exception.
Why don't chipped rows into chunks and set single transaction per each chunk?
Take a look this docs transactions-demarcation-exceptions
If the Session throws an exception, including any SQLException, immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block.
回答3:
Yes.. We can do.. See this code.
public List<RecordErrorStatus> persistBatch(ArrayList<?> domainRecords) {
List<RecordErrorStatus> fedRecordErrorStatusList = new ArrayList<RecordErrorStatus>();
Session session = getSession();
Transaction tx = session.beginTransaction();
long rowCount = 0;
boolean insertionFailed=false;
for (Object object : domainRecords) {
rowCount++;
try {
System.out.println("Inserting Record:"+rowCount+object);
session.persist(object); // Persist the given transient instance
if (! this.rollBackOnFail) {
tx.commit();
tx = session.beginTransaction();
}
} catch (Exception e) {
e.printStackTrace();
RecordErrorStatus feedRecordStatus = new RecordErrorStatus();
feedRecordStatus.setRowNumber(String.valueOf(rowCount));
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
feedRecordStatus.setErrorDescription(exceptionAsString);
fedRecordErrorStatusList.add(feedRecordStatus);
insertionFailed =true;
tx.rollback(); //Rollback the current record..
session.clear();//Clear the seesion.. If not, throws Nested Transaction not allowd...
tx = session.beginTransaction();//Start again..
}
}
if (this.rollBackOnFail && insertionFailed && ! tx.wasRolledBack()) {
tx.rollback();
System.out.println("Rollback");
}
return fedRecordErrorStatusList;
}
来源:https://stackoverflow.com/questions/15170049/in-batch-insert-how-to-continue-inserting-other-rows-when-an-error-occurred-in