2

I am trying to find a solution to build reliability into our webapp. The plan is to dump sql along with data if network connectivity/database connection is lost. In current implementation we have Rest controller, Service, DAO. The DAO throws PersistenceExcetpion, and that is propagated till the Controller layer.

Example code:

public MyDAOClass {
    public void save(Object object) {
        try {
            entityManager.persist(object);
        } catch (PersistenceException e) {
            throw new DBException("Error occurred in save", e);
        }
    }
}

The DBException is a runtime exception.

Now the comes the actual question. One of the teammate suggested to have custom exceptions like for eg. InsertException, UpdateException etc. And if we encounter any of these exceptions we know which operation was performed on that entity so that it can be saved to a file as appropriate sql.

For example. Lets say the code failed to save Employee entity. This will throw InsertException, and will create an entry in file as insert sql statement for that entity. insert into employeee values ('firstname','lastname');

For me the idea of implementing the creation of sql file when connectivity is lost doest not seem to be as simple as implementing the above.

The questions that I have put forward are 1) How do you handle when multiple actions (like any combination of insert, update, delete) are performed in the service method ? 2) What about different exceptions ? I mean the reason for PerisistenceException can be anything like constraint failure, entity not found etc and not just the connection issue.

Is there any way to implement the above scenario which also considers all the different conditions.

Thanks.

Update: Based on comments by chrylis. I should have already added this to the question. It's a webapp running locally in different retail stores. And the application can't have a downtime, so if any connectivity issues, the app should keep work. The file will be later synched with the central database server.

HereToLearn
  • 153
  • 1
  • 2
  • 10
  • This sort of rolling your own sounds like an absolutely terrible idea. Among other things, you'd have to secure these files, somehow deal with transactionality, and coordinate across multiple application instances, all for no benefit (since clients have to deal with other failures anyway). Just return a 5xx error. – chrylis -cautiouslyoptimistic- Dec 20 '15 at 04:37
  • (And just use Spring Data for your DAOs.) – chrylis -cautiouslyoptimistic- Dec 20 '15 at 04:37
  • @chrylis I have updated the question with some more information. Regarding your comment. There is no existing solution for the issue. By transactionality you mean while writing to the file ? In this case the coordination is not required since the data will be specific to the store. – HereToLearn Dec 20 '15 at 04:56
  • So this sounds like what you actually need is a two-layer database, where one layer is local to each store (e.g., local inventory) and gets synchronized periodically to the central database. For inserts, a type 1 UUID (Hibernate provides a generator) would keep each store's records from colliding while preserving locality. – chrylis -cautiouslyoptimistic- Dec 20 '15 at 05:00

1 Answers1

0

With spring you have Hibernate ORM that will store the data to the database. If an exception occurs during any request it will be rolled back by hibernate. This depends on where you'we put the @Transnational annotation.

We use a Service layer that handles the transaction. So if a database operation or any other operation fails in the service layer and throws an exception the transaction is auto rolled back by hibernate. We then use a spring exception resolver to handle any exception and write custom errors in the log and to the user. I guess you could store the exception in another database as well if that is interesting I think logging them should suffice though.

This article teaches you more about general exception handling.

Here is our exception resolver.

import ...

@ControllerAdvice
public class SpringExceptionResolver {

    Logger logger = LoggerFactory.getLogger("com.realitylabs.event.controller.RecoverController"); 


    @ExceptionHandler({CorruptedSessionUserException.class})
    @ResponseBody
    @ResponseStatus(value=HttpStatus.FORBIDDEN)
    public ErrorObject userNotFoundExceptionHandler() {
      // Handle exception
      // log using the logger.
      // We usually return an error object in JSON so that we can show custom    // error messages.
    }


}

Here is how a service might look. We usually call our services from the controllers. If an exception is thrown when coming from a controller the advice will handle it.

import ...

@Service(value="ObjectService")
@Transactional
public class ObjectServiceImpl implements ObjectService {

  @Autowired
  private ObjectDAO objectDAO;

  @Override
  public Object get(int id) {
    Object o = objectDAO.get(id);
    Hibernate.initialize(o.getVoters());
    return o;
  }

}

I hope this helps.

Pablo Jomer
  • 9,870
  • 11
  • 54
  • 102
  • I read the article you linked. I think the challenge is to identify the operations performed in the service so that appropriate sql statements can be written to the file. For example a service performs some inserts, some updates & if there is any database connectivity issue occurs, peform the same operations but to the file. So the file should have the same inserts & update statements. – HereToLearn Dec 21 '15 at 05:35
  • I don't quite understand quite what you are getting at. How error critical is your software? Is it fine for a database query to return an error to the user? If it isn't then you might need to architecture your system in some other way. Try and explain in more detail what you need. Thank you. – Pablo Jomer Dec 21 '15 at 07:56