I'm trying to create a SQLite database with spring-jdbc. I'm doing this using a automatic initialization with this XML configuration:
<jdbc:initialize-database data-source="logDbDataSource" enabled="true">
<jdbc:script location="classpath:scheme.sql" />
</jdbc:initialize-database>
The scheme.sql creates a table for logging events. I also want to automatically delete old data using a trigger, so the SQL looks like this:
CREATE TABLE IF NOT EXISTS events (
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
time DATETIME DEFAULT CURRENT_TIMESTAMP,
value TEXT NOT NULL
);
CREATE TRIGGER IF NOT EXISTS cleanup
AFTER INSERT ON events
BEGIN
DELETE FROM events WHERE time < datetime('now', '-35 days');
END;
This works totally fine when I create the database manually with
sqlite3 eventDb.sqlite < schema.sql.
My problem is, that it leads to the following exception when starting the program, where this is handled by Spring:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0': Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at org.atennert.homectrl.Main.main(Main.java:34)
... 6 more
Caused by: org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:56)
at org.springframework.jdbc.datasource.init.DataSourceInitializer.afterPropertiesSet(DataSourceInitializer.java:84)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 18 more
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.executeSqlScript(ResourceDatabasePopulator.java:202)
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:135)
at org.springframework.jdbc.datasource.init.CompositeDatabasePopulator.populate(CompositeDatabasePopulator.java:56)
at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:47)
... 21 more
Caused by: org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (near ")": syntax error)
at org.sqlite.core.DB.newSQLException(DB.java:920)
at org.sqlite.core.DB.newSQLException(DB.java:932)
at org.sqlite.core.DB.throwex(DB.java:897)
at org.sqlite.core.NativeDB.prepare(Native Method)
at org.sqlite.core.DB.prepare(DB.java:227)
at org.sqlite.jdbc3.JDBC3Statement.execute(JDBC3Statement.java:60)
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.executeSqlScript(ResourceDatabasePopulator.java:187)
... 24 more
My best guess is, there are some problems with automatic population and the datetime function (same problem with the date function). Everything works fine, when I remove the trigger from the script.
Is this an issue with SQLite / SQL functions and/or automatic initialization with Spring JDBC? Do I have to write it differently to get it working for automatic initialization?
Failed to execute SQL script statement at line 3 of
resource class path resource [homectrlLog-schema.sql]:
CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events ⏎
BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
Whatever code you're using to execute the script splits the SQL at every semicolon. This is wrong when you have triggers, because the entire trigger creation until the final END must be executed as a single statement.
Related
Either I can create table using
spring.jpa.hibernate.ddl-auto=update
or I can insert into table using
spring.datasource.initialization-mode=always
How to perform both operation at same time ?
If I do both operation it gives me an exeption as below
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scriptDataSourceInitializer' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration$SharedCredentialsDataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of URL [file:/C:/Users/JAY%20GURUDEV/eclipse-workspace/bootjpa/target/classes/data.sql]: insert into alien(aid,aname,tech) values(1,'ritu','java'); nested exception is java.sql.SQLSyntaxErrorException: Table 'mydb.alien' doesn't exist
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.14.jar:5.3.14]
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of URL [file:/C:/Users/JAY%20GURUDEV/eclipse-workspace/bootjpa/target/classes/data.sql]: insert into alien(aid,aname,tech) values(1,'ritu','java'); nested exception is java.sql.SQLSyntaxErrorException: Table 'mydb.alien' doesn't exist
at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:282) ~[spring-jdbc-5.3.14.jar:5.3.14]
at
Caused by: java.sql.SQLSyntaxErrorException: Table 'mydb.alien' doesn't exist
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-java-8.0.27.jar:8.0.27]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.27.jar:8.0.27]
I think this exception occurs because table is not created and row is trying to be inserted from data.sql file
I need to read data from both select and exec Sybase queries using JdbcCursorItemReader in Spring-Batch. While SELECT queries run perfectly, the Exec queries are running into the following error:
Caused by: org.springframework.jdbc.UncategorizedSQLException:
Executing query; uncategorized SQLException for SQL [exec
proc_1]; SQL state
[ZZZZZ]; error code [7773]; Execute cursor 'jconnect_implicit_1' is
declared on a procedure which contains a non-SELECT or a SELECT with a
COMPUTE clause. For the declaration of this cursor to be legal it
should have a single SELECT statement without a COMPUTE clause.
; nested exception is com.sybase.jdbc4.jdbc.SybSQLException: Execute
cursor 'jconnect_implicit_1' is declared on a procedure which contains
a non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
... 43 common frames omitted
Caused by: com.sybase.jdbc4.jdbc.SybSQLException: Execute cursor
'jconnect_implicit_1' is declared on a procedure which contains a
non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
... 45 common frames omitted
The code for the JdbcCursorItemReader is as follows:
JdbcCursorItemReader itemReader = new JdbcCursorItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setSql(dataSql); //datasql is passed Sybase query
Even after using StoredProcedureItemReader as suggested,
getting the following error:
Caused by: org.springframework.jdbc.UncategorizedSQLException:
Executing stored procedure; uncategorized SQLException for SQL [{call
ftsps_report(?, ?)}]; SQL state [ZZZZZ]; error code
[7773]; Execute cursor 'jconnect_implicit_1' is declared on a
procedure which contains a non-SELECT or a SELECT with a COMPUTE
clause. For the declaration of this cursor to be legal it should have
a single SELECT statement without a COMPUTE clause.
; nested exception is com.sybase.jdbc4.jdbc.SybSQLException: Execute
cursor 'jconnect_implicit_1' is declared on a procedure which contains
a non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:90)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:226)
at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:406)
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:144)
... 43 common frames omitted
Caused by: com.sybase.jdbc4.jdbc.SybSQLException: Execute cursor
'jconnect_implicit_1' is declared on a procedure which contains a
non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
at com.sybase.jdbc4.tds.Tds.processEed(Tds.java:4112)
at com.sybase.jdbc4.tds.Tds.nextResult(Tds.java:3229)
at com.sybase.jdbc4.tds.Tds.getResultSetResult(Tds.java:3974)
at com.sybase.jdbc4.tds.TdsCursor.open(TdsCursor.java:333)
at com.sybase.jdbc4.jdbc.SybCallableStatement.sendRpc(SybCallableStatement.java:2032)
at com.sybase.jdbc4.jdbc.SybCallableStatement.execute(SybCallableStatement.java:241)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
at com.sun.proxy.$Proxy83.execute(Unknown Source)
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:210)
Have defined the StoredProcedureItemReader as follows:
StoredProcedureItemReader itemReader = new StoredProcedureItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setProcedureName(dataSql);
SqlParameter[] parameter = {new SqlParameter("date1", Types.DATE),new SqlParameter("date2", Types.DATE)};
itemReader.setParameters(parameter);
itemReader.setPreparedStatementSetter(psSetter);
where psSetter setValues I have defined as follows:
ps.setDate(1, Date.ValueOf(paramList.get(0));
ps.setDate(2, Date.ValueOf(paramList.get(1));
I tried for few other stored procedures also and got similar issues.
Is it an error with the definition. I just want to define parameters by index preferably. Is there any straightforward way of doing so? Is it expecing the parameters in the storedproc to be named date1/date2 specifically and failing because of that?
For stored procedures, you need to use the StoredProcedureItemReader and not the JdbcCursorItemReader, something like:
#Bean
public StoredProcedureItemReader storedProcedureItemReader() {
StoredProcedureItemReader reader = new StoredProcedureItemReader();
reader.setProcedureName("yourProcedureName");
// set other properties
return reader;
}
Please refer to the reference documentation for more details.
I am starting my application and getting below error in logs at startup. Weird thing is i amnot getting which table is missing ? Is there a way it can display which table does not exist
org.springframework.dao.InvalidDataAccessResourceUsageException: ORA-00942: table or view does not exist
; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: ORA-00942: table or view does not exist
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:635) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:516) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) ~[spring-tx-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) ~[spring-tx-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:394) ~[spring-tx-3.1.2.RELEASE.jar:3.1.2.RELEASE]
ORA-00942: table or view does not exist
It means that your query is trying to use the table which doesn't exists OR it is using the table without having right access.
So, when you start your application, some Spring bean is created and process such query (you can see from stack trace that Spring tx manager is trying to commit the current transaction, so in some place this transaction was opened). You should make sure that all hibernate entities have corresponding table to your schema. If you can't guarantee that, perhaps you can use <hibernate.hbm2ddl.auto> update </hibernate.hbm2ddl.auto>
hibernate will do the job for you and creates tables & sequences and so forth according to your entities.
Also you can check what is going on by enabling hibernate logging. You can enable if by setting property "show_sql" to "true" in your persistence.xml or alternative using
logback:
<logger name="org.hibernate" level="DEBUG" />
log4j:
log4j.logger.org.hibernate.SQL=DEBUG
I have a file(this file actually has tab separated values) which has to be written into one of the database tables. This file can contain duplicate entries as well. I am processing the records in the file in set of 5000, so I first parse these first 5000 records in the file if they contain any duplicate entries I simply ignore the duplicates and write the unique records among them to the database and again process next 5000 records in the similar fashion till EOF is reached. Now while writing these 5000 records it is possible that there are duplicates between the sets of 5000 records and if so happens(then database throws the DomainObjectExistsException) then I catch the exception and simply update the record. I am performing the update operation like this:
getHibernateTemplate().saveOrUpdate(femtoFactoryData);
Where femtoFactoryData is a java Object(POJO) which has to be written into the database table constructed from the tab-separated values in the file. The Primary Key of the table is nothing but the ID of the Femto and the state(Temporary/Permanent).
But while performing this update operation I am getting:
org.hibernate.exception.ConstraintViolationException
Here is the stacktrace from my program:
org.hibernate.exception.ConstraintViolationException: could not insert: [com.airvana.anp.model.db.domainobjects.FemtoFactoryData]
at com.airvana.anp.model.db.impl.DbManagerGlobalUtils.convertException(DbManagerGlobalUtils.java:68)
at com.airvana.anp.model.db.impl.FemtoFactoryDataDAOImplHelper.updateFemtoFactoryData(FemtoFactoryDataDAOImplHelper.java:302)
at com.airvana.anp.model.db.impl.FemtoFactoryDataDAOImpl.updateFemtoFactoryData(FemtoFactoryDataDAOImpl.java:149)
at com.airvana.anp.model.oss.imports.common.DataRecordDAOHelperImpl.updateRecord(DataRecordDAOHelperImpl.java:725)
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:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
at $Proxy89.updateRecord(Unknown Source)
at com.airvana.anp.model.oss.imports.parser.ParseControllerImpl.saveDupFactoryRecordsInDb(ParseControllerImpl.java:477)
at com.airvana.anp.model.oss.imports.parser.ParseControllerImpl.parseFile(ParseControllerImpl.java:111)
at com.airvana.anp.model.oss.imports.FactoryOperationsManagerImpl.onAllocation(FactoryOperationsManagerImpl.java:192)
at com.airvana.anp.model.resource.impl.CallbackWorkerJob.run(CallbackWorkerJob.java:43)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
at java.lang.Thread.run(Thread.java:595)
Caused by: org.springframework.dao.DataIntegrityViolationException: could not insert: [com.airvana.anp.model.db.domainobjects.FemtoFactoryData]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.airvana.anp.model.db.domainobjects.FemtoFactoryData]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:624)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.merge(HibernateTemplate.java:820)
at com.airvana.anp.model.db.impl.FemtoFactoryDataDAOImplHelper.updateFemtoFactoryData(FemtoFactoryDataDAOImplHelper.java:299)
... 16 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.airvana.anp.model.db.domainobjects.FemtoFactoryData]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2272)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
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:1004)
at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:420)
... 19 more
Caused by: java.sql.SQLException: ORA-00001: unique constraint (ANPDB.SYS_C008651) violated
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:955)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3316)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3400)
at weblogic.jdbc.wrapper.PreparedStatement.executeUpdate(PreparedStatement.java:128)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2252)
... 29 more
You're not handling duplicates properly since there's obviously constraint violation regarding unique keys.
I'd suggest eliminating those duplicates entirely before inserting them into database.
Remember: the database is your last line of defense. Ignoring the poetic aspect, that's basically saying that you should do whatever possible to insert into your database exactly what's needed. Nothing more, nothing less. Filter, remove duplicates, whatever on your server side before sending it to database.
I want to generate UUID for a unique string, i am using the following code:-
thread.createSession();
HexGenerator gen1 = new HexGenerator();
gen1.setHexId("2");
thread.ses.save(gen1);
gen1 = (HexGenerator) thread.ses.load(HexGenerator.class, gen1.getHexId());
System.out.println("gen1-->" + gen1.getHexId());
thread.commit();
Below is my hibernate file:-
<class name="entity.HexGenerator" table="dual">
<id name="hexId" type="string" unsaved-value="null">
<generator class="uuid.hex"/>
</id>
</class>
UUId is generated properly, but i am getting an error when the complete transaction is committed. as in the following error comes.
Exception in thread "main" - Could not synchronize database state with session
org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
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 com.ofss.test.hibernate.HibernateThread.commit(HibernateThread.java:29)
at com.ofss.test.hibernate.HibernateThread.main(HibernateThread.java:57)
Caused by: java.sql.BatchUpdateException: ORA-00904: "HEXID": invalid identifier
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10698)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 9 more
org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
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 com.ofss.test.hibernate.HibernateThread.commit(HibernateThread.java:29)
at com.ofss.test.hibernate.HibernateThread.main(HibernateThread.java:57)
Caused by: java.sql.BatchUpdateException: ORA-00904: "HEXID": invalid identifier
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10698)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
You can't insert or update on the Oracle dual virtual table. You just can use it at select queries.
So, your line thread.ses.save(gen1) is what generates the error. I think that if you just delete this line, the error will be fixed.
But I don't really understand why you need to access the database to generate your UUID, which seems to be generated at the HexGenerator class (or maybe at the "uuid.gen" class referenced at the hibernate file).
To overcome the above problem, i mean to generate the UUID, now I have decided to use two method, either to use java.util.UUID.randomUUID() or to write my own logic to generate the same using bits array and then randomizing it.
first, your code looks a little bit strange. You create instance of HexGenerator:
HexGenerator gen1 = new HexGenerator();
use it and immediately override using some unknown for me API that uses dynamic class loading.
thread.ses.load(HexGenerator.class, gen1.getHexId())
Then you call getHexId() again. I believe that code
new HexGenerator().getHexId()
will generate ID that you need.
But I think it is not yet the reason for failure. Unfortunately you did not provide any information about you DB schema. I believe that you ID is simply defined as number, it cannot accept strings. Check it again and please provide more details if this is not the reason.