There are two Oracle functions that I need to call from a Spring Boot application. They are both in the same schema. One of the functions takes a String input value. The call to that function returns the expected result with no errors. The other function takes no input values. The call to that function results in the following exception: java.sql.SQLException: Missing IN or OUT parameter at index:: 1. I'm not sure why this is happening. I'll show the code for both the Oracle function and the Spring Boot call below.
Oracle Function:
create or replace FUNCTION "GETUNIQUEID" RETURN VARCHAR2
IS
returnuniqueid VARCHAR2(26);
BEGIN
SELECT to_char(sysdate, 'MMDDYY-HH24MISS-')||manchester.globalpid.nextval INTO returnuniqueid FROM DUAL;
RETURN (returnuniqueid);
END GETUNIQUEID
Spring Boot code:
#Autowired
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall simpleJdbcCallFunction;
#Override
public void run(String... args) throws Exception {
simpleJdbcCallFunction = new SimpleJdbcCall(jdbcTemplate)
.withFunctionName("GETUNIQUEID");
String uniqueId = simpleJdbcCallFunction.executeFunction(String.class);
}
The exception thrown is java.sql.SQLException: Missing IN or OUT parameter at index:: 1
Thanks very much for taking a look at this issue.
Related
I have a springboot application that needs to iterate over a large number of records and call a stored procedure which inserts some data in a table for each record read.
we cannot use BatchUpdate because it is taking a long time to process thousands of records , I was asked to commit frequently (either after every record or after x records)
I was looking online and I did not see a good example on how to commit manually in springboot while calling a stored procedure in a loop.
I am using SimpleJdbcCall and my code looks like this:
#Transactional(isolation = Isolation.READ_UNCOMMITTED,propagation = Propagation.NOT_SUPPORTED)
public class EventsProcessor
{
#Autowired
#Qualifier("dbDatasource")
DataSource dataSource;
public void process(List<Event> events) throws Exception
{
SimpleJdbcCall dbTemplate = new SimpleJdbcCall(dataSource).withProcedureName("UPDATE_EVENTS").withSchemaName("TEST");
DataSourceUtils.getConnection(dataSource).setAutoCommit(false);
for (Event ev : events)
{
//fill inParams here
outParams = dbTemplate.execute(inParams);
DataSourceUtils.getConnection(dataSource).commit();
}
}
}
I tried without Propagation.NOT_SUPPORTED and with it but same result.
The code is executing the call to the sp and there is not error when it executes commit() , but after commit() if I query the table that the sp inserted the record in it, I don't see the records in the table.
If I remove the setAutocommit(false) and the commit statement and the Propagation.NOT_SUPPORTED , and just let springboot handle transactions, then while it's processing, I can see the records in the table if I do READ UNCOMMITTED, but they will not be committed till the full job ends.
What am I doing wrong that is preventing the commit to happen after each row?
I ended up separating the call to the SP into a different method with
#Transactional(propagation = Propagation.REQUIRES_NEW)
This way when it returns from the method, it commits.
I am doing few hibernate save operations in spring's transactional service class.
My expectation is that by the time method execution finishes hibernate should write data to database.
But hibernate is actually executing those queries only when controller is about to return a response.
My sample code is as follows.
#Controller
public class TestController {
#Autowired
private SaveService saveService;
#RequestMapping(value = "saveData", method = RequestMethod.POST)
public String saveData(HttpServletRequest request, Model model) {
try {
saveService.saveData(object1, object2, object3); // LINE 1
sendEmail(); // LINE 2
//some code here // LINE 3
} catch(Exception e) {
//log exception
//return error message
}
}
}
#Service("saveService")
#Transactional
public class SaveServiceImpl implements SaveService {
#Autowired
private SaveDAO saveDAO;
public void saveData(Object objec1, Object objec2, Object objec3) {
saveDAO.save(object1);
saveDAO.save(object2);
saveDAO.save(object3);
}
}
In above code I am calling SaveService.saveData() method from controller. And if save is successful I want to go ahead and send an email. But if for some reason SaveService.saveData() throws an exception i don't want
to send the email.
When I performed some tests it was observed that even if SaveService.saveData() throws an exception it's not thrown
until the email is sent from controller. I want that if a call to saveService.saveData() at 'LINE 1' in controller
throws an exception the next line that sends email should not get executed.
I wanted to know if this is expected hibernate behavior and if it is what can I do to tell hibernate to execute
queries before exiting service methods.
Thank you.
This behavior is due to hibernate optimizations. Hibernate will wait until the last time possible to execute the sentences.
You can avoid this with session.flush(), Flushing the session forces Hibernate to synchronize the in-memory state of the Session with the database (i.e. to write changes to the database).
The problem here is when an exception occurs, your the variables/objects are not initialized in the catch block and you are accessing it.
As it looks like you have just added a snippet of the code in question, so I guess the variables object1, object2, object3 needs to initalized to null.
for example: object1=null
I am implementing a filter which, under certain conditions, has to make inserts in some tables.
First of all I call my result handler like this:
DateTime midnight = ...//date
MyHandler handler = new MyHandler();
MyFilter filterChain = new MyFilter();
handler.addFilter(filterChain);
//query is a select based on the date passed as parameter
session.select("com.MyRequestMapper.getAllRequests", midnight.toDateTime(), handler);
This is my handler:
#Component
public class MyHandler implements ResultHandler{
#Autowired
private AnotherTableMapper mapper;
...
public void handleResult(ResultContext ctx){
MyRequest req = (MyRequest)ctx.getResultObject();
if(this.filter.apply(req))
mapper.insertRequest(req);
}
This insert gives me the following:
### Error querying database. Cause: java.lang.NullPointerException
### The error may exist in com/MyRequestMapper.java (best guess)
### The error may involve com.MyRequestMapper.getAllRequests
### The error occurred while handling results
### SQL: SELECT* FROM MY_REQUESTS where request_date = ?
### Cause: java.lang.NullPointerException
...but I am performing an insert not a select! And on top of that the insert is not made on All_REQUESTS table!
Why is that?
The below code is not working for rollback when any exception occurs while insertion of records in database.I am using Spring 4 framework and annotation .
*/I am using below code for transaction management and it will not roll back for any exception./
#Transactional(rollbackFor = RuntimeException.class)
public boolean insertBatch(List<String> query) throws SQLException {
boolean flag= false;
try
{
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] Sql= query.toArray(new String[query.size()]);
jdbcTemplate.batchUpdate(Sql);
flag=true;
}catch(DataAccessException e )
{
flag=false;
MessageResource.setMessages("Constraints Violation ! CSV data value not matched with database constraints ");
LOGGER.info("CSV file Data not expected as database table structure defination like constraint violation/Data Type lenght/NUll etc for same data value" );
LOGGER.error( "Cause for error: "+ e.getRootCause().getMessage());
LOGGER.debug( "Details explain : "+ e.toString());
throw new RuntimeException("Roll back operation");
//transactionManager.rollback(status);
}
return flag;
}**
Actullay answaer provided by Sir, M.Deinum is below:
Spring uses proxies to apply AOP this will only work for methods called from the outside. Internal method calls don't pass through the proxy hence no transactions and depending on your queries you get one large or multiple smaller commits. Make sure that the outer method (the one called to initiate everything) is transactional. – M. Deinum 14 hours ago
#Transactional(rollbackFor = RuntimeException.class)
This will rollback only if a RuntimeException or a subclass is thrown from the annotated method. If you want to rollback for any Exception (such as SQLException, which is NOT a RuntimeException), you should do:
#Transactional(rollbackFor = Exception.class)
And if you want to try a rollback for whatever error that might happen
#Transactional(rollbackFor = Throwable.class)
Altough in this last case the runtime might be so broken that not even the rollback can complete.
Use Prepared statement from connection object and the do a execute batch object. On the connection object use conn.setAutoCommit(false). Prepeared statement has 4 times better performance than JdbcTemplate for batch insertion of 1000 records.
Reference : JdbcTemplate.batchUpdate() returns 0, on insert error for one item but inserts the remaining item into sql server db despite using #Transactional
I'm using the following code for passing java array to stored procedure
<select id="abcd" parameterType="java.util.Map" statementType="CALLABLE">
{call PKG_xyz.PR_cbcd(
#{p_array,jdbcType=ARRAY,typeHandler=org.apache.ibatis.type.ArrayTypeHandler,mode=IN},
#{p_ids,jdbcType=INTEGER,mode=IN},
#{p_comments,jdbcType=VARCHAR,mode=IN},
#{p_return_code,jdbcType=INTEGER,mode=OUT},
#{p_msg_out,jdbcType=VARCHAR,mode=OUT}
)}
</select>
here, p_array is my java array. But i'm getting the following error -->
"Error setting null for parameter #1 with JdbcType ARRAY . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: Invalid column type: sqlType=2003"
Could somebody please help....
Thanks in advance...
Try to write your custom TypeHandler like
public class ArrayTypeHandler implements TypeHandler<YourArrayObject[]>{
}
Override this method below to set oracle.sql.ARRAY to PreparedStatement:-
public void setParameter(PreparedStatement ps, int i,
YourArrayObject[] parameter, JdbcType jdbcType) throws SQLException {}
This url might help you do the same:-
How to Pass Java List of Objects to Oracle Stored Procedure Using MyBatis?
Similarly, override getResult() method to get OUT array paramter