Skip to content

在 Feat Cloud 中接入 MyBatis

This content is not available in your language yet.

这一页不再试图做一份“所有 MyBatis 配置项大全”。
它只回答一个更实际的问题:如果你已经能写 Feat Cloud 控制器,现在要把数据库接进来,应该按什么顺序做。

仓库里已经有一套完整示例,可以直接对照阅读:

  • demo/mybatis/src/main/java/tech/smartboot/feat/demo/mybatis/Bootstrap.java
  • demo/mybatis/src/main/java/tech/smartboot/feat/demo/mybatis/controller/UserController.java
  • demo/mybatis/src/main/java/tech/smartboot/feat/demo/mybatis/service/UserService.java
  • demo/mybatis/src/main/java/tech/smartboot/feat/demo/mybatis/mapper/UserMapper.java
  • demo/mybatis/src/main/resources/feat.yaml
  • demo/mybatis/src/main/resources/mybatis/mybatis-config.xml

下面这篇文档会严格按这套结构来讲。

一个最小的 CRUD 链路:

  • 访问 /users 能查到所有用户
  • 访问 /users/{username} 能查到单个用户
  • POST /users 能创建用户
  • PUT /users 能更新用户
  • DELETE /users/{username} 能删除用户

pom.xml 中引入 feat-cloud-startermybatis 和数据库驱动。
示例项目里使用的是 H2 内存数据库:

pom.xml
<dependency>
<groupId>tech.smartboot.feat</groupId>
<artifactId>feat-cloud-starter</artifactId>
<version>${feat.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
</dependency>

第二步:把 MyBatis 配置接到 Feat Cloud 启动流程

Section titled “第二步:把 MyBatis 配置接到 Feat Cloud 启动流程”

src/main/resources/feat.yaml 里声明两件事:

feat.yaml
feat:
mybatis:
path: mybatis/mybatis-config.xml
initial-sql: mybatis/ddl/schema.sql

这里的含义很直接:

  • path:告诉 Feat Cloud 去哪里读 MyBatis 主配置
  • initial-sql:告诉它启动时顺手执行数据库初始化脚本

这就是示例项目为什么一启动就能直接查到用户数据,而不需要你手写额外初始化逻辑。

第三步:准备 MyBatis 配置和表结构

Section titled “第三步:准备 MyBatis 配置和表结构”

demo/mybatismybatis-config.xml 很克制,只做了三件事:

  1. 打开 SQL 日志
  2. 配置 H2 数据源
  3. 注册 mapper 包
mybatis-config.xml
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="h2_mem">
<environment id="h2_mem">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:feat-demo;NON_KEYWORDS=value;mode=mysql;"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="tech.smartboot.feat.demo.mybatis.mapper"/>
</mappers>
</configuration>

schema.sql 负责建表并插入几条初始数据。
这一步让后面的 Controller 和 Service 能立刻验证,不需要再手动准备数据库。

示例里的启动类非常简单:

Bootstrap.java
import tech.smartboot.feat.cloud.FeatCloud;
import tech.smartboot.feat.cloud.annotation.Bean;
@Bean
public class Bootstrap {
public static void main(String[] args) {
FeatCloud.cloudServer().listen();
}
}

这个类本身几乎没做业务事,但它给了 Feat Cloud 一个明确的启动入口。
MyBatis 的配置接入,主要是靠前面的 feat.yaml 和资源文件完成的。

在示例里,Mapper 就是标准 MyBatis 注解接口:

UserMapper.java
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user_info WHERE username = #{username}")
User selectByUsername(@Param("username") String username);
@Select("SELECT * FROM user_info")
List<User> selectAll();
@Insert("INSERT INTO user_info(username, password, `desc`, role) VALUES(#{username}, #{password}, #{desc}, #{role})")
int insert(User user);
@Update("UPDATE user_info SET password=#{password}, `desc`=#{desc}, role=#{role} WHERE username=#{username}")
int update(User user);
@Delete("DELETE FROM user_info WHERE username = #{username}")
int deleteByUsername(@Param("username") String username);
}

这里最重要的不是注解语法本身,而是:

  • Mapper 仍然是纯 MyBatis 思维
  • Feat Cloud 负责把它接进应用上下文

示例项目没有直接在 Controller 里操作 Mapper,而是先过一层 Service:

UserService.java
import tech.smartboot.feat.cloud.annotation.Autowired;
import tech.smartboot.feat.cloud.annotation.Bean;
@Bean
public class UserService {
@Autowired
private UserMapper userMapper;
public User findByUsername(String username) {
return userMapper.selectByUsername(username);
}
public List<User> findAll() {
return userMapper.selectAll();
}
}

这一步的意义很简单:

  • Controller 负责 HTTP
  • Service 负责业务动作
  • Mapper 负责数据库访问

这样后面继续扩展权限、事务、校验时,结构不会乱。

最后在 Controller 里把这条链路接到 HTTP 上:

UserController.java
import tech.smartboot.feat.cloud.RestResult;
import tech.smartboot.feat.cloud.annotation.Autowired;
import tech.smartboot.feat.cloud.annotation.Controller;
import tech.smartboot.feat.cloud.annotation.PathParam;
import tech.smartboot.feat.cloud.annotation.RequestMapping;
import tech.smartboot.feat.cloud.annotation.RequestMethod;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/users")
public RestResult<List<User>> getAllUsers() {
return RestResult.ok(userService.findAll());
}
@RequestMapping("/users/{username}")
public RestResult<User> getUserByUsername(@PathParam("username") String username) {
User user = userService.findByUsername(username);
return user != null ? RestResult.ok(user) : RestResult.fail("User not found");
}
@RequestMapping(value = "/users", method = RequestMethod.POST)
public RestResult<String> createUser(User user) {
return userService.insert(user)
? RestResult.ok("User created successfully")
: RestResult.fail("Failed to create user");
}
}

到这一步,链路已经完整了:

HTTP -> Controller -> Service -> Mapper -> DB

启动 demo/mybatis 后,可以先验证读接口:

Terminal window
curl http://localhost:8080/users
curl http://localhost:8080/users/feat
curl http://localhost:8080/users/role/admin

再验证写接口:

Terminal window
curl -X POST http://localhost:8080/users \
-H 'Content-Type: application/json' \
-d '{"username":"new_user","password":"123456","desc":"created from docs","role":"user"}'

如果这些请求都能返回合理结果,说明:

  • Feat Cloud 启动成功
  • MyBatis 配置被正确读取
  • 初始化 SQL 生效
  • Mapper / Service / Controller 整条链路都打通了

在 Feat Cloud 里,MyBatis 集成的体验更像“编译期接线”而不是“运行时手工拼装”。
这也是它和很多传统 Spring/MyBatis 示例在阅读感受上的区别。

接口能启动,但一访问就报数据库相关错误

Section titled “接口能启动,但一访问就报数据库相关错误”

优先检查:

  1. feat.yaml 里的 feat.mybatis.path 是否指向了真实文件
  2. mybatis-config.xml 里的 mapper 包是否正确
  3. schema.sql 是否真的被打进了资源目录

优先检查:

  1. feat.mybatis.initial-sql 是否写对
  2. SQL 脚本是否在启动时成功执行
  3. 你当前使用的是否真的是同一个数据源配置

为什么文档不推荐一上来就讲多数据源

Section titled “为什么文档不推荐一上来就讲多数据源”

因为大多数第一次接入的人还没把“单数据源链路”走通。
先把单条 CRUD 线打通,再讨论多数据源,排错成本更低。