javamybatisinvocationhandler

Using invocation handler to open and close SQL session


I am using Mybatis to make a CRUD application for a database and since all of my methods contain repetitive code when opening and closing an SQL session I would like to use an invocation handler to minimize the code repetition. Almost all of my methods look something like this:

public int deleteDefDialog(DefDialog defDialog) {
    SqlSession sqlSession = ConnectionFactory.getSqlSessionFactory()
            .openSession();
    try {
        DialogMapper dialogMapper = sqlSession
                .getMapper(DialogMapper.class);
        int i = dialogMapper.deleteDefDialog(defDialog);
        sqlSession.commit();
        return i;
    } finally {
        sqlSession.close();
    }
}


public DefDialog selectDefDialog(BigDecimal i) {
    SqlSession sqlSession = ConnectionFactory.getSqlSessionFactory()
            .openSession();
    try {
        DialogMapper dialogMapper = sqlSession
                .getMapper(DialogMapper.class);

        return dialogMapper.selectDefDialog(i);
    } finally {
        sqlSession.close();
    }
}

My question is how do I properly write and call the invocation handler, keeping in mind that the application remains thread-safe?


Solution

  • I solved the problem so I will answer my own question, the proper way to open and close an sql session using an invocation handler was to store the sqlSession in ThreadLocal.

    ConnectionHandler.java

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.apache.ibatis.session.SqlSession;
    
    public class ConnectionHandler implements InvocationHandler {
    
    private Object obj;
    
    private static final ThreadLocal<SqlSession> session = new ThreadLocal<SqlSession>();
    
    public static SqlSession getSession(){
        return session.get();
    }
    
    public static Object newInstance(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new ConnectionHandler(obj));
    }
    
    private ConnectionHandler(Object obj) {
        this.obj = obj;
    }
    
    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result = null;
    
        SqlSession sqlSession = ConnectionFactory.getSqlSessionFactory()
            .openSession(); 
        session.set(sqlSession);
        try {
            result = m.invoke(obj, args);
            sqlSession.commit();
        } catch (Exception e) {
            sqlSession.rollback();
            throw e;
        } finally {
            sqlSession.close();
        }
        return result;
    }
    }
    

    and change the above class to

    DialogServiceImpl.java

    public int deleteDefDialog(DefDialog defDialog) {
        DialogMapper dialogMapper = ConnectionHandler.getSession()
                .getMapper(DialogMapper.class);
        int i = dialogMapper.deleteDefDialog(defDialog);
        return i;
     }
    
    
    public DefDialog selectDefDialog(BigDecimal i) {
        DialogMapper dialogMapper = ConnectionHandler.getSession()
                .getMapper(DialogMapper.class);
        return dialogMapper.selectDefDialog(i);
    }
    

    and call the function like this

        DialogService ds = (DialogService) ConnectionHandler.newInstance(new DialogServiceImpl());
        ds.removeDefDialog(defDialog);