SqlSessionFactory初始化失败主因是配置未加载成功,如XML路径错误或流为空;Mapper XML的namespace和id必须与接口全限定名及方法名严格一致;#{}用于安全参数绑定,${}仅限白名单校验的元数据拼接。

MyBatis的SqlSessionFactory怎么初始化才不报空指针
根本原因通常是SqlSessionFactory没真正构建成功,却直接拿来用。常见于手动 new SqlSessionFactoryBuilder() 后没传入有效配置流,或 XML 路径写错导致 Resources.getResourceAsStream() 返回 null。
- 确保配置文件路径对:用
Resources.getResourceAsStream("mybatis-config.xml")时,该文件必须在src/main/resources下,且名字拼写完全一致(区分大小写) - 别跳过异常捕获:
new SqlSessionFactoryBuilder().build(...)抛异常时,务必打印完整堆栈,常见错误如org.apache.ibatis.builder.BuilderException: Error creating document instance就是 XML 格式或 DTD 加载失败 - Spring 环境下别自己 new:如果项目已用 Spring,应通过
@MapperScan或SqlSessionFactoryBean交由容器管理,硬编码初始化容易绕过事务代理
Mapper XML里id和接口方法名不匹配会怎样
不会编译报错,但运行时调用必抛 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)。MyBatis 是靠 namespace + id 做全限定映射的,不是靠方法签名推断。
- XML 的
namespace必须是对应 Mapper 接口的完整类名,例如com.example.mapper.UserMapper - 每个
<select>/<insert>的id必须和接口中方法名**完全一致**,包括大小写 - 参数类型不一致也会静默失败:比如 XML 中写
parameterType="int",但接口方法是getUser(Long id),可能触发类型转换异常或查不到数据
单表 CRUD 时,#{} 和 ${} 哪个该用、哪个绝对不能乱用
#{} 是预编译占位符,安全;${} 是字符串拼接,危险。99% 的字段值场景只用 #{},只有动态表名、排序字段等极少数元数据才考虑 ${},且必须配合白名单校验。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 插入/更新字段值:一律用
#{username},防 SQL 注入,也支持自动类型转换 - 动态排序:
ORDER BY ${sortBy}可行,但sortBy必须来自枚举或固定字符串列表,不能直接传前端参数 - 千万别写
WHERE name = '${name}':这等于把用户输入原样拼进 SQL,是高危漏洞 - MyBatis 日志开到 DEBUG 后,能看到实际执行的 SQL —— 如果看到问号(?)就是
#{}生效了;如果看到明文值,大概率误用了${}
为什么selectOne查不到记录时不返回 null 而是抛异常
不是 MyBatis 的默认行为 —— 它本来就会返回 null。如果你遇到抛 TooManyResultsException 或空结果却报错,基本是调用了 selectList().get(0) 这类手写逻辑,或者误用了 selectMap 等有约束的查询方法。
立即学习“Java免费学习笔记(深入)”;
-
selectOne()在结果为空时返回null,多于一条时才抛TooManyResultsException - 想稳妥取单条,推荐用
selectList().stream().findFirst().orElse(null),避免空指针也规避多结果异常 - XML 中别给
<select>配resultType为基本类型(如int)又允许空结果:数据库 NULL 映射不到基本类型,会报NullPointerException,改用包装类java.lang.Integer
MyBatis 的 XML 配置看着简单,但每个标签属性、每个路径字符串、每个符号(# 还是 $)都卡着执行链的关键节点。最容易被忽略的是资源加载时机和命名空间的严格一致性 —— 它们不出错时一切安静,一出错就找不到源头。

















