• 【MyBatis】mybatis工具类迭代


     目录

    MyBatis工具类的迭代

    ThreadLocal使用

    mybatis工具类终极版:


    MyBatis工具类的迭代

    1. public class MyBatisUtil {
    2.      //工具类构造方法私有化
    3.      private void MyBatisUtil() {
    4.     }
    5.      //方法一
    6.      public static SqlSession getSqlSession(){
    7.          try {
    8.              SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    9.              SqlSessionFactory build = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("UserMapper.xml"));
    10.              SqlSession sqlSession = build.openSession();
    11.              return sqlSession;
    12.         } catch (IOException e) {
    13.             throw new RuntimeException(e);
    14.         }
    15.     }

    弊端:每次调用都会创建sqlSessionFactoryBuilder、SqlSessionFactory等大量对象,创建的对象太多,造成资源浪费

    1.    //方法二
    2.      private static SqlSession sqlSession = null;
    3.      static {
    4.          try {
    5.              sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("UserMapper.xml")).openSession();
    6.         } catch (IOException e) {
    7.              throw new RuntimeException(e);
    8.         }
    9.     }
    10.  //   弊端:调用一次mybatisutil就创建好了sqlsession,此后的每次调用会公用一个sqlsession对象;  

    弊端:由于sqlsession对象的创建是在static静态代码块中的,所以第一次调用mybatisutil就创建好了sqlsession,此后的每次调用会公用一个sqlsession对象;这样也是不行的事物这一块会有问题,然后你每次创建会话的目的就是区分和记录不同的会话,他要一样岂不是不符合初期的设计了;

    1.  //方法三
    2.      private static SqlSessionFactory sqlSessionFactory = null;
    3.      static {
    4.          try {
    5.              sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("UserMapper.xml"));
    6.         } catch (IOException e) {
    7.              throw new RuntimeException(e);
    8.         }
    9.     }
    10.      public SqlSession getSqlSession() {
    11.          return sqlSessionFactory.openSession();
    12.          //每调用一次方法,创建一个sqlsession对象,不共用
    13.     }

    之前的这些工具类,刚刚开始学习mybatis时足以使用,但是随着学习的增进,代码量的增大,业务的变多,使用以上工具类就会出现很多的事务问题,例如下面这串代码:

    1.  public class AccountServiceImpl implements AccountService {
    2.   private AccountDao accountDao = new AccountDaoImpl();
    3.   @Override
    4.   public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    5.   // 查询转出账户的余额
    6.   Account fromAct = accountDao.selectByActno(fromActno);
    7.   if (fromAct.getBalance() < money) {
    8.   throw new MoneyNotEnoughException("对不起,您的余额不⾜。");
    9.   }
    10.   try {
    11.   // 程序如果执⾏到这⾥说明余额充⾜
    12.   // 修改账户余额
    13.   Account toAct = accountDao.selectByActno(toActno);
    14.   fromAct.setBalance(fromAct.getBalance() - money);
    15.   toAct.setBalance(toAct.getBalance() + money);
    16.   // 更新数据库(添加事务)
    17.   SqlSession sqlSession = SqlSessionUtil.openSession();
    18.   accountDao.update(fromAct);
    19.   // 模拟异常
    20.   String s = null;
    21.   s.toString();
    22.   accountDao.update(toAct);
    23.   sqlSession.commit();
    24.   sqlSession.close();
    25.   } catch (Exception e) {
    26.   throw new AppException("转账失败,未知原因!");
    27.   }
    28.   }
    29.  }

    很明显,这串代码会报错。虽然我们在代码中开启了事务管理,但是代码中使用了大量的sqlsession对象,所以导致sqlsession的重复出现导致事务管理出错;错误原因在于空指针异常,第一个update事务提交了,然而第二个update的事务没有提交,最开始开启的sqlsession事务对象并不能控制整个转账过程,原因就是每个update都有属于自己的sqlsession,也就是说他们各自使用的sqlsession都不一样,所以我们如何解决?

    那就是让它们使用同一个sqlsession,如何做到呢?使用threadlocal

    ThreadLocal使用

    修改工具类;

    mybatis工具类终极版:

    1.  public class SqlSessionUtil {
    2.   private static SqlSessionFactory sqlSessionFactory;
    3.   /**
    4.   * 类加载时初始化sqlSessionFactory对象
    5.   */
    6.   static {
    7.   try {
    8.   SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    9.   sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
    10.   } catch (Exception e) {
    11.   e.printStackTrace();
    12.   }
    13.   }
    14.   private static ThreadLocal local = new ThreadLocal<>();
    15.   /**
    16.   * 每调⽤⼀次openSession()可获取⼀个新的会话,该会话⽀持⾃动提交。
    17.   *
    18.   * @return 新的会话对象
    19.   */
    20.   public static SqlSession openSession() {
    21.   SqlSession sqlSession = local.get();
    22.   if (sqlSession == null) {
    23.   sqlSession = sqlSessionFactory.openSession();
    24.   local.set(sqlSession);
    25.   }
    26.   return sqlSession;
    27.       }
    28.   /**
    29.   * 关闭SqlSession对象
    30.   * @param sqlSession
    31.   */
    32.   public static void close(SqlSession sqlSession){
    33.   if (sqlSession != null) {
    34.   sqlSession.close();
    35.   }
    36.   local.remove();
    37.   }
    38.  }

  • 相关阅读:
    2022/7/20
    c++回顾与提高
    SDH设备
    Redis知识-实战篇(2)
    Docker--提高下载速度的方法
    【StreamSet】ETL之StreamSet之Pipelines的状态监听之WebHook钉钉篇
    2022年大一网页期末作业(纯html+css实现)
    百科源码生活资讯百科门户类网站百科知识,生活常识
    java-net-php-python-ssh电动车销售系统计算机毕业设计程序
    【Nginx】基本使用及配置-项目部署
  • 原文地址:https://blog.csdn.net/m0_64231944/article/details/133928235