在web應用中常見的3層架構:控制層(Controller)、業務邏輯(Service)、數據持久層(DAO),控制層調用業務邏輯層,業務邏輯層調用數據層。web
這樣:sql
)數據庫
解耦,變成這樣:緩存
首先新建DAO工廠類dao.factory.DaoFactory
, 用於建立DAO對象:安全
/** * dao工廠 * * 注意:工廠類會在類加載的時候爲每種DAO只會建立一個dao對象,因此DAO實現類中 * 不能經過對象包含數據庫鏈接,應該經過ThreadLoacl<Connection>實現每線程一個鏈接 * @author * */ public class DaoFactory { /* 保存全部的Dao對象 */ private static final HashMap<Class<?>,Object> DAO_MAP = new HashMap<>(); static { try { init(); } catch(Exception e) { // 日誌記錄 } } private static void init() { DAO_MAP.put(ManagerDao.class, new ManagerDaoImpl()); DAO_MAP.put(OrderDao.class, new OrderDaoImpl()); DAO_MAP.put(SchoolDao.class, new SchoolDaoImpl()); DAO_MAP.put(UserDao.class, new UserDaoImpl()); } @SuppressWarnings("unchecked") public static<T> T getDao(Class<T> clazz) { // 注:clazz類對應的對象不存在,應該拋出異常 return (T) DAO_MAP.get(clazz); } }
而後在業務邏輯層實現類中,注入Dao對象,以下:mybatis
/** * 用戶服務類 */ public class UserServiceImpl implements UserService { // 經過工廠方式注入 private UserDao userDao = DaoFactory.getDao(UserDao.class); ... }
遵循開閉原則,新建DAO實現類,只須要工修改廠類便可。多線程
注:能夠給DAO實現類添加自定義註解的方式,而後DAO工廠類經過反射,掃描出有指定註解的類,進行注入。架構
注意多線程問題:app
Dao層和Service層均爲「實際單例」緩存到map中,Service中持有dao成員變量,Servlet控制層持有service成員變量,因爲Dao的使用的數據庫鏈接來自於ThreadLocal變量,因此是線程安全的類,service只持有線程安全的類對象,因此也是線程安全的,同理上推。ide
然而,在我使用mybatis的過程當中,出現了錯誤!提示「Executor 已經關閉」,mybatis官方資料顯示mapper和sqlSession具備一樣的聲明週期,均是線程不安全的。此時對象之間的關係是Servlet包含service變量,service變量持有mapper對象,mapper對象對應的sqlSession會在一次請求後關閉(一個線程執行後), 此時再次執行會提示類時數據庫鏈接以及關閉的問題!!!
在過濾器中關閉的SqlSession:
/** * 系統服務過濾器 * 過濾字符編碼 * @author * */ public class OESServiceFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); try{ chain.doFilter(req, resp); }finally{ // 關閉SqlSession MybatisUtil.closeSqlSession(); } } @Override public void init(FilterConfig config) throws ServletException { } }