Mybatis框架之单例模式 (Singleton Pattern)

MyBatis 框架中也使用到了单例模式 (Singleton Pattern) ,主要体现在 SqlSessionFactory 的创建和管理上。通过单例模式,MyBatis 可以确保整个应用程序中只创建一个 SqlSessionFactory 实例,从而有效地管理数据库连接资源并提高性能。下面将详细介绍 MyBatis 中的单例模式的应用原理和实现方式。

1. 什么是单例模式 (Singleton Pattern)?

单例模式 是一种创建型设计模式,确保一个类在整个应用程序中只有一个实例,并提供一个全局访问点来访问该实例。这种模式通常用于需要被频繁访问且只能存在一个实例的对象,例如数据库连接池、线程池、配置管理器等。

单例模式的特点:

  • 唯一性:整个应用程序中只存在一个实例。
  • 全局访问:提供一个全局访问点供其他代码使用。
  • 延迟加载 (Lazy Initialization)(可选):可以在第一次使用时创建实例,从而节省资源。

2. MyBatis 中的单例模式应用

在 MyBatis 中,SqlSessionFactory 就是一个典型的单例模式的实现。SqlSessionFactory 是创建 SqlSession 对象的工厂,它负责解析 MyBatis 配置文件,并管理数据库连接资源。

2.1 为什么 SqlSessionFactory 需要单例模式?
  • 性能考虑 :创建 SqlSessionFactory 是一个相对耗时的操作,需要解析配置文件、初始化连接池等。因此,确保 SqlSessionFactory 只被创建一次,可以减少重复的资源开销,提高性能。
  • 资源管理 :使用单例模式可以确保整个应用程序中只有一个 SqlSessionFactory 实例,从而有效地管理数据库连接资源。
  • 线程安全SqlSessionFactory 本身是线程安全的,可以在多个线程中安全地共享。

3. SqlSessionFactory 的单例模式实现

通常,我们会通过封装一个工具类来实现 SqlSessionFactory 的单例模式。下面是一个基于单例模式的 SqlSessionFactory 实现示例:

3.1 MyBatis 配置文件 (mybatis-config.xml)
XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
3.2 创建单例模式的 MyBatisUtil 工具类
java 复制代码
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil {

    // 静态变量,用于存储唯一的 SqlSessionFactory 实例
    private static SqlSessionFactory sqlSessionFactory;

    // 私有构造函数,防止外部实例化
    private MyBatisUtil() {}

    // 获取 SqlSessionFactory 的方法
    public static SqlSessionFactory getSqlSessionFactory() {
        if (sqlSessionFactory == null) {
            synchronized (MyBatisUtil.class) {
                if (sqlSessionFactory == null) {
                    try {
                        String resource = "mybatis-config.xml";
                        InputStream inputStream = Resources.getResourceAsStream(resource);
                        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return sqlSessionFactory;
    }
}
3.3 使用 MyBatisUtil 获取 SqlSession
java 复制代码
import org.apache.ibatis.session.SqlSession;
import com.example.mapper.UserMapper;
import com.example.model.User;
import java.util.List;

public class MyBatisExample {
    public static void main(String[] args) {
        // 通过单例模式获取 SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = MyBatisUtil.getSqlSessionFactory();

        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 获取 Mapper 接口的实现
            UserMapper userMapper = session.getMapper(UserMapper.class);

            // 调用方法执行 SQL
            List<User> users = userMapper.getAllUsers();
            users.forEach(user -> System.out.println(user.getName()));
        }
    }
}

4. 解析单例模式实现细节

  1. 私有化构造方法

    • 通过将构造函数设为 private,防止外部创建实例,从而确保类的唯一实例性。
  2. 双重检查锁 (Double-Checked Locking)

    • 使用 synchronized 关键字和双重检查锁机制确保 SqlSessionFactory 的线程安全。这可以避免在多线程环境下重复创建实例的问题。
  3. 延迟加载 (Lazy Initialization)

    • 只有在第一次调用 getSqlSessionFactory() 方法时,才会创建 SqlSessionFactory 实例,这样可以节省系统资源。

5. 单例模式的优缺点

优点:
  • 节省资源 :避免重复创建 SqlSessionFactory 实例,节省内存和 CPU 资源。
  • 全局访问:提供了一个全局访问点,方便使用。
  • 线程安全:通过双重检查锁机制,可以确保在多线程环境下的安全性。
缺点:
  • 生命周期管理:由于单例对象在整个应用程序生命周期中都存在,可能会导致资源不能及时释放,从而增加内存消耗。
  • 不易测试:单例模式会增加代码的耦合度,可能会给单元测试带来一定困难。

6. 总结

MyBatis 通过单例模式管理 SqlSessionFactory 的创建和访问,从而提高了系统性能并简化了数据库连接的管理。在实际项目中,SqlSessionFactory 通常是单例的,因为它是线程安全的,且创建过程相对耗时。

使用单例模式可以确保 SqlSessionFactory 只被创建一次,从而避免重复创建造成的资源浪费。这种设计模式在 MyBatis 的实际应用中非常常见,是数据库访问层优化的一个重要手段。

相关推荐
那个失眠的夜1 天前
Mybatis延迟加载策略
xml·java·数据库·maven·mybatis
身如柳絮随风扬1 天前
MyBatis 插件原理详解:从拦截器到动态代理,手写一个分页插件
java·mybatis
小江的记录本1 天前
【JEECG Boot】 JEECG Boot——数据字典管理 系统性知识体系全解析
java·前端·spring boot·后端·spring·spring cloud·mybatis
wuqingshun3141591 天前
说一下mybatis里面#{}和${}的区别
java·spring·mybatis
小江的记录本1 天前
【JEECG Boot】 《JEECG Boot 数据字典使用教程》(完整版)
java·前端·数据库·spring boot·后端·spring·mybatis
小江的记录本1 天前
【JEECG Boot】 JEECG Boot 数据字典管理——六大核心功能(内含:《JEECG Boot 数据字典开发速查清单》)
java·前端·数据库·spring boot·后端·spring·mybatis
小江的记录本1 天前
【JEECG Boot】 JEECG Boot——Online表单 系统性知识体系全解
java·前端·spring boot·后端·spring·低代码·mybatis
MaCa .BaKa2 天前
44-校园二手交易系统(小程序)
java·spring boot·mysql·小程序·maven·intellij-idea·mybatis
java1234_小锋2 天前
Java高频面试题:MyBatis如何实现动态数据源切换?
java·开发语言·mybatis
小旭95272 天前
SpringBoot + 七牛云 + Quartz:图片存储与定时清理
java·spring boot·后端·mybatis