Getting inserted ID after INSERT ... SELECT on Oracle - oracle

This SQL statement works if I run it from my Oracle client (SQL Developer):
insert into Person (Name) select 'Bob' from dual
It also works if I issue it via Spring JDBC, without using a KeyHolder:
final PreparedStatementCreator psc = new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException
{
return con.prepareStatement(
"insert into Person (Name) select 'Bob' from dual");
}
};
jdbcOperations.update(psc);
However I need to use a KeyHolder in order to get the ID of the newly inserted row. If I alter the above code to use a KeyHolder as follows:
final KeyHolder keyHolder = new GeneratedKeyHolder();
final PreparedStatementCreator psc = new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException
{
return con.prepareStatement(
"insert into Person (Name) select 'Bob' from dual",
new String[] {"PersonID"});
}
};
jdbcOperations.update(psc, keyHolder);
... then I get this error:
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:94)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:602)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:842)
at au.com.bisinfo.codecombo.logic.ImportServiceImpl.insertLoginRedirectRule(ImportServiceImpl.java:107)
at au.com.bisinfo.codecombo.logic.ImportServiceImpl.runImport(ImportServiceImpl.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy8.runImport(Unknown Source)
at au.com.bisinfo.codecombo.ui.Main.main(Main.java:39)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1008)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3530)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:844)
at org.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:1)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
... 15 more
FWIW, everything's fine if I do an INSERT ... VALUES instead of an INSERT ... SELECT (although this doesn't help me, as I need to select things):
final KeyHolder keyHolder = new GeneratedKeyHolder();
final PreparedStatementCreator psc = new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException
{
return con.prepareStatement(
"insert into Person (Name) values ('Bob')",
new String[] {"PersonID"});
}
};
jdbcOperations.update(psc, keyHolder);
I'm using:
Spring JDBC 3.0.3.RELEASE
JDBC driver: ojdbc6.jar version 11.2.0.1.0
RDBMS: Oracle9i Release 9.2.0.5.0 - Production
commons-dbcp 1.4
N.B. my app needs to use standard SQL in order to remain db-neutral, which rules out any Oracle-specific SQL (I won't be selecting from "dual" in real life).
Thanks for any help.

java.sql.Connection.prepareStatement(java.lang.String, int) interface is clear
Creates a default PreparedStatement object that has the capability to retrieve auto-generated keys
So you are using The wrong method. Try
return con.prepareStatement(
"insert into Person (Name) select 'Bob' from dual",
Statement.RETURN_GENERATED_KEYS);
instead

How about
INSERT INTO blah b (blah1, blah2, blah3)
VALUES (?, ?, ?) RETURNING b.id INTO ?";

This feature isn't supported by Oracle JDBC Driver

I suspect using a KeyHolder with an INSERT SELECT statement isn't and won't be supported because the select could theoretically select multiple rows, and if it did there would be no way to return those multiple keys into a single KeyHolder. For what you are trying to accomplish, it will likely be easier to simply use a select statement followed by an insert statement.

Related

How to use JPA or JDBC to call specific PL/SQL function using REF CURSOR

My problem is that I want to call PL/SQL function in #PostConstruct method in Spring Boot.
This function returns information about tables in a database as you can see above:
CREATE OR REPLACE FUNCTION dbINFO
return sys_refcursor AS
table_info sys_refcursor;
begin
open table_info
for select table_name from all_tables where owner = 'HOMEUSER';
return table_info;
end;
I tried to use #NamedStoreProcedureQuery annotation but I don't have entity to use it with.
So I decided to try doing it with JDBC and so far I've got something like this.
private EntityManager entityManager;
public HospitalApplication(EntityManager entityManager) {
this.entityManager = entityManager;
}
#PostConstruct
private void init() throws SQLException {
System.out.println("\n\n\n\n\n\n");
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
Connection connection = info.getDataSource().getConnection();
CallableStatement stmt = connection.prepareCall("BEGIN dbINFO(); END;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = ((OracleCallableStatement)stmt).getCursor(1);
while (rs.next()){
System.out.println(rs.getString(1));
}
rs.close();
stmt.close();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
}
Problem is, my program is throwing java.sqlException about column has incorrect index.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hospitalApplication': Invocation of init method failed; nested exception is java.sql.SQLException: Incorrect column index
***EDIT****
I tried something like that and I am receiving error:
PLS-00905: obiekt HOMEUSER.DBINFO is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
#PostConstruct
private void init() throws SQLException {
System.out.println("\n\n\n\n\n\n");
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
Connection connection = Objects.requireNonNull(info.getDataSource()).getConnection();
CallableStatement stmt = connection.prepareCall("{ ? = call dbINFO()}");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = (ResultSet) stmt.getObject(1);
while (rs.next()){
System.out.println(rs.getCursorName());
}
rs.close();
stmt.close();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
}

Derby DB: Table/View doesn't exist ERROR 42X05

I installed a Derby DB and I opened a connection named "MyDbTest".
I created a table named BOOK for "MyDbTest" connection by the SQL command:
CREATE TABLE BOOK(ID INT, DESCRIPTION VARCHAR(20), UNITCOST VARCHAR(20), ISBN VARCHAR(20), NBOFPAGES INT);
I ran the Derby server by using the command: "startNetworkServer.bat"
I ran the following code (using Open JPA):
public class Main {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
System.out.println("\n\n>>> Executing : " + Main.class.toString() + " <<<\n");
persistBook(new Book(new Long(5000), "H2G2", "Best IT Scifi Book", new Float(12.5), "1234-5678-5678",
new Integer(247)));
Book book = findBook(new Long(5000));
System.out.println("# " + book);
}
/**
* Gets a database connection
*/
static {
try {
Class.forName("org.apache.derby.jdbc.ClientDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:derby://localhost:1527/MyDbTest;create=true", "app", "app");
}
/**
* Persists the book to the database
*/
private static void persistBook(Book book) throws SQLException {
String query = "INSERT INTO BOOK (ID, TITLE, DESCRIPTION, UNITCOST, ISBN, NBOFPAGE) VALUES (?, ?, ?, ?, ?, ?)";
try (PreparedStatement stmt = getConnection().prepareStatement(query)) {
stmt.setLong(1, book.getId().longValue());
stmt.setString(2, book.getTitle());
stmt.setString(3, book.getDescription());
stmt.setFloat(4, book.getUnitCost().longValue());
stmt.setString(5, book.getIsbn());
stmt.setInt(6, book.getNbOfPage().intValue());
stmt.executeUpdate();
}
}
}
and I got an Error:
Exception in thread "main" java.sql.SQLSyntaxErrorException:
Table/View 'BOOK' does not exist.
Caused by: ERROR 42X05: Table/View 'BOOK' does not exist.
I also read the solution proposed in this post: Is it necessary to create tables each time you connect the derby database?.
Unfortunately, none of them helped me.
I changed "jdbc:derby://localhost:1527/MyDbTest;create=true" to "jdbc:derby://localhost:1527/MyDbTest;create=false"
I don't use "in-memory" configuration in Derby.
I don't think I connect to the DB as another user (I'm not sure about it. How can I check it?).
I had this error because I was using the database name in the SELECT statement instead of the name of the table.

Spring JdbcTemplate and oracle arrayofnumber

I'm using Spring and Oracle database in my solution and i need to execute script
select count(1) from ELEMENTS, table(cast(? as arrayofnumbers)) session_ids
where root_session_id in session_ids.VALUE
but i have a problem with passing input parameter.
i try to pass List or array of BigInteger into
JdbcTemplate.queryForObject("select count(1) from ELEMENTS, table(cast(? as arrayofnumbers)) session_ids
where root_session_id in session_ids.VALUE", Integer.class, INPUT_PARAMS)
but has an Exception:
java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8861)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8338)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9116)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:9093)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:234)
at weblogic.jdbc.wrapper.PreparedStatement.setObject(PreparedStatement.java:357)
Does anyone have the same problem?
EDIT:
Forget to describe arrayofnumber. It's custom type:
TYPE arrayofnumbers as table of number(20)
Found the solution:
final BigInteger[] ids = new BigInteger[]{BigInteger.valueOf(9137797712513092132L)};
int count = jdbc.query("select count(1) from NC_DATAFLOW_ELEMENTS\n" +
" where root_session_id in (select /*+ cardinality(t 10) */ * from table(cast (? as arrayofnumbers)) t)"
, new PreparedStatementSetter() {
public void setValues(PreparedStatement preparedStatement) throws SQLException {
Connection conn = preparedStatement.getConnection();
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
oracle.sql.ARRAY widgets = oraConn.createARRAY("ARRAYOFNUMBERS", ids);
preparedStatement.setArray(1, widgets);
}
}, new ResultSetExtractor<Integer>() {
public Integer extractData(ResultSet resultSet) throws SQLException, DataAccessException {
resultSet.next();
return resultSet.getInt(1);
}
});
out.println(count);
should note that type of array (ARRAYOFNUMBER) should be in upper case

Can not handle hibernate exceptions inside #Transactional methods in Spring app

I have a question. I use Spring+Hibernate and I can't handle exceptions in methods marked as #Transactional. Previously, when I used Spring JDBC everything worked just fine.
DAO classes are marked with #Repository.
Here is snipper of my old code.
in service:
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public boolean bookTickets(Integer userId, List<Integer> ticketsId) throws TicketsServiceException {
Integer currId = null;
try {
for (Integer ticketId : ticketsId) {
currId = ticketId;
Ticket ticket = ticketDAO.getTicketById(ticketId);
bookingDAO.bookTicket(ticket, userId);
}
} catch (DuplicateKeyException e) {
throw new TicketsServiceException(String.format(MESSAGE_TICKET_ALREADY_BOOKED, currId));
} catch (EmptyResultDataAccessException e) {
throw new TicketsServiceException(String.format(MESSAGE_NO_SUCH_TICKET, currId));
}
return true;
in dao:
#Transactional(propagation = Propagation.MANDATORY)
public void bookTicket(Ticket ticket, final int userId) {
MapSqlParameterSource map = new MapSqlParameterSource();
map.addValue(Constants.TABLE_BOOKING.FIELD_TICKET_ID, ticket.getId());
map.addValue(Constants.TABLE_BOOKING.FIELD_USER_ID, userId);
int rowsAffected = template.update(QUERY_INSERT_BOOKING, map);
if (LOG.isTraceEnabled()) {
LOG.trace("Affected " + rowsAffected + " rows.");
}
}
Now I'm moving my DAO from Spring JDBC onto hibernate 3.
That's what I have now.
in service:
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public boolean bookTickets(Integer userId, List<Integer> ticketsId) throws TicketsServiceException {
Integer currId = null;
try {
for (Integer ticketId : ticketsId) {
currId = ticketId;
Ticket ticket = ticketDAO.getTicketById(ticketId);
bookingDAO.bookTicket(new Booking(ticketId, userId));
}
} catch (Exception e) {
throw new TicketsServiceException(String.format(MESSAGE_THERE_IS_NO_SUCH_TICKET_OR_ALREADY_BOOKED, currId));
}
return true;
}
in dao:
#Override
public void bookTicket(Booking booking) {
getHibernateTemplate().save(booking);
}
The problem is that I can't handle exceptions inside try-catch block in service method. They are throwing directly into my controller.
I think the problem is in difference between transaction managers org.springframework.jdbc.datasource.DataSourceTransactionManager in Spring JDBC and org.springframework.orm.hibernate3.HibernateTransactionManager in hibernate, but I dont have any ideas how to overcome this problem, so I need your help.
AFTER UPDATE. ADDED EXAMPLE OF EXCEPTION.
2013-10-21 14:51:17 ERROR BookingController:89 - Unhandled exception
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?)]; constraint ["CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"; SQL statement:
insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?) [23505-173]]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at cdp.tarasenko.springmvc.task3.service.TicketsService$$EnhancerByCGLIB$$fabdc899.bookTickets(<generated>)
at cdp.tarasenko.springmvc.task3.controller.BookingController.bookTickets(BookingController.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:594)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:486)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
at org.eclipse.jetty.server.Server.handle(Server.java:351)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:900)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:954)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:857)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:77)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:609)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:45)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534)
at java.lang.Thread.run(Thread.java:662)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
... 51 more
Caused by: org.h2.jdbc.JdbcBatchUpdateException: Нарушение уникального индекса или первичного ключа: "CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"
Unique index or primary key violation: "CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"; SQL statement:
insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?) [23505-173]
at org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1167)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 59 more
Is there any ways to handle exceptions inside service layer?
Thank you.
Take a look of hibernate FlushMode
Default HiberanateTemplate FlushMode is FlusMode.AUTO, so session synchronization will occur on commit or before some queries to prevent stale state.
You could change HibernateTemplate flush mode to FlushMode.ALWAYS, inefficient and not recomended (but will work as you expect now), or call Session.flush() at some points.
see HiberanateTemplate.setFlushMode() and Session.flush()
You don't get DB exceptions like constraint violations before committing the TX and TX gets committed in transaction manager. The best solution would be handling TX manager exceptions using an afterThrowing aspect (AOP). Alternatively, you can call your #Transactional methods inside another non-transactional method in your service and have it catch the exceptions. Personally, I don't like the later as you will have to create a wrapper method for all your services.
Or you can invoke your transactional code in explicit transaction mode.
E.g.
//No #transactional here
public void service() {
PlatformTransactionManager txManager= ...;
TransactionStatus tx = txManager.getTransaction(new DefaultTransactionDefinition());
try{
.... do something
txManager.commit(tx);
}catch(DataAccessException ex){
txManager.rollback(tx);
... handle error
}
}

hive jdbc throws "Error running query: java.lang.NullPointerException"

FROM cr_expanded_crcs_halen c INSERT OVERWRITE TABLE merge_result SELECT 'crcs', operator_id, instance_id, ts, user, application, actualconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
I try to insert data to table merge_result using above sql with jdbc, found errors as below
Exception in thread "main" java.sql.SQLException: Error running query: java.lang.NullPointerException
at org.apache.hive.jdbc.Utils.verifySuccess(Utils.java:159)
at org.apache.hive.jdbc.Utils.verifySuccessWithInfo(Utils.java:147)
at org.apache.hive.jdbc.HiveStatement.execute(HiveStatement.java:182)
at org.apache.solr.handler.dataimport.scheduler.HiveClient.main(HiveClient.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
but the data has been inserted successfully.
Any body can help me ?
I have had the same error.
Unfortunately, I can't found why it's failing, but I found a workaround.
The problem occurs when you use the word NULL into a select statement thought JDBC, My ugly solution was replace NULL by an udf "null_value()"
I will open a jira with this problem
#Description(name="null_value", value="_FUNC() return null")
#UDFType(deterministic=true, stateful=false)
public class NullValue extends GenericUDF {
#Override
public ObjectInspector initialize(ObjectInspector[] arguments)
throws UDFArgumentException {
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
#Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
return null;
}
#Override
public String getDisplayString(String[] children) {
return "keys_to_lower_"+children[0];
}
}
Thanks,
Gabo

Resources