SqlSessionFactory 必须全局唯一且线程安全,仅在应用启动时构建一次;通过 SqlSessionFactoryBuilder 读取配置流创建,构建开销大,重复创建会导致资源浪费与映射冲突;推荐静态内部类或枚举实现单例;创建后用 openSession() 获取非线程安全的 SqlSession,需及时关闭。

SqlSessionFactory 是 MyBatis 的核心工厂,负责创建 SqlSession。它必须全局唯一、线程安全,且只应在应用启动时构建一次——不是每次用都重建,更不能由业务代码随意 new。
怎么创建 SqlSessionFactory
创建过程由 SqlSessionFactoryBuilder 完成,它是一次性工具,不保存状态,用完即弃:
- 确保
mybatis-config.xml在src/main/resources下(如路径为mybatis-config.xml) - 用
Resources.getResourceAsStream("mybatis-config.xml")获取输入流(注意:不能带前导/) - 调用
new SqlSessionFactoryBuilder().build(inputStream)得到实例 - 若配置有误(如
<environments>缺少default属性),会在 build 阶段直接抛异常
为什么必须单例管理
SqlSessionFactory 构建开销大:需解析 XML、注册 Mapper、初始化 Configuration、加载 TypeHandler 等。重复构建不仅浪费 CPU 和内存,还可能导致映射冲突或连接池混乱:
- Configuration 对象不可变,是线程安全的基础
- 多个 SqlSessionFactory 实例会各自维护一套映射关系和连接池,资源隔离但低效
- Spring 环境下交由
@Bean管理,容器自动保证单例 - 纯 Java 应用推荐静态内部类懒汉式实现,避免类加载竞争
常见单例实现方式
手动管理时,不建议用简单 static 字段(非线程安全初始化),推荐以下两种:
立即学习“Java免费学习笔记(深入)”;
- 静态内部类:利用 JVM 类加载机制保证线程安全与延迟加载
- 枚举单例:天然防止反射/反序列化破坏,简洁可靠
- 切忌在 DAO 或 Service 方法里反复 new SqlSessionFactoryBuilder 并调用 build() —— 这等于每调用一次就造一个新工厂
构建后怎么用
SqlSessionFactory 创建成功后,业务层通过它获取 SqlSession:
-
openSession():默认手动提交,适合增删改场景 -
openSession(true):自动提交,适合只读查询(慎用,事务控制力弱) - SqlSession 非线程安全,必须每个线程独用一个,并用 try-with-resources 及时关闭
- 不要缓存 SqlSession,也不要在多线程间共享


















