I am using grails with mysql 5. I am using .withTransaction for transaction management in a service. Within the withTransaction block I am using savePoint() method which is causing the following exception. Note: I am using setRollbackOnly() method without any issue.
2011-06-26 23:02:37,818 [quartzScheduler_Worker-7] ERROR listeners.ExceptionPrinterJobListener - Exception occured in job: GRAILS_JOBS.com.exmp.bdg.PowerRollupJob
org.quartz.JobExecutionException: Transaction manager does not allow nested transactions [See nested exception: org.springframework.transaction.NestedTransactionNotSupportedException: Transaction manager does not allow nested transactions]
at org.codehaus.groovy.grails.plugins.quartz.GrailsJobFactory$GrailsTaskClassJob.execute(GrailsJobFactory.java:81)
at org.quartz.core.JobRunShell.run(JobRunShell.java:199)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:546)
Caused by: org.springframework.transaction.NestedTransactionNotSupportedException: Transaction manager does not allow nested transactions
at org.springframework.jdbc.datasource.JdbcTransactionObjectSupport.getConnectionHolderForSavepoint(JdbcTransactionObjectSupport.java:151)
at org.springframework.jdbc.datasource.JdbcTransactionObjectSupport.createSavepoint(JdbcTransactionObjectSupport.java:104)
at org.springframework.transaction.support.AbstractTransactionStatus.createSavepoint(AbstractTransactionStatus.java:176)
at org.springframework.transaction.SavepointManager$createSavepoint.call(Unknown Source)
at com.exmp.bdg.service.PowerRollupService$_doRollup_closure2.doCall(PowerRollupService.groovy:85)
By default the transaction manager for hibernate and MySQL don't have the save points enabled.
In BootStrap.groovy add the following:
transactionManager.setNestedTransactionAllowed(true)
Then in a transaction you can do the following:
Thing.withTransaction { status ->
//Do some work and a save
def savePoint = status.createSavepoint()
//do other work
if(checkOk)
{
//Everything worked so don't need the save point anymore
status.releaseSavepoint(savePoint)
}
else
{
//The other work did not work so rollback from it.
status.rollbackToSavepoint(savePoint)
}
}
Related
I am trying to use Java Streams with JPA in Apache Camel Route with MySQL. I have seen few resources and they have mentioned that we need to have the below 3 properties for Streams to work properly with MySQL.
1. Forward-only resultset
2. Read-only statement
3. Fetch-size set to Integer.MIN_VALUE
I have tried setting the 2nd and 3rd property in the JPA Repository using QueryHint.
#QueryHints(value = {
#QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE),
#QueryHint(name = HINT_READONLY, value = "true")
})
Looks like Fetch-size is working, but 2nd property is not working, as I am still facing the below error:
Caused by: java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic#54b12700 is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.
I have made the route Transactional using transacted() which is equivalent to spring #Transactional. But not sure what is the equivalent for #Transactional(readonly=true). Any leads?
from("direct:" + ROUTE_ID)
.routeId(ROUTE_ID)
.log("Start the processing")
.transacted()
.bean(Processor.class)
.to("log:ProcessName?showAll=true");
I have referred this blog as reference.
This post is marked for deletion, as the issue was with the IDE in not creating the proper jar, hence issues with the code interaction
I have a small flink application that reads from a kafka topic,
needs to query if the input from the topic (x) exists in a column of MySql Database before processing it (Not Ideal but its the current requirement)
When I run the Application through the IDE (Intellij) -> It works.
However when I submit the job to flink server it fails to open connection based on driver
Error from Flink Server
// ERROR
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
// ---------------------
// small summary of MAIN
// ---------------------
Get Data from Source (x)
source.map(x => {
// open connection (Fails to open)
// check if data exist in db
})
// -------------------------------------
// open connection function (Scala Code)
// -------------------------------------
def openConnection() : Boolean = {
try {
// - set driver
Class.forName("com.mysql.jdbc.Driver")
// - make the connection
connection = DriverManager.getConnection(url, user, pswd)
// - set status controller
connection_open = true
}
catch {
// - catch error
case e: Throwable => e.printStackTrace
// - set status controller
connection_open = false
}
// return result
return connection_open
}
Question
1) Whats the correct way to interface to MySql Database from a flink application?
2) I will also at a later stage have to do similar interaction with MongoDB, whats the correct way interacting with MongoDB from FLink?
Unbelievable IntelliJ does not update dependencies on rebuild command.
In IntelliJ, You have to delete and re-setup your artifact creator for all dependencies do be added. (Build, Clean, Rebuild,Delete) does not update its settings.
I deleted and recreated the artifact file. And it Works
Apologies for the unnecessary inconvenience (As you can imagine my frustration). But it's a word of caution for those developing in IntelliJ, to manually delete and recreate artifacts
Solution:
(File -> Project Structure -> Artifacts -> (-) delete previous one -> (+) create new one -> Select Main Class)
In my project there is a table called process_detail. Row inserted in this table as soon as a cron process starts and is updated at the end
of the cron process completion. We are using grails which internally takes care of transaction at service level method i.e. transaction starts at the start of the method, commit if the method execution successful, rollback if any exception.
Here what happens is that if the transaction fails this row also being rolled back this I don't want because this is type of a log
table. I tried creating a nested transaction and save this row and at the end update it but that fails with lock acquisition exception.
I am thinking of using MyISAM for this particular table,
this way I don't have to worry about transaction because MyISAM does not support it and it will commit immediately and no rollback possible. Here's pseudo code for what I am trying to achieve.
def someProcess(){
//Transaction starts
saveProcessDetail(details); //Commit this immediately, should not rollback if below code fails.
someOtherWork;
updateProcessDetail(details); //Commit this immediately, should
//Transaction Ends
}
Pseudo code for save and update process detail;
def saveProcessDetail(processName, processStatus){
ProcessDetail pd = new ProcessDetail(processName, processStatus);
pd.save();
}
def updateProcessDetail(processDetail, processStatus){
pd.procesStatus = processStatus;
pd.save();
}
Please advice if there is better of doing this in InnoDB. Answer could be mysql level I can find the grails solution my self. Let me know if any other info required.
Make someProcess #NonTransactional, then manage the transactional nature yourself. Write the initial saveProcessDetail with a flush:true, then make the remainder of the processing transactional, withTransaction?
Or
#NonTransactional
def someProcess() {
saveProcessDetail(details) // I'd still use a flush:true
transactionalProcessWork()
}
#Transactional
def transactionalProcessWork() {
someOtherWork()
updateProcessDetail(details)
}
I'm trying to run a function that goes something like this:
$records->connection()->transactional(function () use ($records, $entities) {
foreach ($entities as $record) {
$records->save($record, ['atomic' => false]);
}
});
Is there a way to check and see if this transactional threw an error, or is there just something inherently wrong with running a transactional in this fashion vs. executes?
The end goal is to update a set number of entities, but update none if an error was thrown. The functions above are abstract enough to allow different aspects of the entity to be changed, so this method was played around with rather than specific executes to allow for ease of saving through entities.
ConnectionInterface::transactional() will issue a rollback in case the callback returns false or throws an error (which is being re-thrown afterwards).
Quote from the docs:
[...]
The transactional method will do the following:
Call begin.
Call the provided closure.
If the closure raises an exception, a rollback will be issued. The original exception will be re-thrown.
If the closure returns false, a rollback will be issued.
If the closure executes successfully, the transaction will be committed.
[...]
Cookbook > Dabase Access & ORM > Database Basis > Using Transactions
[...]
Returns mixed The return value of the callback.
[...]
API > \Cake\Datasource\ConnectionInterface::transactional()
So exceptions are already covered, you can simply catch them, and the return value is the value that is returned from your closure, so all you may additionally need is to return false from your closure in case Table::save() calls are failing.
I've written a grails service with the following code:
EPCGenerationMetadata requestEPCs(String indicatorDigit, FilterValue filterValue,
PartitionValue partitionValue, String companyPrefix, String itemReference,
Long quantity) throws IllegalArgumentException, IllegalStateException {
//... code
//problematic snippet bellow
def serialGenerator
synchronized(this) {
log.debug "Generating epcs..."
serialGenerator = SerialGenerator.findByItemReference(itemReference)
if(!serialGenerator) {
serialGenerator = new SerialGenerator(itemReference: itemReference, serialNumber: 0l)
}
startingPoint = serialGenerator.serialNumber + 1
serialGenerator.serialNumber += quantity
serialGenerator.save(flush: true)
}
//code continues...
}
Being a grails service a singleton by default, I thought I'd be safe from concurrent inconsistency by adding the synchronized block above. I've created a simple client for testing concurrency, as the service is exposed by http invoker. I ran multiple clients at the same time, passing as argument the same itemReference, and had no problems at all.
However, when I changed the database from MySQL to PostgreSQL 8.4, I couldn't handle concurrent access anymore. When running a single client, everything is fine. However, if I add one more client asking for the same itemReference, I get instantly a StaleObjectStateException:
Exception in thread "main" org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [br.com.app.epcserver.SerialGenerator] with identifier [10]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.com.app.epcserver.SerialGenerator#10]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:672)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:881)
at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod$1.doInHibernate(SavePersistentMethod.java:58)
(...)
at br.com.app.EPCGeneratorService.requestEPCs(EPCGeneratorService.groovy:63)
at br.com.app.epcclient.IEPCGenerator$requestEPCs.callCurrent(Unknown Source)
at br.com.app.epcserver.EPCGeneratorService.requestEPCs(EPCGeneratorService.groovy:29)
at br.com.app.epcserver.EPCGeneratorService$$FastClassByCGLIB$$15a2adc2.invoke()
(...)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.com.app.epcserver.SerialGenerator#10]
Note: EPCGeneratorService.groovy:63 refers to serialGenerator.save(flush: true).
I don't know what to think, as the only thing that I've changed was the database. I'd appreciate any advice on the matter.
I'm using:
Grails 1.3.3
Postgres 8.4 (postgresql-8.4-702.jdbc4 driver)
JBoss 6.0.0-M4
MySQL:
mysqld Ver 5.1.41 (mysql-connector-java-5.1.13-bin driver)
Thanks in advance!
That's weird, try disabling transaction.
This is indeed a strange behavior, but you could try to workaround by using a "select ... for upgrade", via hibernate lock method.
Something like this:
def c = SerialGenerator.createCriteria()
serialgenerator = c.get {
eg "itemReferece", itemReference
lock true
}