Spring Batch-How to process multiple records at the same time in the processor? - spring

I have a file to parse and process records from. It is working fine as line-by-line (parsing one record at a time). My requirement is I've to parse thru multiple line and fetch the required information from each records and then after combining the fetched info from all the records, I call a service to perform business logic. I have to perform this logic inside my Processor class. The data looks like as below example:
001 123456 987654321551580 Wayne DR 1
001 123456 987654321552APT 786 1
001 123456 987654321553LOS ANGELES 1
001 123456 987654321554CA 1
001 123456 98765432155590001 1
The data element available at columns 30-32 is what I am interested to fetch from each record. In the above example, the values 551, 552, 553, 554, 555 in each line respectively. They all come in together in the file. So basically when the current item in my processor parses the first line and finds out that its '551' (means Address Line1 in business code), then I want to fetch the rest of the address that follows this line and save them in one complete address. At the end I want to pass this address to the service class from the processor and then move on to parse the next record available in the file. My problem is that the processor works on line by line for each record so this way I am not able to keep track/association between all these related lines.
Sorry if I am not able to explain my problem in an easier way..I am new to Spring Batch and still learning.

If you know the associated data records will be next to one another in the file (as opposed to spread out randomly), you can leverage the SingleItemPeekableItemReader to associate multiple lines to create one complete object. This older answer has a bit more info.
Example Context File:
<bean id="peekingReader" class="com.package.whatever.YourPeekingReader">
<property name="delegate" ref="flatFileItemReader"/>
</bean>
<bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file://temp/file.txt" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer" ref="yourTokenizer"/>
<property name="fieldSetMapper" ref="yourMapper"/>
</bean>
</property>
</bean>
Example Peeking Reader:
public class YourPeekingReader extends SingleItemPeekableItemReader<YourObject> {
#Override
public YourObject read() {
YourObject item = super.read();
if (item == null) {
return null;
}
while (true) {
YourObject possibleRelatedObject = peek();
if (possibleRelatedObject == null) {
return item;
}
//logic to determine if next line in file relates to same object
boolean matches = false;
if (matches) {
item.addRelatedInfo(super.read());
} else {
return item;
}
}
}
}

#Dean..thanks again. To be more precise with my code, here it is
Customer-record-reader.xml
<batch:job id="myFileReaderJob">
<batch:step id="stepA" next="stepSuccess">
<batch:tasklet>
<batch:chunk reader="myInputReader" processor="myProcessor" writer="myWriter" commit-interval="1"/>
</batch:tasklet>
</batch:step>
<batch:step id="stepSuccess">
<batch:tasklet ref="successTasklet" />
</batch:step>
</batch:job>
<bean id="myInputReader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="lineMapper" ref="myLineMapper" />
</bean>
<bean id="myLineMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean id="fixedLengthLineTokenizer" class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
<property name="names" value="custRecord,tranId,partyId,uniquePartyId,deNum,deVal" />
<property name="columns" value="1-75,1-3,6-11,21-29,30-32,33-62" />
<property name="strict" value="false" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="myInputData" />
</bean>
</property>
</bean>
As you can see, I am not using a custom implementation of ItemReader to wrap the FlatFileItemReader. Can you elaborate more in detail, on how to make changes in this code above to implement the SingleItemPeekableItemReader.
Thanks

#Dean
I tried implementing as per your suggestion
Config1.xml
<import resource="classpath*:/META-INF/java-batchlauncher/mainConfig.xml" />
<batch:job id="prT813FileReaderJob">
<batch:step id="stepA" next="stepB">
<batch:tasklet ref="aTasklet" />
</batch:step>
<batch:step id="stepB" next="stepSuccess">
<batch:tasklet>
<batch:chunk reader="prT813MultiReader" processor="participantRecordT813Processor" writer="prT813ItemWriter" commit-interval="1"/>
<batch:listeners>
<batch:listener ref="enabledFeaturesStepListener"/>
</batch:listeners>
<batch:transaction-attributes propagation="NEVER"/>
</batch:tasklet>
</batch:step>
<batch:step id="stepSuccess">
<batch:tasklet ref="successTasklet" />
</batch:step>
</batch:job>
My mainConfig.xml file changes:
<bean id="prT813MultiReader" scope="step" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="#{jobParameters[INPUT_FILES]}" />
<property name="delegate" ref="prT813InputReader" />
</bean>
<bean id="prT813MultiThreadedReader" scope="step" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="#{stepExecutionContext[fileName]}" />
<property name="delegate" ref="prT813InputReader" />
</bean>
<bean id="prT813InputReader" scope="step" class="com.fileprocessing.ParticipantRecordT813ItemReader">
<property name="delegate" ref="prT813CustomPeekableItemReader" />
</bean>
<bean id="prT813CustomPeekableItemReader" scope="step" class="org.springframework.batch.item.support.SingleItemPeekableItemReader">
<property name="delegate" ref="participantRecordT813ItemReader" />
</bean>
<bean id="participantRecordT813ItemReader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="lineMapper" ref="prT813LineMapper" />
</bean>
Created a new Reader class:
public class ParticipantRecordT813ItemReader extends SingleItemPeekableItemReader<ParticipantRecordT813InputData> {
private static final String CLASS = "ParticipantRecordT813ItemReader";
#Override
public ParticipantRecordT813InputData read() throws UnexpectedInputException, ParseException, Exception {
ParticipantRecordT813InputData item = super.read();
Log.report(CLASS, "I am in the reader ::::");
if (item != null) {
while (item.getDeNum()=="551") {
Log.report(CLASS, "I am in the reader at DE551::::" + item.getDeNum());
ParticipantRecordT813InputData possibleRelatedObject = peek();
if (possibleRelatedObject == null) {
return item;
}
//logic to determine if next line in file relates to same object
boolean matches = possibleRelatedObject.getDeNum()=="552";
if (matches) {
Log.report(CLASS, "I am in the reader at DE552::::" + possibleRelatedObject.getDeNum());
} else {
return item;
}
}
}
return item;
}
}
I am getting the below exception:
ERROR [main] (AbstractStep.java:225)- Encountered an error executing step stepB in job prT813FileReaderJob
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.prT813MultiReader' defined in URL []: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.sun.proxy.$Proxy10 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.PeekableItemReader,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.batch.item.file.ResourceAwareItemReaderItemStream' for property 'delegate'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy10 implementing org.springframework.batch.item.ItemStreamReader,org.springframework.batch.item.PeekableItemReader,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.file.ResourceAwareItemReaderItemStream] for property 'delegate': no matching editors or conversion strategy found
As you can see that prT813MultiReader and prT813MultiThreadedReader of type MultiResourceItemReader and I delegate them to prT813InputReader of type SingleItemPeekableItemReader.
I tried implementing ResourceAwareItemReaderItemStream in my reader class which get rid of the above exception but then it complaints on ParticipantRecordT813InputData item = super.read(); for nullPointerException.
public class ParticipantRecordT813ItemReader extends SingleItemPeekableItemReader<ParticipantRecordT813InputData> implements ResourceAwareItemReaderItemStream<ParticipantRecordT813InputData> {
private static final String CLASS = "ParticipantRecordT813ItemReader";
SingleItemPeekableItemReader<ParticipantRecordT813InputData> delegate = new SingleItemPeekableItemReader<ParticipantRecordT813InputData>();
#Override
public ParticipantRecordT813InputData read() throws UnexpectedInputException, ParseException, Exception {
ParticipantRecordT813InputData item = super.read();
Log.report(CLASS, "I am in the reader ::::");
if (item != null) {
while (item.getDeNum()=="551") {
Log.report(CLASS, "I am in the reader at DE551::::" + item.getDeNum());
ParticipantRecordT813InputData possibleRelatedObject = peek();
if (possibleRelatedObject == null) {
return item;
}
//logic to determine if next line in file relates to same object
boolean matches = possibleRelatedObject.getDeNum()=="552";
if (matches) {
Log.report(CLASS, "I am in the reader at DE552::::" + possibleRelatedObject.getDeNum());
} else {
return item;
}
}
}
return item;
}
#Override
public void close() throws ItemStreamException {
// TODO Auto-generated method stub
super.close();
}
#Override
public void open(ExecutionContext arg0) throws ItemStreamException {
// TODO Auto-generated method stub
super.open(arg0);
}
#Override
public void update(ExecutionContext arg0) throws ItemStreamException {
// TODO Auto-generated method stub
super.update(arg0);
}
#Override
public void setResource(Resource arg0) {
// TODO Auto-generated method stub
super.setDelegate(delegate);
}
}
Any idea where I am wrong????

Related

Spring Batch - reading multiple PDF files and passing them to ItemProcessor

I would like to read a multiple pdf files and process them one by one.
I use MultiResourceItemReader and a custom delegate:
public class MyItemReader implements ResourceAwareItemReaderItemStream<MyItem> {
private Resource resource;
#Override
public MyItem read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
return null; //create MyItem
}
#Override
public void setResource(Resource resource) {
this.resource = resource;
}
#Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
}
#Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
}
#Override
public void close() throws ItemStreamException {
}
}
The problem I have is that the read method is ivoked infinitly and my ItemProcessor is not invoked.
The resources property is correctly set - files are set.
Could anyone explain me this? Thanks in advance.
I finally decided to use ResourcesItemReader instead of MultiResourceItemReader with custom delegate. This solution is simpler.
<!--suppress SpringBatchModel -->
<batch:job id="my-import">
<batch:step id="myFileStep">
<batch:tasklet>
<batch:chunk reader="resourcesItemReader"
processor="sddeImportProcessor"
writer="sddeImportJpaItemWriter"
commit-interval="${commit.interval:500}"/>
</batch:tasklet>
</batch:step>
<batch:listeners>
<batch:listener ref="sftpImportExecutionListener"/>
<batch:listener ref="longRunningJobExecutionNotificator"/>
<batch:listener ref="exitStatusJobExecutionListener"/>
<batch:listener ref="afterJobExecutionMailSender"/>
</batch:listeners>
</batch:job>
<bean id="sftpImportExecutionListener"
class="my.batches.shared.listener.SftpImportJobListener">
<constructor-arg name="ftsReadService" ref="ftsReadService"/>
<constructor-arg name="ftsWriterService" ref="ftsWriterService"/>
<constructor-arg name="localDir" value="${voe.batch.sdde.unterschriftenblatt.import.local.folder}"/>
<constructor-arg name="remoteDir" value="${voe.batch.sdde.unterschriftenblatt.import.remote.folder}"/>
<constructor-arg name="multipleFilesImport" value="true" />
</bean>
<bean id="resourcesItemReader" class="org.springframework.batch.item.file.ResourcesItemReader" scope="step">
<property name="resources" value="#{jobExecutionContext['import.input.file.path']}"/>
</bean>
<bean id="myImportProcessor" class="my.MyProcessor">
<property name="myUpdateService" ref="defaultUpdateService" />
</bean>
<bean id="myImportJpaItemWriter" class="org.springframework.batch.item.database.JpaItemWriter">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

How to write a spring batch step without an itemwriter

I am trying to configure a spring batch step without an item writer using below configuraion. However i get error saying that writer
element has neither a 'writer' attribute nor a element.
I went through the link spring batch : Tasklet without ItemWriter. But could not resolve issue.
Could any one tell me the specific changes to be made in the code snippet I mentioned
<batch:job id="helloWorldJob">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="cvsFileItemReader"
commit-interval="10">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="classpath:cvs/input/report.csv" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="id,sales,qty,staffName,date" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="com.mkyong.ReportFieldSetMapper" />
<!-- if no data type conversion, use BeanWrapperFieldSetMapper to map by name
<bean
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="report" />
</bean>
-->
</property>
</bean>
</property>
</bean>
For chunk-based step reader and writer are mandatory.
If you don't want a writer use a No-operation ItemWriter that does nothing.
EDIT:
A no-op implementation is an empty implementation of interface tha does...nothing!
Just let your class implements desiderable inteface(s) with empty methods.
No-op ItemWriter:
public class NoOpItemWriter implements ItemWriter {
void write(java.util.List<? extends T> items) throws java.lang.Exception {
// no-op
}
}
I hope you got answer but I want to explain it for other readers, When we use chunk then usually we declare reader, processor and writer. In chunk reader and writer are mandatory and processor is optional. In your case if you don't need writer then u need to make a class which implements ItemWriter. Override write method and keep it blank. Now create a bean of writer class and pass it as reference of writer.
<batch:step id="recordProcessingStep" >
<batch:tasklet>
<batch:chunk reader="fileReader" processor="recordProcessor"
writer="rocordWriter" commit-interval="1" />
</batch:tasklet>
</batch:step>
Your writer class will look like .
public class RecordWriter<T> implements ItemWriter<T> {
#Override
public void write(List<? extends T> items) throws Exception {
// TODO Auto-generated method stub
}
}
In maven repo you can find the framework "spring-batch-samples".
In this framework you will find this Writer :
org.springframework.batch.sample.support.DummyItemWriter

spring batch ItemReader FlatFileItemReader set cursor to start reading from a particular line or set linestoskip dynamically

In my springbatch+quartz setup, I am reading a CSV File using FlatFileItemReader. I want to set the cursor for the reader to start the next jobinstance with the given parameters for reader. Is it possible?
<bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<!-- Read a csv file -->
<property name="resource" value="classpath:cvs/input/report.csv" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="id,impressions" />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="report" />
</bean>
</property>
</bean>
</property>
</bean>
The idea is to continue reading the file where last failure occured in the next execution. I am putting an integer 'writecursor' for each line written in my customWriter.
public void write(List<? extends Report> items) throws Exception {
System.out.println("writer..." + items.size() + " > ");
for(Report item : items){
System.out.println("writing item id: " + item.getId());
System.out.println(item);
}
//getting stepExecution by implementing StepExecutionListener
this.stepExecution.getExecutionContext().putInt("writecursor", ++writecursor);
}
Now, in the customItemReadListener, I want to get the update writecursor value and then skip the lines from the top to start reading from writecursor
public class CustomItemReaderListener implements ItemReadListener<Report>, StepExecutionListener {
ApplicationContext context = ApplicationContextUtils.getApplicationContext();
private StepExecution stepExecution;
#Override
public void beforeRead() {
//Skip lines somehow
}
Another thing I saw as a possible solution is to set linestoskip dynamically in itemreader. There is a thread here http://thisisurl.com/dynamic-value-for-linestoskip-in-itemreader but not answered yet. And here,
http://forum.spring.io/forum/spring-projects/batch/100950-accessing-job-execution-context-from-itemwriter
Use FlatFileItemReader.linesToSkip property setted injecting job Parameter value.
<bean id="myReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="linesToSkip" value="file:#{jobParameters['cursor']}" />
</bean>
A more easy way for implementing the lines to skip is by the following:
create a reader flat file reader in the xml, autowire the reader to the beforeStep of step execution listener as shown below
public class CustomStepListener implements StepExecutionListener {
#Autowired
#Qualifier("cvsFileItemReader")
FlatFileItemReader cvsFileItmRdr;
#Override
public void beforeStep(StepExecution stepExecution) {
System.out.println("StepExecutionListener -------- beforeStep");
cvsFileItmRdr.setLinesToSkip(4);
}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
System.out.println("StepExecutionListener - afterStep");
return null;
}
}
it is working fine for me.....

Spring Batch - Validate Header Lines in input csv file and skip the file if it invalidates

I have a simple job as below:
<batch:step id="step">
<batch:tasklet>
<batch:chunk reader="itemReader" processor="itemProcessor" writer="itemWriter" commit- interval="5000" />
</batch:tasklet>
</batch:step>
itemReader is as below:
<bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader"
scope="step">
<property name="linesToSkip" value="1"></property>
<property name="skippedLinesCallback" ref="skippedLinesCallback" ></property>
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer" ref="lineTokenizer">
<property name="delimiter" value="," />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper" />
</property>
</bean>
</property>
<property name="resource" value="#{stepExecutionContext['inputKeyName']}" />
</bean>
<bean id"lineTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<bean id="skippedLinesCallback" class="com.test.IteMReaderHeader" >
<property name="lineTokenizer" ref="lineTokenizer">
</bean>
I am setting the "names" of the input fields in "com.test.IteMReaderHeader" class by injecting "lineTokenizer" in it.
I need to validate the header lines which is the 1st line in the input csv file with a fixed header value and if the header line invalidates then in that case I need to fail the step and skip the entire file so that the next file can be used for reading.
Please suggest a suitable way of achieving it.
I would really appreciate your time and valuable inputs.
Thanks !!
Looking code of FlatFileItemReader file stop condition is managed;
with private field boolean noInput
with private function readLine() used in protected doRead()
IMHO the best solution is to throw a runtime exception from your skippedLineCallback and manage error as reader exhaustion condition.
Foe example writing your delegate in this way
class SkippableItemReader<T> implements ItemStreamReader<T> {
private ItemStreamReader<T> flatFileItemReader;
private boolean headerError = false;
void open(ExecutionContext executionContext) throws ItemStreamException {
try {
flatFileItemReader.open(executionContext);
} catch(MyCustomExceptionHeaderErrorException e) {
headerError = true;
}
}
public T read() {
if(headerError)
return null;
return flatFileItemReader.read();
}
// Other functions delegation
}
(you have to register delegate as stream manually,of course)
or extending FlatFileItemReader as
class SkippableItemReader<T> extends FlatFileItemReader<T> {
private boolean headerError = false;
protected void doOpen() throws Exception {
try {
super.doOpen();
} catch(MyCustomExceptionHeaderErrorException e) {
headerError = true;
}
}
protected T doRead() throws Exception {
if(headerError)
return null;
return super.doRead();
}
}
The code has been written directly without test so there can be errors, but I hope you can understand my point.
Hope can solve your problem

spring mybatis transaction getting committed

I am trying to use mybatis spring transaction management
My problem is that the transactions are getting committed even if an exception is thrown.
Relatively new to this, anykind of help is much appreciated.
Following are the code snippets
spring xml configuration
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:Config.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:Configuration.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
Service class
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,String confidentialValue,String summaryValue,String notes ,String notesId,String noteTypeValue,
String claimNumber,String notepadId,String mode)
{
NotepadExample notepadExample= new NotepadExample();
//to be moved into dao class marked with transaction boundaries
Notepad notepad = new Notepad();
notepad.setAddDate(new Date());
notepad.setAddUser("DummyUser");
if("true".equalsIgnoreCase(confidentialValue))
confidentialValue="Y";
else
confidentialValue="N";
notepad.setConfidentiality(confidentialValue);
Long coverageId=getCoverageId(claimNumber);
notepad.setCoverageId(coverageId);
notepad.setDescription(summaryValue);
notepad.setEditUser("DmyEditUsr");
//notepad.setNotepadId(new Long(4)); //auto sequencing
System.out.println(notes);
notepad.setNotes(notes);
notepad.setNoteType(noteTypeValue); //Do we really need this?
notepad.setNoteTypeId(Long.parseLong(notesId));
if("update".equalsIgnoreCase(mode))
{
notepad.setNotepadId(new Long(notepadId));
notepad.setEditDate(new Date());
notepadMapper.updateByPrimaryKeyWithBLOBs(notepad);
}
else
notepadMapper.insertSelective(notepad);
throw new java.lang.UnsupportedOperationException();
}
Not sure where I am going wrong...
The current call is from the controller as given below
#Controller
public class NotesController {
private static final Logger logger = LoggerFactory
.getLogger(NotesController.class);
#Autowired
private Utils utility;
#Autowired
NotepadService notepadService;
public #ResponseBody List<? extends Object> insertNotes(HttpServletRequest request,
HttpServletResponse response,#RequestParam("noteTypeValue") String noteTypeId,
#RequestParam("confidentialValue")String confidentialValue,
#RequestParam("summaryValue")String summaryValue,
#RequestParam("notes")String notes ,
#RequestParam("notesId")String notesId,
#RequestParam("noteTypeValue")String noteTypeValue,
#RequestParam("claimNumber")String claimNumber,
#RequestParam("notepadId")String notepadId,
#RequestParam("mode")String mode) {
try {
notepadService.insertNotes(noteTypeId, confidentialValue, summaryValue, notes, notesId, noteTypeValue, claimNumber, notepadId, mode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
I had the same issue. I am also relatively new to spring. But according to me it depends on how you are calling your insertNotes() method. If you are calling it from another local method then it will not work, because spring has no way of know that it is called and to start the transaction.
If you are calling it from a method of another class by using autowired object of the class which contains insertNotes() method, then it should work.
For example
class ABC
{
#Autowired
NotesClass notes;
public void testMethod() {
notes.insertNotes();
}
}
class NotesClass
{
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRED)
public void insertNotes(String noteTypeId,
String confidentialValue,
String summaryValue,String notes ,
String notesId,String noteTypeValue,
String claimNumber,
String notepadId,
String mode) {
//Your code
}
}
You can try using transaction template. Remove #Tranasactional annotation from method and following code to xml file.
<bean id="trTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="timeout" value="30"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
Create object of Trasactiontemplate and call insertNotes from controller like this
#Autowired
private TransactionTemplate transactionTemplate;
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
insertNotes();
} catch (Exception e) {
transactionStatus.setRollbackOnly();
logger.error("Exception ocurred when calling insertNotes", e);
throw new RuntimeException(e);
}
}
});
Note : You have to make all parameters final before calling insertNotes method

Resources