JavaEE:能不能使用ThreadLocal+过滤器优化Mybatis的事务控制?

使用一个名为OpenSessionInView的servlet过滤器,统一mybatis的事务处理。

 

 


一、情况分析

Mybatis的使用过程:

  1、获取配置文件

  2、获取session工厂

  3、获取session对象

  4、进行sql操作,获取对应结果

  5、提交事务

  6、关闭session对象

  其中,我们一般只需要关注第4步。

ThreadLocal的原理:
  它用于存放每个线程自己的独立数据。参考:Java:ThreadLocal是什么?

servlet中过滤器:

  它会在servlet执行前后,进行过滤操作。

  处于同一线程下。

  即可以在过滤器中进行session的管理(创建、提交、回滚、关闭)。

  参考:Servlet_2_过滤器


二、具体方案

  1、创建一个MybatisUtils工具类,它负责sesion的创建和关闭。对于同一个线程,它只提供一个session对象。

/**
 * 一个线程中,通过getSession获取,始终是同一个session对象
 * @author lurenjia
 * @date 2023/2/19-17:19
 */
public class MybatisUtils {

    /**
     * 同一线程共享的空间
     */
    private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();
    
    /**
     * 工厂只有一个
     */
    private static SqlSessionFactory factory = null;
    //初始化工厂
    static {
        try {
            //获取配置文件
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //获取工厂
            factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 获取session对象,一个线程只能获取到同一个
     * @return
     */
    public static SqlSession getSession(){
        SqlSession session = tl.get();
        //如果线程中没有session对象,则创建一个
        if(tl.get()==null){
            tl.set(factory.openSession());
        }
        return tl.get();
    }
    /**
     * 关闭线程中的session对象
     */
    public static void close(){
        SqlSession session = tl.get();
        if(session!=null){
            session.close();
        }
        tl.set(null);
    }
    private MybatisUtils(){}
}

  2、创建一个过滤器。在过滤方法中对session进行管理。

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //统一编码格式
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");

        //获取到这个线程的session
        SqlSession session = MybatisUtils.getSession();
        try {
            //放行,让它去找它的servlet服务处理
            filterChain.doFilter(servletRequest, servletResponse);

            //处理完了提交事务
            session.commit();
        } catch (Exception e) {
            //出现异常了,回滚!
            session.rollback();
        } finally {
            //关闭资源
            MybatisUtils.close();
        }
    }
posted @ 2023-02-19 18:23  在博客做笔记的路人甲  阅读(46)  评论(0编辑  收藏  举报