在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 { } }