How to get information about error from SqlExceptionHelper for REST spring application - spring

I have some tables in my database and I want to get information about wrong requests to the database. In case If I'm trying to save entity with wrong foreigns keys, I want to get detail information about these keys.
For example:
2020-03-25 18:37:37.595 ERROR 9788 --- [nio-8090-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: insert or update on table "student" violates foreign key constraint "student_fkey_to_specialty"
Detail: Key (specialtykey)=(2) is not present in table "specialty".
I tried to solve with this code, but I get other information.
could not execute statement; SQL [n/a]; constraint [student_fkey_to_specialty]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
my code:
#PostMapping
public void saveStudent(#RequestBody StudentDTO studentDTO) {
if(studentDTO!=null){
try {
studentService.save(studentDTO);
}catch (Exception|Error e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getLocalizedMessage(),e );
}
}
}

Use a loop to iterate to the original exception,
here a example function that does that:
private String getCauseMessage(Throwable t)
Throwable cause = t;
while (t.getCause() != null) {
cause = t.getCause();
}
return t.getLocalizedMessage();
}
As you never know how many exception might be chained together, using a loop is the safest way. If you just use it directly you risk getting a NullPointerException or
not getting the message of the original exception.

Student table is having "student_fkey_to_specialty" which is getting violated. Check on which filed this constraint is and provide the correct value for that field

I solved this problem with this code. This allows getting information about exceptions from the database.
e.getCause().getCause().getLocalizedMessage()

Related

LockForUpdate causes Deadlock if table is empty

Currently I am trying to upload some images parallel with dropzone.js.
This is part of the code, that handles the upload.
\DB::beginTransaction();
$maxPos = GalleryImage::lockForUpdate()->max('pos');
try {
// some other code
// ....
$galleryImage->pos = $maxPos + 1;
$galleryImage->save();
} catch (\Exception $e) {
\DB::rollBack();
\Log::error($e->getMessage());
return response('An error occured', 500);
}
\DB::commit();
If I do not use the lockForUpdate() I end up with duplicate positions in database.
The problem with above solution ist, that if the table is empty I get the error:
Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
But only for the second image I am uploading.
Additionally the autoincrement id skips the value 2 and goes like 1,3,4,5,6,7, ...
The Positions in the table are shown correctly 1,2,3,4....
I think the problem has to do with the table beeing empty initially, as I did not notice this problem, when there are already some entries in the table.
Any suggestions what I am doing wrong? Or Maybe using lockForUpdate() in combination with an aggregate function is wrong at all...
I recommend a different approach to transactions.
try {
app('db')->transaction(function ()) {
$maxPos = GalleryImage::lockForUpdate()->max('pos');
// other code (...)
$galleryImage->pos = $maxPos + 1;
$galleryImage->save();
}
} catch (\Exception $e) {
// display an error to user
}
Should any exception occurs inside the callback, the transaction will rollback and free any locks.

DB2 SQL Error: SQLCODE=-270 exception thrown by jpa paging item reader

I have created a spring batch service with a item reader, item processor and item writer.I have extended the AbstractPagingItemReader and created my own implementation by the name of JpaPagingItemReader.Now when I ran the batch service the reader reads a fix set of records from db (default page size: 10),processes them and writes them.However on second read it throws me the below exception:
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-270, SQLSTATE=42997, SQLERRMC=63, DRIVER=3.61.65
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-270;42997;63, DRIVER=3.61.65
2015-06-25 16:33:00,712 ERROR [jobLauncherTaskExecutor-6][saeedh:120659] org.hibernate.util.JDBCExceptionReporter : DB2 SQL Error: SQLCODE=-727, SQLSTATE=56098, SQLERRMC=2;-270;42997;63, DRIVER=3.61.65
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-270, SQLSTATE=42997, SQLERRMC=63, DRIVER=3.61.65
at com.ibm.db2.jcc.am.ed.a(ed.java:676)
at com.ibm.db2.jcc.am.ed.a(ed.java:60)
at com.ibm.db2.jcc.am.ed.a(ed.java:127)
at com.ibm.db2.jcc.am.gn.c(gn.java:2554)
at com.ibm.db2.jcc.am.gn.d(gn.java:2542)
at com.ibm.db2.jcc.am.gn.a(gn.java:2034)
at com.ibm.db2.jcc.am.hn.a(hn.java:6500)
at com.ibm.db2.jcc.t4.cb.g(cb.java:140)
at com.ibm.db2.jcc.t4.cb.a(cb.java:40)
at com.ibm.db2.jcc.t4.q.a(q.java:32)
at com.ibm.db2.jcc.t4.rb.i(rb.java:135)
I get that this error is probably because there is a CLOB column in the table from where I am reading records but the weird thing is it reads the first batch of 10 records fine,process them and write them but on second time read it throws the above exception.Any suggestions?Below is a snippet from JpaPagingItemReader that I wrote.The override doReadPage method from AbstractPagingItemReader.java.
protected void doReadPage ()
{
setPageSize (10);
// Flush we already have in entity manager
getEntityManager ().flush ();
// clear the entity manager: To read and detach
getEntityManager ().clear ();
Query query = createQuery ().setFirstResult (getPage () * getPageSize ()).setMaxResults (getPageSize ());
if (parameterValues != null)
{
for (Map.Entry<String, Object> me : parameterValues.entrySet ())
{
query.setParameter (me.getKey (), me.getValue ());
}
}
if (results == null)
{
results = new CopyOnWriteArrayList<T> ();
}
else
{
results.clear ();
}
results.addAll (query.getResultList ());
// Detach all objects that became part of persistence context
getEntityManager ().clear ();
}
Any help is highly appreciated as I already behind deadline due to this issue.Please if you think any thing is missing,do let me know and I will update the question.Thanks.
I figured it out.The issue was indeed that we are not allowed to have Clob data as a projection in a scrollable JPA cursor.The first 10 records are read just fine but as soon as It starts to read the second batch it has to move the cursor from 0 to the 11th record.That is when I was getting sql exception.
Simple fix was to remove the CLOB column from the select statement and get it in a separate query where its value is required.That fixed my problem.Thanks.

Native Query With Spring's JdbcTempate

I'm using spring's JdbcDaoSupport for making data base call. I want to execure native query (sql query) for retrieving data. Do we have any API available in JdbcTemplate for native query? I used queryForObject but it throws exception if there is no data whereas i was expecting it to return back null if it couldn't find data.
There are many options available for executing native sql with JdbcTemplate. The linked documentation contains plenty of methods that take native sql, and usually some sort of callback handler, which will accomplish exactly what you are looking for. A simple one that comes to mind is query(String sql, RowCallbackHandler callback).
jdbcTemplate.query("select * from mytable where something > 3", new RowCallbackHandler() {
public void processRow(ResultSet rs) {
//this will be called for each row. DO NOT call next() on the ResultSet from in here...
}
});
Spring JdbcTemplate's queryForObject method expects your SQL to return exactly one row. If the there are no rows returned or if there are more than 1 row returned it will throw a org.springframework.dao.IncorrectResultSizeDataAccessException. You will have to wrap the call to queryForObject with a try catch block to handle IncorrectResultSizeDataAccessException and return null if the exception is thrown
e.g.
try{
return jdbcTemplate.queryForObject(...);
}catch(IncorrectResultSizeDataAccessException e){
return null;
}

About Spring Transaction Manager

Currently i am using spring declarative transaction manager in my application. During DB operations if any constraint violated i want to check the error code against the database. i mean i want to run one select query after the exception happened. So i am catching the DataIntegrityViolationException inside my Catch block and then i am trying to execute one more error code query. But that query is not get executed . I am assuming since i am using the transaction manager if any exception happened the next query is not getting executed. Is that right?. i want to execute that error code query before i am returning the results to the client. Any way to do this?
#Override
#Transactional
public LineOfBusinessResponse create(
CreateLineOfBusiness createLineOfBusiness)
throws GenericUpcException {
logger.info("Start of createLineOfBusinessEntity()");
LineOfBusinessEntity lineOfBusinessEntity =
setLineOfBusinessEntityProperties(createLineOfBusiness);
try {
lineOfBusinessDao.create(lineOfBusinessEntity);
return setUpcLineOfBusinessResponseProperties(lineOfBusinessEntity);
}
// Some db constraints is failed
catch (DataIntegrityViolationException dav) {
String errorMessage =
errorCodesBd.findErrorCodeByErrorMessage(dav.getMessage());
throw new GenericUpcException(errorMessage);
}
// General Exceptions handling
catch (Exception exc) {
logger.debug("<<<<Coming inside General >>>>");
System.out.print("<<<<Coming inside General >>>>");
throw new GenericUpcException(exc.getMessage());
}
}
public String findErrorCodeByErrorMessage(String errorMessage)throws GenericUpcException {
try{
int first=errorMessage.indexOf("[",errorMessage.indexOf("constraint"));
int last=errorMessage.indexOf("]",first);
String errorCode=errorMessage.substring(first+1, last);
//return errorCodesDao.find(errorCode);
return errorCode;
}
catch(Exception e)
{
throw new GenericUpcException(e.getMessage());
}
}
Please help me.
I don't think problem you're describing has anything to do with Transaction management. If DataIntegrityViolationException happens within your try() block you code within catch() should execute. Perhaps exception different from DataIntegrityViolationException happens or your findErrorCodeByErrorMessage() throwing another exception. In general, Transaction logic would be applied only once you return from your method call, until then you could do whatever you like using normal Java language constructs. I suggest you put breakpoint in your error error handler or some debug statements to see what's actually happening.

LinqToSql update problem when switching parents

I am trying to perform a straighforward update using LinqToSQL, and just cannot get it to work.
Here's the data model: there is a timesheet_entry and customer. One customer has many timesheet_entries. It's a simple foreign key relationship.
If I'm editing an existing timesheet_entry, I get an exception if I change the customer_id.
Here's my attempt at the code. Can someone help me out here?
internal void CommitChangesToEntry(Timesheet_Entry entry)
{
Timesheet_Entry latest = (from e
in m_dataContext.Timesheet_Entries
where e.Timesheet_Entry_ID == entry.Timesheet_Entry_ID
select e).First();
latest.Entry_Start_DateTime = entry.Entry_Start_DateTime;
latest.Entry_End_DateTime = entry.Entry_End_DateTime;
latest.Task_Description = entry.Task_Description;
// Comment out this line of code and it
// doesn't throw an exception
latest.Customer_ID = entry.Customer_ID;
m_dataContext.SubmitChanges(); // This throws a NotSupportedException
}
The error is: "An attempt has been made to attach or add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported".
Do you have any reason for not using the Attach method? Like the following:
m_dataContext.Timesheet_Entries.Attach(entry);
m_dataContext.SubmitChanges();

Resources