8. Mybatis 接口代理机制及使用

疑问:在MyBatis中,SqlSession​对象为什么不写在方法外部呢?

在MyBatis中,SqlSession​对象通常不推荐写在方法外部(如类成员变量或静态变量)并且在整个类中共享的原因主要包括以下几个方面:

  1. 线程安全
    SqlSession​不是线程安全的对象,因此每个线程都应该拥有自己的SqlSession​实例。如果在类级别上声明一个全局的SqlSession​,多线程环境下可能会导致数据竞争和不可预测的结果。
  2. 资源管理
    SqlSession​内部持有数据库连接资源,打开连接会消耗系统资源,而长时间不关闭连接可能导致资源泄露。最佳实践是在每次数据库操作完成后立即关闭SqlSession​以释放资源。将SqlSession​放在方法内,可以在方法结束时确保及时关闭。
  3. 事务控制
    每个SqlSession​对应一个数据库事务,当在一个业务逻辑中需要多个数据库操作构成一个原子事务时,应该在一个方法内创建并开启事务,完成所有操作后再提交或回滚事务,这样能保证事务的一致性。若SqlSession​是全局的,事务边界将会变得模糊,不利于精确控制。
  4. 依赖注入与单元测试
    在使用Spring等容器管理MyBatis时,SqlSession​可以通过依赖注入的方式在每次请求或者每个方法调用时获得新的实例,这符合面向切面编程(AOP)的原则,使得代码更加模块化和易于测试。

基于以上原因,在编写测试类或实际应用中的DAO层代码时,推荐的做法是每次执行CRUD操作时,在方法内部创建SqlSession​对象,执行完必要的操作后,立即将其关闭。例如:

public void testInsert(User user) {
    try (SqlSession session = sqlSessionFactory.openSession()) {
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.insert(user);
        session.commit();
    } catch (Exception e) {
        // 处理异常,可能需要回滚事务
    }
}

上述代码展示了在方法内部获取并使用SqlSession​的最佳实践,这样可以确保每次操作都独立于其他操作,避免了资源管理和并发问题。

使用mybatis获取dao接口代理类对象

代码展示:

AccountDao accountDao = (AccountDao)sqlSession.getMapper(AccountDao.class);

使用前提:AccountMapper.xml文件中的namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致。

将service中获取dao对象的代码再次修改,如下:

image

代码测试:

    @Test
    public void testInsert() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null , "3333" , "CT5" , 30.0 , "2023-10-10" , "燃油车");
        int rows = mapper.insert(car);
        System.out.println("插入数据:" + rows);
        sqlSession.commit();
    }

posted @ 2024-06-23 12:40  捞月亮的小北  阅读(2)  评论(0编辑  收藏  举报