天天看點

light-4j單獨使用mybatis出現Executor was close問題錯誤分析代碼分析解決方法

最近用light-4j的項目在正式環境偶爾報Executor was close問題 導緻sql有時執行失敗

light-4j單獨使用mybatis出現Executor was close問題錯誤分析代碼分析解決方法

錯誤分析

這個錯誤看起來像是兩個程序 A程序在對資料庫操作的時候 B程序将sqlSession關閉了 但是想不通在哪裡關閉的

代碼分析

封裝了一個單例的sessionFactory

public class SqlSessionFactoryHelper {
    //首先建立靜态成員變量sqlSessionFactory,靜态變量被所有的對象所共享。
    public static SqlSessionFactory sqlSessionFactory;
    private SqlSessionFactoryHelper() {}
    //使用靜态代碼塊保證線程安全問題
    static{
        if(sqlSessionFactory==null) {
            try {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //獲得一個session
    public static SqlSession getSession(boolean autoCommit){
        SqlSession session= sqlSessionFactory.openSession(autoCommit);
        return session;
    }
}
           

感覺這裡并沒有什麼問題 繼續看service層

public class UserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);

    private SqlSession sqlSession;
    private UserDao userDao;

    void getUserDao (boolean autoCommit){
        sqlSession= SqlSessionFactoryHelper.getSession(autoCommit);
        userDao = sqlSession.getMapper(UserDao.class);
    }

    /**
     * 根據id查找使用者脫敏
     * @param userId
     * @return
     * @throws ServiceException
     */
    public User findByUserIdSafe(Integer userId) throws ServiceException {
        getUserDao(Boolean.TRUE);
        try {
            return userDao.findByUserIdSafe(userId);
        }catch (Exception e){
            LOGGER.error(e.getMessage());
            throw new ServiceException("查詢使用者資訊失敗:"+e.getMessage());
        }finally {
            sqlSession.close();
        }
    }
}
           

這裡看起來也沒有問題 根據需求決定擷取一個是否需要自動送出的sqlSession 然後調用dao層擷取資料 在finally裡邊關閉sqlSession 并不會有線程沖突啊 繼續看看控制層

/**
 * 獲得使用者資訊
 */
public class GetUserHandler implements HttpHandler {

    private UserService userService = new UserService();

    @Override
    public void handleRequest(HttpServerExchange exchange) throws Exception {
        exchange.getRequestReceiver().receiveFullString((exchangeCopy, message) -> {
            exchangeCopy.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain; charset=utf-8");
            JsonResultHelper jsonResult = new JsonResultHelper();
            Map<String, Deque<String>> queryParam = exchange.getQueryParameters();
            String userId = queryParam.get("userId") == null ? "" : queryParam.get("userId").getFirst();
            if(!StringHelper.isNumeric(userId)){
                jsonResult = new JsonResultHelper(JsonResultHelper.FAIL,"輸入參數錯誤!");
            }else {
                try{
                    User user = userService.findByUserIdSafe(Integer.parseInt(userId));
                    if(user==null){
                        jsonResult = new JsonResultHelper(JsonResultHelper.FAIL,"使用者不存在!");
                    }else{
                        jsonResult = new JsonResultHelper(user);
                    }
                }catch (ServiceException e){
                    jsonResult = new JsonResultHelper(JsonResultHelper.FAIL,e.getMessage());
                }catch (Exception e){
                    e.printStackTrace();
                    jsonResult = new JsonResultHelper(JsonResultHelper.FAIL,"處理錯誤,請聯系管理者!");
                }
            }
            exchangeCopy.setStatusCode(StatusCodes.OK);
            exchangeCopy.getResponseSender().send(jsonResult.toJsonStr(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES));
        }, Charset.forName("UTF-8"));
    }
}
           

這裡加了

system.out.print(userService);

以後發現多次請求調用了同一個service對象 檢視了light-4j文檔後 發現隻在項目啟動時對handler進行初始化 由于之前習慣了Spring的代碼風格 把service對象定義成了類成員變量 并且在service層中将變量SqlSession也定義成了類成員變量 導緻資料庫操作頻繁時會互相影響 出現這次問題

解決方法

将service調用方式改為

User user = new UserService().findByUserIdSafe(Integer.parseInt(userId));
           

這種調用方式 問題解決

繼續閱讀