【MyBatis】mybatis工具类迭代

目录

MyBatis工具类的迭代

ThreadLocal使用

mybatis工具类终极版:


MyBatis工具类的迭代

java 复制代码
public class MyBatisUtil {
     //工具类构造方法私有化
     private void MyBatisUtil() {
     }
     //方法一
     public static SqlSession getSqlSession(){
         try {
             SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
             SqlSessionFactory build = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("UserMapper.xml"));
             SqlSession sqlSession = build.openSession();
             return sqlSession;
         } catch (IOException e) {
            throw new RuntimeException(e);
         }
     }

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

java 复制代码
   //方法二
     private static SqlSession sqlSession = null;
     static {
         try {
             sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("UserMapper.xml")).openSession();
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 //    弊端:调用一次mybatisutil就创建好了sqlsession,此后的每次调用会公用一个sqlsession对象;   

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

java 复制代码
 //方法三
     private static SqlSessionFactory sqlSessionFactory = null;
     static {
         try {
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("UserMapper.xml"));
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
     public SqlSession getSqlSession() {
         return sqlSessionFactory.openSession();
         //每调用一次方法,创建一个sqlsession对象,不共用
     }

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

java 复制代码
 public class AccountServiceImpl implements AccountService {
         private AccountDao accountDao = new AccountDaoImpl();
  @Override
  public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
  // 查询转出账户的余额
         Account fromAct = accountDao.selectByActno(fromActno);
         if (fromAct.getBalance() < money) {
             throw new MoneyNotEnoughException("对不起,您的余额不⾜。");
         }
         try {
  // 程序如果执⾏到这⾥说明余额充⾜
  // 修改账户余额
              Account toAct = accountDao.selectByActno(toActno);
             fromAct.setBalance(fromAct.getBalance() - money);
             toAct.setBalance(toAct.getBalance() + money);
  // 更新数据库(添加事务)
             SqlSession sqlSession = SqlSessionUtil.openSession();
             accountDao.update(fromAct);
  // 模拟异常
             String s = null;
             s.toString();
             accountDao.update(toAct);
             sqlSession.commit();
             sqlSession.close();
         } catch (Exception e) {
                 throw new AppException("转账失败,未知原因!");
          }
  }
 }

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

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

ThreadLocal使用

修改工具类;

mybatis工具类终极版:

java 复制代码
 public class SqlSessionUtil {
  private static SqlSessionFactory sqlSessionFactory;
  /**
  * 类加载时初始化sqlSessionFactory对象
  */
  static {
     try {
             SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
             sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
         } catch (Exception e) {
             e.printStackTrace();
         }
      }
  private static ThreadLocal<SqlSession> local = new ThreadLocal<>();
  /**
  * 每调⽤⼀次openSession()可获取⼀个新的会话,该会话⽀持⾃动提交。
  *
  * @return 新的会话对象
  */
  public static SqlSession openSession() {
         SqlSession sqlSession = local.get();
         if (sqlSession == null) {
             sqlSession = sqlSessionFactory.openSession();
             local.set(sqlSession);
         }
         return sqlSession;
      }
  /**
  * 关闭SqlSession对象
  * @param sqlSession
  */
  public static void close(SqlSession sqlSession){
         if (sqlSession != null) {
             sqlSession.close();
          }
         local.remove();
     }
 }
相关推荐
vivi_and_qiao4 分钟前
HTML的form表单
java·前端·html
Slaughter信仰20 分钟前
深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第四章知识点问答补充及重新排版
java·开发语言·jvm
心灵宝贝23 分钟前
Mac用户安装JDK 22完整流程(Intel版dmg文件安装指南附安装包下载)
java·开发语言·macos
ta是个码农26 分钟前
Mysql——日志
java·数据库·mysql·日志
今***b38 分钟前
Python 操作 PPT 文件:从新手到高手的实战指南
java·python·powerpoint
David爱编程40 分钟前
volatile 关键字详解:轻量级同步工具的边界与误区
java·后端
fatfishccc3 小时前
Spring MVC 全解析:从核心原理到 SSM 整合实战 (附完整源码)
java·spring·ajax·mvc·ssm·过滤器·拦截器interceptor
没有bug.的程序员3 小时前
MyBatis 初识:框架定位与核心原理——SQL 自由掌控的艺术
java·数据库·sql·mybatis
执键行天涯3 小时前
从双重检查锁定的设计意图、锁的作用、第一次检查提升性能的原理三个角度,详细拆解单例模式的逻辑
java·前端·github
程序员江鸟4 小时前
Java面试实战系列【JVM篇】- JVM内存结构与运行时数据区详解(私有区域)
java·jvm·面试