Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MyBatis mapper injected directly into service class. What about exceptions?

I'm currently working with MyBatis-Spring integration framework and that's what I read from docs:

Rather than code data access objects (DAOs) manually using SqlSessionDaoSupport or SqlSessionTemplate, Mybatis-Spring provides a proxy factory: MapperFactoryBean. This class lets you inject data mapper interfaces directly into your service beans. When using mappers you simply call them as you have always called your DAOs, but you won't need to code any DAO implementation because MyBatis-Spring will create a proxy for you.

That's a very nice feature... but what about exception handling? Where should I translate SQL errors? In my service layer? But wouldn't it violate service-DAO patterns?

Example:

public final class AccountServiceImpl implements AccountService {
(...)
    private AccountMapper accountMapper;
(...)
    @Override
    public void addAccount(Account account) throws AccountServiceException {

       //Validating, processing, setting timestamps etc.
       (...)

       //Persistence:
       int rowsAffected;
       try {
            rowsAffected = accountMapper.insertAccount(account);
       } catch (Exception e) {
            String msg = e.getMessage();
            if (msg.contains("accounts_pkey"))
                throw new AccountServiceException("Username already exists!");
            if (msg.contains("accounts_email_key"))
                throw new AccountServiceException("E-mail already exists!");
            throw new AccountServiceException(APP_ERROR);
       }

       LOG.debug("Rows affected: '{}'", rowsAffected);

       if (rowsAffected != 1)
            throw new AccountServiceException(APP_ERROR);
    }

Is it OK to translate exceptions in service layer?

How should it be done?

Thanks in advance for you advice.

like image 267
Maciej Ziarko Avatar asked Jan 04 '12 14:01

Maciej Ziarko


People also ask

What is the difference between iBATIS and MyBatis?

MyBatis is a fork from iBATIS, and according to Wikipedia most of iBATIS' developers moved over to MyBatis too. The iBATIS project is currently marked as Inactive, therefore you should go with MyBatis for new projects and only use iBATIS if you're maintaining an existing project which already uses iBATIS.

Can I pass a list as a parameter to a MyBatis Mapper?

NOTE You can pass any Iterable object (for example List, Set, etc.), as well as any Map or Array object to foreach as collection parameter.

What is mapper in MyBatis?

Mapper XML is an important file in MyBatis, which contains a set of statements to configure various SQL statements such as select, insert, update, and delete. These statements are known as Mapped Statements or Mapped SQL Statements. All the statements have unique id.

How does Spring Boot Work With MyBatis?

Spring Boot provides mechanisms that simplify the configuration of MyBatis with Spring even more. By default, if we use an auto-configuration feature, Spring Boot detects the H2 dependency from our classpath and configures both Datasource and SqlSessionFactory for us. In addition, it also executes both schema.


2 Answers

Having recently used mybatis-spring for a project I came across the same stumbling block. I also didn't want to litter my service class with DAO exception handling, particularly since some methods in my service layer required read-only access to a lot of different tables.

The solution I arrived at was to catch the exceptions in the service layer but create your own exception type that takes the caught exception as a parameter. This can then filter out what kind of error message should be contained when the exception is actually constructed and remove the need for string matching (in the service layer at least).

You are close to that there, except the AccountServiceException would have a constructor that took the Exception e as a parameter. I also chose to try and do all my data access as early as possible and wrap it all in a single try/catch. Since the MapperFactoryBean always translates thrown exceptions in to Spring DataAccessExceptions you don't have to worry about catching other kinds of exceptions when doing data access.

I hesitate to consider this an answer as such - more of a sharing of experience given I came across that and hesitated as well.

like image 79
BeRecursive Avatar answered Nov 04 '22 00:11

BeRecursive


Translating low level DataAccessExceptions thrown by MyBatis to application-defined ones in service layer is a standard practice.

It's usually connected to transaction handling as you can't handle the transaction spanning multiple DAOs in DA layer.

So yes it's OK and even recommended.

Normally I log the exceptions thrown by DAO in error log and rethrow something defined by application.

like image 27
soulcheck Avatar answered Nov 04 '22 01:11

soulcheck