【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();
     }
 }
相关推荐
冷琴19964 分钟前
基于java+springboot的酒店预定网站、酒店客房管理系统
java·开发语言·spring boot
daiyang123...30 分钟前
IT 行业的就业情况
java
爬山算法1 小时前
Maven(6)如何使用Maven进行项目构建?
java·maven
.生产的驴1 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
爱学的小涛1 小时前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
吹老师个人app编程教学1 小时前
详解Java中的BIO、NIO、AIO
java·开发语言·nio
爱学的小涛1 小时前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪1 小时前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
琴智冰1 小时前
SpringBoot
java·数据库·spring boot
binqian1 小时前
【SpringSecurity】基本流程
java·spring