I am working on a spring MVC application. I have a DAO, Service and Controller. In Dao, I have a method which queries database to return a Sql rowset. I am checking sql rowset to be empty and if it is, I am throwing a Runtime exception. Also, according to the logic of the application, the query to database should return at least one row. So, basically I am assuming that if I get an empty sql rowset, then there is some issue, may be database is corrupt or something similar.
Is this the correct way to check for unknown exceptions. Or should I return the sql rowset as it is to the service? It may result in a null pointer exception when service uses this sql rowset.
The problem is if I throw exception in dao, I can't cover that part in the test cases. Means I have to put db in inconsistent state for this code to execute and test the exception handling part.
No, more generally you should never introduce a restriction into your application just because you don't have that situation or requirement right now. If you don't have any rows in a database your database might just be empty... Or you may be doing testing on that schema and it is currently empty. Your violating the concern of the dao by doing that.
Furthermore don't worry about the database, that is senseless. If you can't accept the tools you are working are functioning correctly then you won't be able to build anything at all. If you want to handle database exceptions have a controller which catches these exceptions and redirects to a view showing an error message:
#ControllerAdvice
public class ErrorHandler {
#ExceptionHandler(DataAccessException.class)
public String handleDatabaseException(DataAccessException ex) {
return "error";
}
#ExceptionHandler(CannotCreateTransactionException.class)
public String handleAccessException(CannotCreateTransactionException ex) {
return "database_error";
}
}
The DAO layer should not concern itself with business rules. It should simply abstract the data operations so that the service layer does not need to concern itself with how and where is the data being stored.
In my opinion, the DAO should simply return an empty result set. It will be up to the service to know what to do with an empty result set, since at the service layer is usually where the business logic is stored.
Related
I'm going to become mad with JPA...
I have a JAX-WS Webservice like that
#WebService
public class MyService
{
#EJB private MyDbService myDbService;
...
System.out.println(dmrService.read());
...
}
My EJB contains
#Stateless
public class MyDbService
{
#PersistenceContext(unitName="mypu")
private EntityManager entityManager;
public MyEntity read()
{
MyEntity myEntity;
String queryString = "SELECT ... WHERE e.name = :type";
TypedQuery<MyEntity> query = entityManager.createQuery(queryString,MyEntity.class);
query.setParameter("type","xyz");
try
{
myEntity= query.getSingleResult();
}
catch (Exception e)
{
myEntity= null;
}
return myEntity;
}
In my persistence.xml the mypu has transaction-type="JTA" and a jta-data-source
If I call the webservice, it's working. The entity is retrieved from the db.
Now, using an external tool, I'm changing the value of one field in my record.
I'm calling the webservice again and ... the entity displayed contains the old value.
If I'm deploying again, or if I'm adding a entityManager.refresh(myEntity) after the request, I have the good value again.
In #MyTwoCents answer, Option 2 is to NOT use your 'external' tool for changes, use your application instead. Caching is of more use if your application knows about all the changes going on, or has some way of being informed of them. This is the better option, but only if your application can be the single access point for the data.
Forcing a refresh, via EntityManager.refresh() or through provider specific query hints on specific queries, or by invalidating the cache as described here https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching#How_to_refresh_the_cache is another option. This forces JPA to go past the cache and access the database on the specific query. Problems with this are you must either know when the cache is stale and needs to be refreshed, or put it on queries that cannot tolerate stale data. If that is fairly frequent or on every query, then your application is going through all the work of maintaining a cache that isn't used.
The last option is to turn off the second level cache. This forces queries to always load entities into an EntityManager from the database data, not a second level cache. You reduce the risk of stale data (but not eliminate it, as the EntityManager is required to have its own first level cache for managed entities, representing a transactional cache), but at the cost of reloading and rebuilding entities, sometimes unnecessarily if they have been read before by other threads.
Which is best depends entirely on the application and its expected use cases.
Don't be mad its fine
Flow goes like this.
You fired a query saying where type="xyz"
Now Hibernate keeps this query or state in cache so that if you fire query again it will return same value if state is not changes.
Now you are updating detail from some external resource.
Hibernate doesnt have any clue about that
So when you fire query again it returns from catch
When you do refresh, hibernate gets detail from Database
Solution :
So you can either add refresh before calling get call
OR
Change the Table value using Hibernate methods in Application so that Hibernate is aware about changes.
OR
Disable Hibernate cache to query each time from DB (not recommended as it will slow down stuff)
I am working on play framework using jpa, I have a field with an unique constraint, after "try" to persist an entity with a repeated value, the framework shows an error page like this:
error page
When I try to catch this exception...
try{
JPA.em().persist(nArtist);
}catch(Exception e){
form.reject("username","user already exist");
return badRequest(create_artist.render(form));
}
The page still shows the message... ( I tried already with rollback exception ).
Pdta: That JPA.em() is the only time I called the em.
The call to EntityManager.persist does not guarantee changes to be flushed to the database immediately (which is the point at which constraint violations would emerge). If you want to force a flush, call EntityManager.flush right after persist
Do not use exceptions to handle conditions that could normally occur in your application and, above all, do not use the generic java.lang.Exception. The exceptions thrown from the persistence layer at persist time could mean a lot more things than the specific constraint violation that you're after
I have to write some methods to change values into database and make some operations on file system.
So I have to make this sequence of step:
Set the boolean Updating field to true into database. It is used to avoid access to file system and database information that are linked with this value (for example a fleet of cars)
Make some operation on the database. For example change the date, name, value or other fields. These changes affect more database tables.
Make change to file system and database
Set the boolean Updating to false
As you can imagine I have to manage errors and start rollback procedure to restore database and file system.
I have some doubt about how I can write my method. I have:
The entity
The repository interface that extends JpaRepositoryand has Query creation from method names and #Query annotated with #Transactional if them write into database (otherwise I recevied error)
The service interface
The service implementation that contains all the method to make simple changes to database. This class is annotated with #Transactional
From the other classes I call service methods to use database but if I call some of these methods I write each value into database so it isn't possible to throw rollback, or I wrong?
The step 1 has to be write immediatly into database instead the other changes should be use #Transactional properties, but just adding #Transactional to my method is enough? For file system rollback I create a backup of all subfolders and restore them in case of error.
For example:
#Transactional(rollbackFor=FileSystemException.class)
private void changeDisplacement(int idApplication, int idDisplacement){
applicationServices.setUpdating(true); //this has be to write immediatly into database so that the other methods can stop using this application
Application application = applicationServices.getId(idApplication);
application.setDisplacement(displacementServices.getId(idDisplacement));
//OTHER OPERATIONS ON DIFFERENT TABLES
//OPERATIONS ON FILE SYSTEM CATCHING ALL EXCEPTION WITH TRY-CATCH AND IN THE CATCH RESTORE FILESYSTEM AND THROW FileSystemException to start database rollback
//In the finally clause use applicationServices.setUpdating(false)
}
Can it work with this logic or the #Transactional field is wrong here?
Thanks
#Transactional is OK here. The only thing is you need to set propagation of applicationServices.setUpdating to REQUIRES_NEW so that it gets committed individually:
public class ApplicationServices {
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void setUpdating(boolean b) {
// update DB here
}
}
In the case of the exceptions, it will still update the DB as long as you have the call to setUpdating in the finally block.
There are multiple questions here and some of them are hard to grasp, here is a bit of input. When you have this:
#Transactional(rollbackFor=FileSystemException.class)
private void changeDisplacement(int idApplication, int idDisplacement){
applicationServices.setUpdating(true);
That flag will hit the database only when the #Transactional finishes. The change stays in hibernate context, until the end of #Transactionl method.
So while you execute changeDisplacement and someone else comes and reads that flag - it will see false (because you have not written it to the DB just yet). You could get it via READ_UNCOMMITTED, but it's up to your application if you allow this.
You could have a method with REQUIRES_NEW and set that flag to true there and in case of revert update that flag back.
Generally updating both the DB and file system is not easy (keeping them in sync). The way I have done it before (might be better options) is register events (once a correct DB was made) and then write to the filesystem.
I'm using Spring Boot and Spring Data.
In the Service Layer, which is better, try to insert the record and catch the "Already Inserted" Exception by the unique key and than translate it into the business exception or use the repository to find the record and than throw the business exception directly?
Database PK is the best approach to maintain uniqueness constraint, if you try approach of querying and checking for PK then you could get in race condition where it will pass the unique check but fails in insert, so any way SQL exception thrown should be handled.
So it is better to handle via Exception and translate to meaning full business error.
this is going long in my mind, i still wonder why spring jdbc made EmptyResultDataAccessException as runtime exception instead of forcing calling method (by making Exception) to catch a EmptyResultDataAccessException, i personally faced an issue , when i first implement spring jdbc, let us take this first scenario
public List<User> getUsers(String firstName){
JdbcTemplate jd = this.getJdbcTemplate();
List<User> userLst = jd.query("select query for user here matched firstname", BeanPropertyRowmapper(User.class))
}
in the above scenario even if this select query doesnt return any value, spring jdbc still creates new List object of type user and returns list object with size 0. so here spring jdbc is not throwing EmptyResultDataAccessException , instead it is creating new List object if there is no rec fetched from DB.
secondly, in case for querying for an object, it behaves differently.
User user = jd.queryForObject("select * from user where user_id = [EDITuser id here", User.class)
here spring jdbc throws EmptyResultDataAccessException incase it didnt find any record for *user_id = 1*.
more over, since EmptyResultDataAccessException is runtime exception, i was not forced to catch this exception and do some action for this exception, so most of time developer puzzled and it go unnoticed.
as i said in the first scenario , when i first coded, i was expecting userLst object as null, but actually spring jdbc creates new object which we didnt handle it.
posting this to make myself clear on this aspect. Thanks
There is most probably no way to make everyone happy. Take the contrary, you perfectly know that the row exists because it's a valid ID. Yet, calling this method forces you to catch this exception that will never be thrown so you have an empty catch block, which is bad.
This goes back to the use of runtime exception vs. checked exception, there are plenty of references on this site and elsewhere.