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
Related
We are trying to load data to google bigquery using Jdbc (Simba driver). When trying to insert a null value in a prepared statement, we are getting an exception. This works when it is not a prepared statement. For example, the code (with the connection Url hidden):
import java.sql.*;
public class Program {
public static void main(String[] args) {
Program program = new Program();
try {
program.doStatement();
} catch (Exception e) {
e.printStackTrace();
}
try {
program.doPreparedStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
public Program() {}
public void doPreparedStatement() throws Exception {
try(Connection connection = getConnection()) {
PreparedStatement statement = connection.prepareStatement("INSERT INTO test1.my_table (CONTACT, COMPANY, ADDRESS, CITY, STATE, ZIP) VALUES (?,?,?,?,?,?)");
statement.setString(1, "MyContact");
statement.setString(2, "MyCompany");
statement.setString(3, "MyAddress");
statement.setString(4, "MyCity");
statement.setString(5, "MyState");
statement.setNull(6, Types.BIGINT);
System.err.println("Executing prepared statement...");
int count = statement.executeUpdate();
}
System.err.println(" done.");
}
public void doStatement() throws Exception {
try(Connection connection = getConnection()) {
String create_command =
"CREATE TABLE test1.my_table ( CONTACT STRING, COMPANY STRING, ADDRESS STRING, CITY STRING, STATE STRING, ZIP STRING )";
Statement createStatement = connection.createStatement( );
System.err.println("Create table.");
createStatement.execute(create_command);
System.err.println("Table created.");
System.err.println("Executing statement...");
Statement statement = connection.createStatement();
int count = statement.executeUpdate("INSERT INTO test1.my_table (CONTACT, COMPANY, ADDRESS, CITY, STATE, ZIP) VALUES ('MyContact','MyCompany','MyAddress','MyCity','MyState',NULL)");
}
System.err.println(" done.");
}
private Connection getConnection() throws Exception
{
Connection connection = null;
connection = DriverManager.getConnection(CONNECTION_URL);
return connection;
}
}
Produces the following output:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Create table.
Table created.
Executing statement...
done.
Executing prepared statement...
java.sql.SQLException: [Simba][BigQueryJDBCDriver](100032) Error executing query job. Message: Unparseable query parameter `` in type `TYPE_INT64`, Bad int64 value: null value: 'null'
at com.simba.googlebigquery.googlebigquery.client.BQClient.insertJob(Unknown Source)
at com.simba.googlebigquery.googlebigquery.client.BQClient.executeQuery(Unknown Source)
at com.simba.googlebigquery.googlebigquery.dataengine.BQAbstractExecutor.execute(Unknown Source)
at com.simba.googlebigquery.googlebigquery.dataengine.BQSQLExecutor.execute(Unknown Source)
at com.simba.googlebigquery.jdbc.common.SPreparedStatement.executeWithParams(Unknown Source)
at com.simba.googlebigquery.jdbc.common.SPreparedStatement.executeAnyUpdate(Unknown Source)
at com.simba.googlebigquery.jdbc.common.SPreparedStatement.executeUpdate(Unknown Source)
at Program.doPreparedStatement(Program.java:35)
Caused by: com.simba.googlebigquery.support.exceptions.GeneralException: [Simba][BigQueryJDBCDriver](100032) Error executing query job. Message: Unparseable query parameter `` in type `TYPE_INT64`, Bad int64 value: null value: 'null'
... 8 more
I've found this to work when adding BigQuery support to jOOQ (see e.g. #11841), for numeric types:
statement.setBigDecimal(6, null);
The BigDecimal type is the only numeric JDBC type that is not primitive. For other data types, use their respective setter if it is supported, or setString(6, null), if Simba still doesn't like NULL values for the respective type, including e.g.:
Boolean
Date
Time
If in doubt about any conversion problems (e.g. because Simba seems to bind BigDecimal as STRING, currently, at least in version 1.2.13.1016), make sure you cast the bind variable, e.g.:
CAST(? AS INT64)
I am trying to create stored procedure in derby database using java.
public class TestDrive {
public static void main (String[] args) throws SQLException, ClassNotFoundException{
Connection conn = null;
CallableStatement stmt = null;
try {
try{
Class.forName("org.apache.derby.jdbc.ClientDriver").;
} catch(ClassNotFoundException e){
System.out.println("Can't load the database driver");
return;
}
conn = DriverManager.getConnection("jdbc:derby://localhost:1527/Connections_DB", "Connections_DB", "KaayRey");
stmt = conn.prepareCall("CALL NameOFstoreProcedure4( ?, ? )");
stmt.setString(1, "Kitu");
stmt.setString(2, "KaayChalay");
stmt.execu`enter code here`te();
} finally {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
} //END OF CLASS TestDrive.java
TempSP.java Code:-
public class TempSP {
public static void NameOFSP(String uname, String upass)throws SQLException {
PreparedStatement stmt = null;
ResultSet res = null;
String message = null ;
try{
try{`enter code here`
Class.forName("org.apache.derby.jdbc.ClientDriver");
} catch(ClassNotFoundException e){
System.out.println("Can't load the database driver");
return;
}
String dbURL = "jdbc:derby://localhost:1527/Connections_DB";
Connection conn = DriverManager.getConnection(dbURL, "Connections_DB", "KaayRey");
Stri`enter code here`ng sql = "INSERT INTO USERS2(USER_NAME, USER_PASSWORD) VALUES(?, ?)";
stmt = conn.prepareStatement(sql);
stmt.setString(1, uname);
stmt.setString(2, upass);
int row = stmt.executeUpdate(sql);
}catch (SQLException ex) {
message = "ERROR 1 : " + ex.getMessage();
ex.printStackTrace();
}
}
} // END OD TempSP.java
But when I run run my TestDrive.java file it will gives me following error:-
"Exception in thread "main" java.sql.SQLSyntaxErrorException: The class 'TempSP' does not exist or is inaccessible. This can happen if the class is not public.
at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
at org.apache.derby.client.am.Connection.prepareCall(Unknown Source)
at FriendsConnectionPack.TestDrive.main(TestDrive.java:34)
Caused by: org.apache.derby.client.am.SqlException: The class 'TempSP' does not exist or is inaccessible. This can happen if the class is not public.
at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.parsePrepareError(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.parsePRPSQLSTTreply(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.readPrepare(Unknown Source)
at org.apache.derby.client.net.StatementReply.readPrepare(Unknown Source)
at org.apache.derby.client.net.NetStatement.readPrepare_(Unknown Source)
at org.apache.derby.client.am.Statement.readPrepare(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.readPrepareDescribeInput(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.flowPrepareDescribeInputOutput(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.prepare(Unknown Source)
at org.apache.derby.client.am.Connection.prepareCallX(Unknown Source)
... 2 more
Caused by: org.apache.derby.client.am.SqlException: Java exception: 'TempSP: java.lang.ClassNotFoundException'.
... 13 more
Java Result: 1
BUILD SUCCESSFUL (total time: 1 second)"
Derby Stored Procedure Code As Follows:-
CREATE PROCEDURE NameOFstoreProcedure5(User_Name VARCHAR(50), User_Password VARCHAR(20))
PARAMETER STYLE JAVA READS SQL DATA LANGUAGE JAVA EXTERNAL NAME
'FriendsConnectionPack.TempSP.NameOFSP'
I encountered the same problem and the solution was setting the stored procedure's code in a jar file and then using the derby's systems procedures to register the jar and setting the derby's class path as shown next
To add a jar to Derby:
CALL sqlj.install_jar('PATH TO JAR FILE', 'DATABASE.IDENTIFIER FOR THE JAR', 0)
To add the jar to derby's internal classpath
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(
'derby.database.classpath',
'colonSeparatedJarFiles')
Hope this helps someone
Using spring 4.0.6.RELEASE, Hibernate 4.3.6.Final and hsqldb 2.3.2. My integration test looks like the following;
#Test(expected = DataIntegrityViolationException.class)
public final void testDuplicateItems() {
final ServerEntity serverEntity1 = new ServerEntity("DuplicateItem");
opService.save(serverEntity1);
opService.save(serverEntity1);
}
This works as expected. However, when I run my standalone java component i can save the first item, the second item which is a duplicate is not saved but Im unable to catch the exception. Here is the log file
WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper: SQL Error: -104, SQLState: 23505
2014-08-27 14:52:06,843 ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper: integrity constraint violation: unique constraint or index violation; UK_NFU7LXMMDFVIR1WD08662085N table: SERVERENTITY
[WARNING]
java.lang.reflect.InvocationTargetException
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:606)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_NFU7LXMMDFVIR1WD08662085N]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:161)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:681)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:563)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy38.execute(Unknown Source)
at com.opserver.simpleapp.MainApp.start(MainApp.java:60)
at com.opserver.simpleapp.MainApp.main(MainApp.java:37)
... 6 more
Both the service and dao implementations have #Transactional at class level. I've a component class that is calling the service class, this component class is not transactional! The component class prints a response, does the session need to be flushed here?
Need to figure out why the save method in the dao is not throwing the exception, I can actually see it an id being created and then rolled back.
J
My component class is very basic;
boolean isValid = opServerService.loadXMLFile("Server.xml");
try{
if (isValid) {
System.out.println("Entity has been added");
} else {
System.out.println("Entity has not been added");
}
}catch (Exception ex){
System.out.println("that was a focked up");
}
The problem is that "Entity has been added" gets printed to console and then I see the above error in console.
DAO looks like this
#Override
#Transactional
public final void save(final ServerEntity serverEntity) throws DataIntegrityViolationException {
LOGGER.debug(">>start(serverEntity=" + serverEntity + ")");
Preconditions.checkNotNull(serverEntity);
this.getCurrentSession().save(serverEntity);
}
Service method with #Transactional at class level, looks like this
#Override
public final void save(ServerEntity serverEntity) {
opServerDao.save(serverEntity);
}
And Component looks like this
#Component
public class AddCommand implements Command {
#Autowired
OpService opService;
public AddServerCommand() {
super();
}
#Override
public void execute(String[] options) {
try{
boolean isValid = opService.save("Server.xml");
if (isValid) {
System.out.println("Entity has been added");
} else {
System.out.println("Entity has not been added");
}
}catch (Exception ex){
System.out.println("Exception found");
}
}
}
You should catch your exception in the component that's calling the service.
Found the solution, was missing from the applicationContext.xml. The wrapped try/catch around the opService now catches the exception. Need to implement my own custom exception handler but for now at least I know the component class is handling the exception which is being thrown from the service class.
Thanks for your help.
J
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
}
}
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.