作为一名长期使用IntelliJ IDEA进行Java开发的工程师,我经常需要快速搭建SpringBoot项目骨架。今天我将分享一个完整的SpringBoot+MyBatis+MySQL工程搭建指南,这个配置方案已经在我参与的多个电商和ERP系统中得到验证。
这个技术栈组合特别适合需要快速迭代的中小型项目。SpringBoot的自动配置让我们免去了繁琐的XML配置,MyBatis提供了灵活的SQL控制能力,而MySQL作为最流行的开源关系型数据库,三者组合能快速构建出健壮的数据访问层。下面我会从环境准备开始,详细演示每个关键步骤。
在开始前,请确保已安装以下组件:
提示:使用Docker运行MySQL可以避免污染本地环境,启动命令:
docker run --name mysql8 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:8.0 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
设置全局编码:
配置Maven:
xml复制<mirror>
<id>aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
创建完成后应看到标准Maven结构:
code复制src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ └── DemoApplication.java
│ └── resources
│ ├── application.yml
│ ├── static
│ └── templates
└── test
└── java
检查pom.xml应包含以下核心依赖:
xml复制<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
创建测试数据库和表:
sql复制CREATE DATABASE demo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO user(username, password, email) VALUES
('admin', '123456', 'admin@example.com'),
('test', 'test123', 'test@example.com');
在application.yml中添加:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 30000
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注意:生产环境密码应该使用加密配置,推荐使用Jasypt或Vault
使用Lombok简化代码:
java复制@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String username;
private String password;
private String email;
private Date createTime;
}
创建UserMapper.java:
java复制@Mapper
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> findAll();
@Insert("INSERT INTO user(username, password, email) VALUES(#{username}, #{password}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("UPDATE user SET username=#{username}, email=#{email} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id=#{id}")
int delete(Long id);
}
java复制@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
public List<User> listAll() {
return userMapper.findAll();
}
public int createUser(User user) {
return userMapper.insert(user);
}
public int updateUser(User user) {
return userMapper.update(user);
}
public int deleteUser(Long id) {
return userMapper.delete(id);
}
}
java复制@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<List<User>> listUsers() {
return ResponseEntity.ok(userService.listAll());
}
@PostMapping
public ResponseEntity<Void> addUser(@RequestBody User user) {
userService.createUser(user);
return ResponseEntity.created(URI.create("/api/users/" + user.getId())).build();
}
@PutMapping("/{id}")
public ResponseEntity<Void> updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
userService.updateUser(user);
return ResponseEntity.noContent().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
添加PageHelper支持:
xml复制<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
java复制public PageInfo<User> listByPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.findAll();
return new PageInfo<>(users);
}
在Service方法上添加事务注解:
java复制@Transactional(rollbackFor = Exception.class)
public int createUser(User user) {
// 业务逻辑...
}
对于需要连接多个数据库的场景:
yaml复制spring:
datasource:
primary:
url: jdbc:mysql://localhost:3306/db1
username: user1
password: pass1
secondary:
url: jdbc:mysql://localhost:3306/db2
username: user2
password: pass2
java复制@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
症状:应用运行一段时间后出现连接超时
解决方案:
yaml复制spring:
datasource:
hikari:
connection-timeout: 30000
maximum-pool-size: 10
idle-timeout: 600000
max-lifetime: 1800000
yaml复制spring:
datasource:
hikari:
connection-test-query: SELECT 1
症状:查询结果字段为null
解决方案:
yaml复制mybatis:
configuration:
map-underscore-to-camel-case: true
yaml复制logging:
level:
com.example.demo.mapper: debug
常见原因:
验证方法:
java复制@SpringBootTest
class TransactionTest {
@Autowired
private UserService userService;
@Test
void testTransaction() {
try {
userService.testTransactional();
} catch (Exception e) {
// 检查数据库是否回滚
}
}
}
使用MyBatis Generator自动生成基础代码:
xml复制<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
</configuration>
</plugin>
xml复制<context id="mysql" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/demo_db"
userId="root"
password="123456"/>
<javaModelGenerator targetPackage="com.example.demo.model"
targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.demo.mapper"
targetProject="src/main/java"/>
<table tableName="user" domainObjectName="User"/>
</context>
集成Spring Boot Actuator监控数据源:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics
metrics:
tags:
application: ${spring.application.name}
code复制http://localhost:8080/actuator/metrics/hikaricp.connections.usage
yaml复制spring:
datasource:
password: ENC(加密后的密码)
xml复制<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
使用SpringBootTest测试Mapper:
java复制@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testFindAll() {
List<User> users = userMapper.findAll();
assertFalse(users.isEmpty());
}
}
测试Controller层:
java复制@AutoConfigureMockMvc
@SpringBootTest
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testListUsers() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].username").exists());
}
}
使用JMeter进行压力测试:
使用Maven打包可执行JAR:
bash复制mvn clean package -DskipTests
创建Dockerfile:
dockerfile复制FROM openjdk:11-jre-slim
COPY target/demo-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
构建并运行:
bash复制docker build -t demo-app .
docker run -d -p 8080:8080 --name demo demo-app
bash复制java -jar -Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m app.jar
yaml复制management:
endpoint:
health:
show-details: always
MyBatis插件推荐:
代码模板:
数据库工具:
MyBatis SQL日志:
yaml复制logging:
level:
org.mybatis: debug
条件断点:
HTTP客户端:
code复制###
GET http://localhost:8080/api/users
Accept: application/json
代码风格:
分层原则:
版本控制:
动态SQL:
xml复制<select id="findByCondition" resultType="User">
SELECT * FROM user
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email LIKE CONCAT('%',#{email},'%')
</if>
</where>
</select>
类型处理器:
java复制@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptTypeHandler implements TypeHandler<String> {
// 实现加解密逻辑
}
插件开发:
java复制@Intercepts({
@Signature(type= Executor.class, method="update",
args={MappedStatement.class,Object.class})
})
public class MyPlugin implements Interceptor {
// 实现拦截逻辑
}
整合Redis缓存:
java复制@Cacheable(value = "user", key = "#id")
public User getById(Long id) {
return userMapper.selectById(id);
}
整合RabbitMQ消息队列:
java复制@RabbitListener(queues = "user.queue")
public void processUserCreate(User user) {
// 处理用户创建消息
}
整合Elasticsearch:
java复制public interface UserRepository extends ElasticsearchRepository<User, Long> {
List<User> findByUsername(String username);
}
多模块拆分:
code复制project
├── user-service
│ ├── src
│ └── pom.xml
├── order-service
│ ├── src
│ └── pom.xml
└── pom.xml (父POM)
微服务改造:
云原生部署:
典型数据流:
数据库设计要点:
核心功能:
性能优化点:
特殊需求:
技术挑战:
问题:用户列表查询慢(>2s)
分析:
解决方案:
sql复制ALTER TABLE user ADD INDEX idx_username (username);
效果:查询时间降至200ms以内
初始配置:
yaml复制maximum-pool-size: 50
问题:高并发时出现连接等待
调整:
yaml复制maximum-pool-size: 20
connection-timeout: 3000
原理:根据实际TPS计算,20连接足够支持500QPS
默认参数:
问题:频繁GC影响性能
调整:
bash复制java -jar -Xms512m -Xmx1024m -XX:+UseG1GC app.jar
监控工具:
始终使用参数化查询:
java复制@Select("SELECT * FROM user WHERE username = #{name}")
User findByUsername(@Param("name") String username);
避免拼接SQL:
java复制// 错误示范
@Select("SELECT * FROM user WHERE username = '" + name + "'")
使用MyBatis的<bind>标签处理LIKE:
xml复制<bind name="pattern" value="'%' + name + '%'" />
SELECT * FROM user WHERE username LIKE #{pattern}
实现自定义TypeHandler:
java复制public class SensitiveTypeHandler implements TypeHandler<String> {
@Override
public void setParameter(...) {
// 加密逻辑
}
@Override
public String getResult(...) {
// 解密逻辑
}
}
在字段上指定:
java复制@Column(typeHandler = SensitiveTypeHandler.class)
private String idCard;
使用MyBatis插件记录操作:
java复制@Intercepts(@Signature(type= Executor.class, method="update", ...))
public class AuditLogPlugin implements Interceptor {
// 记录修改操作
}
存储到日志文件或数据库
示例.gitlab-ci.yml:
yaml复制stages:
- build
- test
- deploy
build:
stage: build
script:
- mvn clean package -DskipTests
test:
stage: test
script:
- mvn test
deploy:
stage: deploy
script:
- scp target/*.jar user@server:/app/
only:
- master
Jenkinsfile示例:
groovy复制pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy') {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'prod-server',
transfers: [
sshTransfer(
sourceFiles: 'target/*.jar',
remoteDirectory: '/app'
)
]
)
]
)
}
}
}
}
集成SonarQube:
xml复制<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1</version>
</plugin>
运行扫描:
bash复制mvn sonar:sonar -Dsonar.host.url=http://sonar-server:9000
设置质量阈值:
添加依赖:
xml复制<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置端点:
yaml复制management:
endpoints:
web:
exposure:
include: prometheus
metrics:
export:
prometheus:
enabled: true
监控指标:
ELK架构:
日志格式规范:
java复制private static final Logger log = LoggerFactory.getLogger(UserController.class);
log.info("Get user by id: {}", id);
log.error("Failed to create user", ex);
追踪ID:
java复制@GetMapping
public List<User> list(@RequestHeader("X-Request-ID") String requestId) {
MDC.put("requestId", requestId);
// ...
}
使用Swagger UI:
添加依赖:
xml复制<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
配置类:
java复制@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
访问地址:
code复制http://localhost:8080/swagger-ui/
使用Screw生成:
添加插件:
xml复制<plugin>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-maven-plugin</artifactId>
<version>1.0.5</version>
</plugin>
运行命令:
bash复制mvn screw:run
输出HTML/Markdown文档
维护CHANGELOG.md:
code复制# 变更日志
## [1.0.0] - 2023-06-01
### 新增
- 用户管理功能
- 权限控制
### 修复
- 修复SQL注入漏洞
常见技术债务:
使用SonarQube测量:
经过这个完整的SpringBoot+MyBatis+MySQL项目实践,我总结了以下几点经验:
配置标准化:统一管理数据库连接池、MyBatis等配置,避免团队协作时的混乱
分层明确:严格遵循Controller-Service-Mapper的分层架构,保持代码清晰
SQL可控:MyBatis的XML方式虽然需要额外文件,但相比JPA能更好控制复杂SQL
性能可测:从开发阶段就建立性能基准,避免后期大规模重构
渐进式优化:先保证功能完整,再根据实际性能数据进行针对性优化
这套技术栈特别适合需要精细控制SQL的中小型项目,在实际开发中,配合MyBatis-Plus等增强工具可以进一步提升开发效率。对于超大型项目,可以考虑结合JPA使用,取两者之长。