Mybatis: java.sql.SQLRecoverableException: Closed Statement - java

when I use Mybatis execute query sql for oracle database, it sometimes throw the exception:
org.springframework.dao.RecoverableDataAccessException:
### Error querying database. Cause: java.sql.SQLRecoverableException: Closed Statement
### The error may exist in com/mapper/TestMapper.xml
### The error may involve com.mapper.TestMapper.getList
### The error occurred while handling results
### SQL: SELECT * FROM person_view
the xml config for the query:
<select id="getList" resultType="com.domain.TestBean" parameterType="map">
select * from person_view where rownum < #{limit}
</select>
when the query time > 60s, it will throw the exception, however I can't find any query time limit in my mybatis configuration and connection pool configuration. Any ideas, thanks in advance.

Related

Spring Boot: Handle Raised Exception from Database Trigger

I have a requirement to prevent the update action for ceratin columns in the table and display the message. I am using the liquibase to manage the database schema. To achieve this I used the Trigger Functions and Triggers which works fine.
Function
CREATE OR REPLACE FUNCTION FN_BU_CATEGORY() RETURNS trigger
LANGUAGE plpgsql AS
$$BEGIN
IF NEW.created_by <> OLD.created_by THEN
RAISE EXCEPTION 'Not allowed to update the value of created_by';
END IF;
RETURN NEW;
END;$$;
Trigger:
CREATE TRIGGER TR_BU_CATEGORY
BEFORE UPDATE ON category FOR EACH ROW
EXECUTE PROCEDURE FN_BU_CATEGORY();
I am managing the exception handling using #ControllerAdvice and #ExceptionHandler with PSQLException.class, GenericJDBCException.class, JpaSystemException.class and I was able to handle the exception. To verify the functionality, when I make an API hit to update the values of restricted columns, trigger raised the exception and I can see the following in the console.
handleTriggerException
#ExceptionHandler({PSQLException.class, GenericJDBCException.class, JpaSystemException.class})
public ResponseEntity<Problem> handleTriggerException(Exception ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.withStatus(Status.BAD_REQUEST)
.withDetail("Test Message " + ex.getMessage())
.build();
return create(ex, problem, request);
}
Console:
Hibernate: update category set created_by = 'abc' where id = 1234
19:37:49.126 [XNIO-1 task-9] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: P0001
19:37:49.127 [XNIO-1 task-9] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: Not allowed to update
the value of created_by
Where: PL/pgSQL function noupdate() line 3 at RAISE
.......
org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is
org.hibernate.exception.GenericJDBCException: could not execute statement
Caused by: org.postgresql.util.PSQLException: ERROR: Not allowed to update the value of created_by
Where: PL/pgSQL function noupdate() line 3 at RAISE
Question is
Currently, ex.getMessage() returns org.hibernate.exception.GenericJDBCException: could not execute statement.
How can I fetch the message described in the trigger (i.e PSQLException: Not allowed to update
the value of created_by)
If I remove the JpaSystemException, handleTriggerException does not work anymore, why?
Environment:
Framework: Spring Boot
ORM: Hibernate
Database: Postgres 11
UPDATE:
I have tried to get a message with the following methods but unfortunately, they all return the same message.
System.out.println("1: " +ex.getCause());
System.out.println("2: " +ex.getMessage());
System.out.println("3: " +ex.getLocalizedMessage());
System.out.println("4: " +ex.fillInStackTrace());
System.out.println("5: " +ex.getStackTrace());
1: org.hibernate.exception.GenericJDBCException: could not execute statement
2: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
3: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
4: org.springframework.orm.jpa.JpaSystemException: could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
5: [Ljava.lang.StackTraceElement;#6f3072be
Using ExceptionUtils with getRootCause(throwable) gives the root cause message.
#ExceptionHandler({PSQLException.class, GenericJDBCException.class, JpaSystemException.class})
public ResponseEntity<Problem> handleTriggerException(Exception ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.withStatus(Status.BAD_REQUEST)
.withDetail(ExceptionUtils.getRootCause(ex).getMessage())
.build();
return create(ex, problem, request);
}
How to get root cause message?

SQL Server query throws Deadlock Exception on rs.next

We run a SELECT statement using preparedStatement.executeQuery on a SQL Server database. The query fails with a deadlock exception which is expected. The problem here is, the exception is not thrown on the executeQuery but thrown while we are doing rs.next() ie., while reading the result set. Is there any reason for this behaviour? What can we do to make it throw the exception on executeQuery?
Driver jar - sqljdbc4 - 4.0.2206.100
Java version - 1.8
Query Executed: SELECT Col1 from Table1 where Col2 = ?
Error trace:
com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 66) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:217)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet$FetchBuffer.nextRow(SQLServerResultSet.java:6357)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.fetchBufferNext(SQLServerResultSet.java:1798)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.next(SQLServerResultSet.java:1049)

org.springframework.dao.CannotAcquireLockException for select sql query

I am getting org.springframework.dao.CannotAcquireLockException for select statment. Not sure why spring is trying to put lock for select query.
I am using NamedParameterJdbcTemplate and performing queryforlist. Its all select statements so we are not using and transactions. This database is shared so it might possible there are other application who are writing or performed lock but my app is just read.
This is MS SQL Server.
I am getting exception after 3 secs so looks like spring is trying to get lock and waited for 3 sec and then throws exception.
Below is full exception.
org.springframework.dao.CannotAcquireLockException: PreparedStatementCallback; SQL [select id ticketDBId from fpscdb002_ws_004.incident where ticket_number = ?]; Lock request time out period exceeded.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: Lock request time out period exceeded.
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:259)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:722)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:772)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:211)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForMap(NamedParameterJdbcTemplate.java:238)
at com.abc.servicedesk.fp.dao.FPBaseDAO.getTicketDbId(FPBaseDAO.java:44)

Record inserted but still not found

I was currently using java spring jdbctemplate to insert and select record. However, Now the system have go for production, some issue has happen. This system will prevent record duplicate by select the record by certain key to check is it already exist. However, I notice the 1st transaction after inserted into database, then the 2nd transaction come in, jdbc template select still show that record was not found? I notice this will happen if the 2 transaction was submitted within a milliseconds different...
The record time was
e.g.
1st Record insert - 15/6/17 12:22:39,986 - insert success
2nd record select - 15/6/17 12:22:44,680 - search record show not found?
Sample insert log
15/6/17 12:22:39,937 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:869) Executing prepared SQL update
15/6/17 12:22:39,938 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:616) Executing prepared SQL statement [INSERT INTO ...;]
15/6/17 12:22:39,950 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:879) SQL update affected 1 rows
15/6/17 12:22:39,951 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:869) Executing prepared SQL update
15/6/17 12:22:39,952 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:616) Executing prepared SQL statement [INSERT INTO ...;]
15/6/17 12:22:39,965 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.core.JdbcTemplate:879) SQL update affected 1 row
15/6/17 12:22:39,970 DEBUG [30:http-nio-8080-exec-2] (org.springframework.jdbc.datasource.DataSourceUtils:327) Returning JDBC Connection to DataSource
Sample select log
15/6/17 12:22:44,680 DEBUG [29:http-nio-8080-exec-1] (org.springframework.jdbc.core.JdbcTemplate:682) Executing prepared SQL query
15/6/17 12:22:44,680 DEBUG [29:http-nio-8080-exec-1] (org.springframework.jdbc.core.JdbcTemplate:616) Executing prepared SQL statement [SELECT * FROM ...]
Please note that this system was set in 2 different server by using load balancing. They both point to the same database. The insert was completed on server 1 because it already return the connection to the jdbc connection pool. A new transaction come in the server 2, select but no record found?
I wonder why it still cannot found event after insert was finish? Is it because of the time delay?
This question had been resolved. It was due to the server time not consistent. Thanks
RealSkeptic

Resource governor for 'prepared statements' exceeded

We are using Spring JDBCTemplate 2.5 version and getting below exception when used batchupdate method.
Exception thrown!
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [SELECT SERVICE WHERE CREATE_TIME >= ? AND CREATE_TIME < ?]; SQL state [HY000]; error code [-685]; [Sybase][JDBC Driver][SQL Anywhere]Resource governor for 'prepared statements' exceeded; nested exception is java.sql.SQLException: [Sybase][JDBC Driver][SQL Anywhere]Resource governor for 'prepared statements' exceeded
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.translate(SQLStateSQLExceptionTranslator.java:124)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.translate(SQLErrorCodeSQLExceptionTranslator.java:322)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:607)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:641)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:670)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:678)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:710)
at org.springframework.jdbc.core.simple.SimpleJdbcTemplate.query(SimpleJdbcTemplate.java:187)
Could you please let me know if it is known issue? if so how to get it resolved.
From the documentation:
Applications that use prepared statements can receive the error "Resource governor for 'prepared statements' exceeded" if the prepared statements are not explicitly dropped once they are no longer required.
So you probably should review your code for non-closed prepared statement or adjust your sybase "max_statement_count" parameter. The later seems more likely as you are using JdbcTemplates

Categories