I'm using spring's JdbcDaoSupport for making data base call. I want to execure native query (sql query) for retrieving data. Do we have any API available in JdbcTemplate for native query? I used queryForObject but it throws exception if there is no data whereas i was expecting it to return back null if it couldn't find data.
There are many options available for executing native sql with JdbcTemplate. The linked documentation contains plenty of methods that take native sql, and usually some sort of callback handler, which will accomplish exactly what you are looking for. A simple one that comes to mind is query(String sql, RowCallbackHandler callback).
jdbcTemplate.query("select * from mytable where something > 3", new RowCallbackHandler() {
public void processRow(ResultSet rs) {
//this will be called for each row. DO NOT call next() on the ResultSet from in here...
}
});
Spring JdbcTemplate's queryForObject method expects your SQL to return exactly one row. If the there are no rows returned or if there are more than 1 row returned it will throw a org.springframework.dao.IncorrectResultSizeDataAccessException. You will have to wrap the call to queryForObject with a try catch block to handle IncorrectResultSizeDataAccessException and return null if the exception is thrown
e.g.
try{
return jdbcTemplate.queryForObject(...);
}catch(IncorrectResultSizeDataAccessException e){
return null;
}
Related
I have a service that handles the insertion of a new record into a MongoDB collection:
public Mono<ProductDto> insertProduct(Mono<ProductDto> in) {
//TODO Must handle Duplicate key inserts --> Throw a ProductAlreadyExistsException
Mono<ProductDto> productDtoMono ;
try{
productDtoMono= in.map(ProductDto::toEntity)
.flatMap(productRepository::insert)
.map(ProductDto::new)
;
}
catch (DuplicateKeyException ex) {
throw new ProductAlreadyExistsException();
}
return productDtoMono;
}
When the ID given is already in use, the application throws a org.springframework.dao.DuplicateKeyException.
I am aware the above code with the try/catch block is incorrect, it is mostly there to demonstrate what I want to do. I am very new to Webflux, and reactive programming... I'd like to find out the correct way to handle this, but I have not been able to find much in the way of decent sample code for exception handling in the service layers for this, it is almost always in the router or request handler layer.
Hoping someone might be able to guide me on this.
The exception would be caught, and the application would throw the new, custom ProductAlreadyExistsException created for this purpose.
I have also tried to do this within the flatMap insert, but at this point I am kind of throwing poop at the wall to see if I can stumble into how it should be done:
public Mono<ProductDto> insertProduct(Mono<ProductDto> in) {
//TODO Must handle Duplicate key inserts --> Throw a ProductAlreadyExistsException
Mono<ProductDto> productDtoMono ;
productDtoMono= in.map(ProductDto::toEntity)
.flatMap(p -> {
try{
return productRepository.insert(p);
}
catch (DuplicateKeyException ex) {
return Mono.error(new ProductAlreadyExistsException());
}
})
.map(ProductDto::new)
;
return productDtoMono;
}
Since DuplicateKeyException is an unchecked exception and not a checked exception (which are quite annoying to use in Reactive code), you can use the onErrorMap()-method here:
public Mono<ProductDto> insertProduct(Mono<ProductDto> in) {
return in.map(ProductDto::toEntity)
.flatMap(productRepository::insert)
.onErrorMap(DuplicateKeyException.class, e -> new ProductAlreadyExistsException())
.map(ProductDto::new);
}
The intermediate productDtoMono variable here is redundant.
If however you need to work with checked exceptions, your last snippet of code is typically how you would do it.
Your first snippet of code does not do what you think it does, the catch-block will never run because Project Reactor catches it before your code does and transforms it into an error signal for downstream operators.
We created a custom item reader which extends AbstractPaginatedDataItemReader. Spring-batch allows to manage which exception stops or not a job (skipped exceptions).
In "classic" spring-batch readers, the doRead method throws any Exception. That means, if a skipped exception is thrown during the read, the item is skipped and the job continues running.
But in paginated readers, the doPageRead method, used to retrieve next data page, doesn't throw any exception:
protected abstract Iterator<T> doPageRead();
The doPageRead method is called by the doRead one:
protected T doRead() throws Exception {
synchronized (lock) {
if(results == null || !results.hasNext()) {
results = doPageRead();
page ++;
if(results == null || !results.hasNext()) {
return null;
}
}
if(results.hasNext()) {
return results.next();
}
else {
return null;
}
}
}
As doPageRead method doesn't declare any thrown exception, that means a configured skipped exception can only be a RuntimeException?
Thanks
A Spring Batch reader is eventually an ItemReader irrespective of it being a paging reader or a non - paging reader. Which eventually means that it will hand over single - single items to processor and read() method contract is all that matters.
Paging readers simply have an optimization about how they actually read an item but no different than than a regular non - paging reader.
So in my opinion, your look out for doReadPage() method seems unnecessary, what matters is read() method contract.
If you are facing any issue ( and that is not clear from your question ) , do let me know.
the code like this:
the exception like this:
java.sql.SQLFeatureNotSupportedException
at com.salesforce.phoenix.jdbc.PhoenixResultSet.first(PhoenixResultSet.java:173)
If you recode your code to use next() instead of first() you'll be fine:
while(resultset.next()) {
//Do something with resultset
}
If you're looking for the why though... you'll have to go and ask the developers of that JDBC driver. As positioning inside a ResultSet requires a scrollable ResultSet, it is possible that this feature simply is not there.
The implementation for ResultSet.first() is not yet done in Apache Phenix. Hence, you get the error.
public boolean first() throws SQLException {
throw new SQLFeatureNotSupportedException();
}
Try using ResultSet.next() function.
Currently i am using spring declarative transaction manager in my application. During DB operations if any constraint violated i want to check the error code against the database. i mean i want to run one select query after the exception happened. So i am catching the DataIntegrityViolationException inside my Catch block and then i am trying to execute one more error code query. But that query is not get executed . I am assuming since i am using the transaction manager if any exception happened the next query is not getting executed. Is that right?. i want to execute that error code query before i am returning the results to the client. Any way to do this?
#Override
#Transactional
public LineOfBusinessResponse create(
CreateLineOfBusiness createLineOfBusiness)
throws GenericUpcException {
logger.info("Start of createLineOfBusinessEntity()");
LineOfBusinessEntity lineOfBusinessEntity =
setLineOfBusinessEntityProperties(createLineOfBusiness);
try {
lineOfBusinessDao.create(lineOfBusinessEntity);
return setUpcLineOfBusinessResponseProperties(lineOfBusinessEntity);
}
// Some db constraints is failed
catch (DataIntegrityViolationException dav) {
String errorMessage =
errorCodesBd.findErrorCodeByErrorMessage(dav.getMessage());
throw new GenericUpcException(errorMessage);
}
// General Exceptions handling
catch (Exception exc) {
logger.debug("<<<<Coming inside General >>>>");
System.out.print("<<<<Coming inside General >>>>");
throw new GenericUpcException(exc.getMessage());
}
}
public String findErrorCodeByErrorMessage(String errorMessage)throws GenericUpcException {
try{
int first=errorMessage.indexOf("[",errorMessage.indexOf("constraint"));
int last=errorMessage.indexOf("]",first);
String errorCode=errorMessage.substring(first+1, last);
//return errorCodesDao.find(errorCode);
return errorCode;
}
catch(Exception e)
{
throw new GenericUpcException(e.getMessage());
}
}
Please help me.
I don't think problem you're describing has anything to do with Transaction management. If DataIntegrityViolationException happens within your try() block you code within catch() should execute. Perhaps exception different from DataIntegrityViolationException happens or your findErrorCodeByErrorMessage() throwing another exception. In general, Transaction logic would be applied only once you return from your method call, until then you could do whatever you like using normal Java language constructs. I suggest you put breakpoint in your error error handler or some debug statements to see what's actually happening.
I'm using LLBLGen and I have some code like so:
if (onlyRecentMessages)
{
messageBucket.PredicateExpression.Add(MessageFields.DateEffective >= DateTime.Today.AddDays(-30));
}
var messageEntities = new EntityCollection<MessageEntity>();
using (var myAdapter = PersistenceLayer.GetDataAccessAdapter())
{
myAdapter.FetchEntityCollection(messageEntities, messageBucket);
}
I'm currently getting a SqlException on the FetchEntityCollection line. The error is:
System.Data.SqlClient.SqlException: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Too many parameters were provided in this RPC request. The maximum is 2100.
but that's a side note. What I actually want to be able to do is include the generated SQL in a custom exception in my code. So for instance something like this:
using (var myAdapter = PersistenceLayer.GetDataAccessAdapter())
{
try
{
myAdapter.FetchEntityCollection(messageEntities, messageBucket);
}
catch (SqlException ex)
{
throw new CustomSqlException(ex, myAdapter.GeneratedSqlFromLastOperation);
}
}
Of course, there is no such property as GeneratedSqlFromLastOperation. I'm aware that I can configure logging, but I would prefer to have the information directly in my stack track / exception so that my existing exception logging infrastructure can provide me with more information when these kinds of errors occur.
Thanks!
Steve
You should get an ORMQueryExecutionException, which contains the full query in the description. The query's execute method wraps all exceptions in an ORMQueryExecutionException and stores the query in the description.
ps: please, if possible ask llblgen pro related questions on our forums, as we don't monitor stackoverflow frequently. Thanks. :)