JavaEE:能不能使用ThreadLocal+过滤器优化Mybatis的事务控制?
使用一个名为OpenSessionInView的servlet过滤器,统一mybatis的事务处理。
一、情况分析
Mybatis的使用过程:
1、获取配置文件
2、获取session工厂
3、获取session对象
4、进行sql操作,获取对应结果
5、提交事务
6、关闭session对象
其中,我们一般只需要关注第4步。
ThreadLocal的原理:
它用于存放每个线程自己的独立数据。参考:Java:ThreadLocal是什么?
servlet中过滤器:
它会在servlet执行前后,进行过滤操作。
处于同一线程下。
即可以在过滤器中进行session的管理(创建、提交、回滚、关闭)。
二、具体方案
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(); } }