Spring Boot与Vue 3实战:智慧停车场管理系统开发指南
在 Java Web 开发领域,智慧停车场管理系统是一个典型的全栈实战项目,它涵盖了用户管理、车位预约、费用计算、数据统计等核心业务场景。使用 Spring Boot 作为后端框架,配合 Vue 3 构建现代化前端界面,能够帮助开发者掌握前后端分离架构的设计思路和实现细节。本文将基于 Spring Boot 和 Vue 3 技术栈,从零开始搭建一个功能完整的智慧停车场管理系统,重点讲解环境准备、项目结构设计、关键模块实现和常见问题排查。
1. 项目环境准备与依赖配置
在开始编码前,需要确保本地开发环境满足项目运行的基本要求。智慧停车场管理系统涉及前后端两个部分,需要分别配置相应的开发工具和运行环境。
1.1 后端开发环境要求
后端基于 Spring Boot 3.x 构建,需要 Java 17 或更高版本。建议使用 IntelliJ IDEA 作为开发 IDE,同时安装 Lombok 插件以简化实体类编写。
<!-- pom.xml 中的关键依赖配置 -->
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Starter Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
数据库使用 MySQL 8.0,需要在 application.yml 中配置数据源连接信息:
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/parking_management?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
server:
port: 8080
1.2 前端开发环境配置
前端使用 Vue 3 组合式 API 风格,需要 Node.js 16+ 和 npm 8+ 环境。推荐使用 VS Code 作为开发工具,并安装 Volar 扩展以提供更好的 Vue 3 开发体验。
// package.json 关键依赖
{
"dependencies": {
"vue": "^3.3.0",
"vue-router": "^4.2.0",
"axios": "^1.4.0",
"element-plus": "^2.3.0",
"pinia": "^2.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.0",
"vite": "^4.3.0",
"typescript": "^5.0.0",
"sass": "^1.62.0"
}
}
前端项目使用 Vite 作为构建工具,vite.config.js 基础配置如下:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
1.3 数据库表结构设计
停车场管理系统的核心数据模型包括用户表、停车场表、车位表、订单表等。以下是关键表的结构设计:
-- 停车场表
CREATE TABLE parking_lot (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL COMMENT '停车场名称',
address VARCHAR(200) NOT NULL COMMENT '停车场地址',
total_spaces INT NOT NULL COMMENT '总车位数量',
available_spaces INT NOT NULL COMMENT '可用车位数量',
price_per_hour DECIMAL(10,2) NOT NULL COMMENT '每小时价格',
status TINYINT DEFAULT 1 COMMENT '状态:0-关闭,1-开放',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 车位表
CREATE TABLE parking_space (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
parking_lot_id BIGINT NOT NULL COMMENT '所属停车场ID',
space_number VARCHAR(20) NOT NULL COMMENT '车位编号',
space_type TINYINT DEFAULT 1 COMMENT '车位类型:1-小型车,2-大型车',
status TINYINT DEFAULT 0 COMMENT '状态:0-空闲,1-已预约,2-使用中',
FOREIGN KEY (parking_lot_id) REFERENCES parking_lot(id)
);
-- 预约订单表
CREATE TABLE reservation_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL COMMENT '用户ID',
parking_space_id BIGINT NOT NULL COMMENT '车位ID',
start_time DATETIME NOT NULL COMMENT '预约开始时间',
end_time DATETIME NOT NULL COMMENT '预约结束时间',
total_amount DECIMAL(10,2) NOT NULL COMMENT '总金额',
order_status TINYINT DEFAULT 0 COMMENT '订单状态:0-待支付,1-已支付,2-已完成,3-已取消',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parking_space_id) REFERENCES parking_space(id)
);
2. 后端核心模块实现
Spring Boot 后端采用经典的三层架构:控制器层(Controller)、服务层(Service)、数据访问层(Repository)。下面重点讲解车位管理和订单处理两个核心模块的实现。
2.1 车位管理模块设计
车位管理模块负责停车场的车位信息维护、状态更新和查询功能。首先定义实体类和数据访问接口。
// ParkingSpace 实体类
@Entity
@Table(name = "parking_space")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ParkingSpace {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "parking_lot_id")
private ParkingLot parkingLot;
@Column(name = "space_number")
private String spaceNumber;
@Column(name = "space_type")
private Integer spaceType; // 1-小型车,2-大型车
@Column(name = "status")
private Integer status; // 0-空闲,1-已预约,2-使用中
@CreationTimestamp
@Column(name = "create_time")
private LocalDateTime createTime;
@UpdateTimestamp
@Column(name = "update_time")
private LocalDateTime updateTime;
}
// ParkingSpaceRepository 数据访问接口
@Repository
public interface ParkingSpaceRepository extends JpaRepository<ParkingSpace, Long> {
// 根据停车场ID和状态查询车位
List<ParkingSpace> findByParkingLotIdAndStatus(Long parkingLotId, Integer status);
// 根据车位编号查询
Optional<ParkingSpace> findBySpaceNumber(String spaceNumber);
// 统计某个停车场的空闲车位数量
@Query("SELECT COUNT(ps) FROM ParkingSpace ps WHERE ps.parkingLot.id = :parkingLotId AND ps.status = 0")
Long countAvailableSpacesByParkingLotId(@Param("parkingLotId") Long parkingLotId);
}
服务层实现车位状态管理和业务逻辑处理:
// ParkingSpaceService 接口
public interface ParkingSpaceService {
Page<ParkingSpaceVO> getParkingSpacesByPage(ParkingSpaceQuery query);
ParkingSpaceVO getParkingSpaceDetail(Long id);
boolean updateParkingSpaceStatus(Long spaceId, Integer status);
List<ParkingSpaceVO> getAvailableSpaces(Long parkingLotId);
}
// ParkingSpaceServiceImpl 实现类
@Service
@Transactional
@Slf4j
public class ParkingSpaceServiceImpl implements ParkingSpaceService {
@Autowired
private ParkingSpaceRepository parkingSpaceRepository;
@Autowired
private ParkingLotRepository parkingLotRepository;
@Override
public Page<ParkingSpaceVO> getParkingSpacesByPage(ParkingSpaceQuery query) {
// 构建查询条件
Specification<ParkingSpace> spec = (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (query.getParkingLotId() != null) {
predicates.add(criteriaBuilder.equal(root.get("parkingLot").get("id"), query.getParkingLotId()));
}
if (query.getStatus() != null) {
predicates.add(criteriaBuilder.equal(root.get("status"), query.getStatus()));
}
if (StringUtils.hasText(query.getSpaceNumber())) {
predicates.add(criteriaBuilder.like(root.get("spaceNumber"), "%" + query.getSpaceNumber() + "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
Pageable pageable = PageRequest.of(query.getPageNum() - 1, query.getPageSize(),
Sort.by(Sort.Direction.DESC, "createTime"));
Page<ParkingSpace> parkingSpacePage = parkingSpaceRepository.findAll(spec, pageable);
// 转换为VO对象
return parkingSpacePage.map(this::convertToVO);
}
@Override
public boolean updateParkingSpaceStatus(Long spaceId, Integer status) {
try {
ParkingSpace parkingSpace = parkingSpaceRepository.findById(spaceId)
.orElseThrow(() -> new RuntimeException("车位不存在"));
parkingSpace.setStatus(status);
parkingSpace.setUpdateTime(LocalDateTime.now());
parkingSpaceRepository.save(parkingSpace);
// 同步更新停车场的可用车位数量
updateParkingLotAvailableSpaces(parkingSpace.getParkingLot().getId());
return true;
} catch (Exception e) {
log.error("更新车位状态失败: spaceId={}, status={}", spaceId, status, e);
return false;
}
}
private void updateParkingLotAvailableSpaces(Long parkingLotId) {
Long availableCount = parkingSpaceRepository.countAvailableSpacesByParkingLotId(parkingLotId);
ParkingLot parkingLot = parkingLotRepository.findById(parkingLotId)
.orElseThrow(() -> new RuntimeException("停车场不存在"));
parkingLot.setAvailableSpaces(availableCount.intValue());
parkingLotRepository.save(parkingLot);
}
private ParkingSpaceVO convertToVO(ParkingSpace parkingSpace) {
ParkingSpaceVO vo = new ParkingSpaceVO();
vo.setId(parkingSpace.getId());
vo.setSpaceNumber(parkingSpace.getSpaceNumber());
vo.setSpaceType(parkingSpace.getSpaceType());
vo.setStatus(parkingSpace.getStatus());
vo.setParkingLotName(parkingSpace.getParkingLot().getName());
vo.setCreateTime(parkingSpace.getCreateTime());
return vo;
}
}
2.2 订单处理模块实现
订单模块处理用户的预约、支付、取消等业务流程,需要特别注意并发场景下的数据一致性。
// ReservationOrder 实体类
@Entity
@Table(name = "reservation_order")
@Data
public class ReservationOrder {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "parking_space_id")
private ParkingSpace parkingSpace;
@Column(name = "start_time")
private LocalDateTime startTime;
@Column(name = "end_time")
private LocalDateTime endTime;
@Column(name = "total_amount")
private BigDecimal totalAmount;
@Column(name = "order_status")
private Integer orderStatus; // 0-待支付,1-已支付,2-已完成,3-已取消
@CreationTimestamp
@Column(name = "create_time")
private LocalDateTime createTime;
}
// OrderService 订单服务
@Service
@Transactional
@Slf4j
public class OrderService {
@Autowired
private ReservationOrderRepository orderRepository;
@Autowired
private ParkingSpaceService parkingSpaceService;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 创建预约订单
public ReservationOrderVO createOrder(OrderCreateDTO createDTO) {
// 检查车位是否可用
ParkingSpace parkingSpace = checkParkingSpaceAvailable(createDTO.getParkingSpaceId());
// 计算费用
BigDecimal amount = calculateAmount(createDTO.getStartTime(), createDTO.getEndTime(),
parkingSpace.getParkingLot().getPricePerHour());
// 创建订单
ReservationOrder order = new ReservationOrder();
order.setParkingSpace(parkingSpace);
order.setStartTime(createDTO.getStartTime());
order.setEndTime(createDTO.getEndTime());
order.setTotalAmount(amount);
order.setOrderStatus(0); // 待支付
ReservationOrder savedOrder = orderRepository.save(order);
// 更新车位状态为已预约
parkingSpaceService.updateParkingSpaceStatus(createDTO.getParkingSpaceId(), 1);
return convertToVO(savedOrder);
}
// 支付订单
public boolean payOrder(Long orderId) {
ReservationOrder order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (!order.getOrderStatus().equals(0)) {
throw new RuntimeException("订单状态异常,无法支付");
}
// 模拟支付流程
order.setOrderStatus(1); // 已支付
orderRepository.save(order);
// 发送支付成功消息
sendPaymentSuccessMessage(order);
return true;
}
// 取消订单
public boolean cancelOrder(Long orderId) {
ReservationOrder order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (order.getOrderStatus().equals(2) || order.getOrderStatus().equals(3)) {
throw new RuntimeException("订单无法取消");
}
order.setOrderStatus(3); // 已取消
orderRepository.save(order);
// 释放车位
parkingSpaceService.updateParkingSpaceStatus(order.getParkingSpace().getId(), 0);
return true;
}
private ParkingSpace checkParkingSpaceAvailable(Long spaceId) {
ParkingSpace parkingSpace = parkingSpaceRepository.findById(spaceId)
.orElseThrow(() -> new RuntimeException("车位不存在"));
if (!parkingSpace.getStatus().equals(0)) {
throw new RuntimeException("车位当前不可用");
}
return parkingSpace;
}
private BigDecimal calculateAmount(LocalDateTime startTime, LocalDateTime endTime, BigDecimal pricePerHour) {
long hours = Duration.between(startTime, endTime).toHours();
if (hours < 1) {
hours = 1; // 不足1小时按1小时计算
}
return pricePerHour.multiply(BigDecimal.valueOf(hours));
}
}
3. 前端界面开发与接口对接
前端使用 Vue 3 组合式 API 和 Element Plus 组件库构建用户界面,通过 Axios 与后端 API 进行数据交互。
3.1 前端项目结构设计
src/
├── api/ # API接口封装
├── components/ # 公共组件
├── views/ # 页面组件
├── router/ # 路由配置
├── store/ # 状态管理
├── utils/ # 工具函数
└── assets/ # 静态资源
3.2 车位管理页面实现
车位管理页面展示停车场车位状态,支持按条件筛选和分页查询。
<template>
<div class="parking-space-management">
<el-card>
<template #header>
<div class="card-header">
<span>车位管理</span>
<el-button type="primary" @click="handleRefresh">刷新</el-button>
</div>
</template>
<!-- 查询条件 -->
<el-form :model="queryParams" inline>
<el-form-item label="停车场">
<el-select v-model="queryParams.parkingLotId" placeholder="请选择停车场">
<el-option
v-for="lot in parkingLots"
:key="lot.id"
:label="lot.name"
:value="lot.id"
/>
</el-select>
</el-form-item>
<el-form-item label="车位状态">
<el-select v-model="queryParams.status" placeholder="请选择状态">
<el-option label="全部" value="" />
<el-option label="空闲" :value="0" />
<el-option label="已预约" :value="1" />
<el-option label="使用中" :value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 车位列表 -->
<el-table :data="tableData" v-loading="loading">
<el-table-column prop="spaceNumber" label="车位编号" width="120" />
<el-table-column prop="parkingLotName" label="所属停车场" width="200" />
<el-table-column prop="spaceType" label="车位类型" width="100">
<template #default="scope">
<el-tag :type="scope.row.spaceType === 1 ? '' : 'warning'">
{{ scope.row.spaceType === 1 ? '小型车' : '大型车' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="scope">
<el-tag
:type="getStatusTagType(scope.row.status)"
>
{{ getStatusText(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180" />
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button size="small" @click="handleView(scope.row)">查看</el-button>
<el-button size="small" type="danger" @click="handleUpdateStatus(scope.row)">
更新状态
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getParkingSpaces, updateParkingSpaceStatus } from '@/api/parkingSpace'
import { getParkingLots } from '@/api/parkingLot'
const loading = ref(false)
const tableData = ref([])
const parkingLots = ref([])
const total = ref(0)
const queryParams = reactive({
parkingLotId: '',
status: '',
spaceNumber: '',
pageNum: 1,
pageSize: 10
})
// 获取车位列表
const fetchParkingSpaces = async () => {
loading.value = true
try {
const response = await getParkingSpaces(queryParams)
tableData.value = response.data.list
total.value = response.data.total
} catch (error) {
ElMessage.error('获取车位列表失败')
} finally {
loading.value = false
}
}
// 获取停车场列表
const fetchParkingLots = async () => {
try {
const response = await getParkingLots()
parkingLots.value = response.data
} catch (error) {
ElMessage.error('获取停车场列表失败')
}
}
// 状态标签类型
const getStatusTagType = (status) => {
const map = {
0: 'success', // 空闲
1: 'warning', // 已预约
2: 'danger' // 使用中
}
return map[status] || ''
}
// 状态文本
const getStatusText = (status) => {
const map = {
0: '空闲',
1: '已预约',
2: '使用中'
}
return map[status] || '未知'
}
// 查询
const handleSearch = () => {
queryParams.pageNum = 1
fetchParkingSpaces()
}
// 重置
const handleReset = () => {
Object.assign(queryParams, {
parkingLotId: '',
status: '',
spaceNumber: '',
pageNum: 1,
pageSize: 10
})
fetchParkingSpaces()
}
// 分页大小改变
const handleSizeChange = (size) => {
queryParams.pageSize = size
fetchParkingSpaces()
}
// 当前页改变
const handleCurrentChange = (page) => {
queryParams.pageNum = page
fetchParkingSpaces()
}
// 更新车位状态
const handleUpdateStatus = async (row) => {
try {
await ElMessageBox.confirm('确定要更新该车位状态吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const newStatus = row.status === 0 ? 1 : 0
await updateParkingSpaceStatus(row.id, newStatus)
ElMessage.success('状态更新成功')
fetchParkingSpaces()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('状态更新失败')
}
}
}
onMounted(() => {
fetchParkingLots()
fetchParkingSpaces()
})
</script>
3.3 API 接口封装
使用 Axios 封装 HTTP 请求,统一处理请求拦截、响应处理和错误处理。
// api/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'
// 创建axios实例
const service = axios.create({
baseURL: '/api',
timeout: 10000
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 添加token
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
// token过期处理
if (res.code === 401) {
localStorage.removeItem('token')
router.push('/login')
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
ElMessage.error('网络错误,请检查网络连接')
return Promise.reject(error)
}
)
export default service
// api/parkingSpace.js
import request from './request'
// 获取车位列表
export function getParkingSpaces(params) {
return request({
url: '/parking-space/page',
method: 'get',
params
})
}
// 更新车位状态
export function updateParkingSpaceStatus(spaceId, status) {
return request({
url: `/parking-space/${spaceId}/status`,
method: 'put',
data: { status }
})
}
// 获取可用车位
export function getAvailableSpaces(parkingLotId) {
return request({
url: `/parking-space/available/${parkingLotId}`,
method: 'get'
})
}
4. 系统部署与性能优化
完成开发后,需要将系统部署到生产环境,并进行必要的性能优化配置。
4.1 后端部署配置
使用 Docker 容器化部署 Spring Boot 应用,确保环境一致性。
# Dockerfile
FROM openjdk:17-jdk-slim
# 设置工作目录
WORKDIR /app
# 复制jar包
COPY target/parking-management-0.0.1-SNAPSHOT.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=prod"]
生产环境配置文件 application-prod.yml:
spring:
datasource:
url: jdbc:mysql://mysql-server:3306/parking_management?useUnicode=true&characterEncoding=utf8
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
jpa:
hibernate:
ddl-auto: validate
show-sql: false
redis:
host: redis-server
port: 6379
password: ${REDIS_PASSWORD}
timeout: 3000
lettuce:
pool:
max-active: 20
max-wait: -1
max-idle: 10
min-idle: 0
server:
port: 8080
tomcat:
max-connections: 10000
max-threads: 200
min-spare-threads: 10
4.2 前端构建与部署
使用 Vite 构建生产版本,配置 Nginx 作为静态文件服务器。
// vite.config.prod.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
outDir: 'dist',
assetsDir: 'assets',
rollupOptions: {
output: {
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
}
},
server: {
port: 3000
}
})
Nginx 配置示例:
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
# 后端API代理
location /api/ {
proxy_pass http://backend-server:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
4.3 数据库性能优化
针对停车场管理系统的高并发场景,需要对数据库进行性能优化。
-- 为常用查询字段添加索引
CREATE INDEX idx_parking_space_status ON parking_space(status);
CREATE INDEX idx_parking_space_lot_id ON parking_space(parking_lot_id);
CREATE INDEX idx_order_user_id ON reservation_order(user_id);
CREATE INDEX idx_order_status ON reservation_order(order_status);
CREATE INDEX idx_order_create_time ON reservation_order(create_time);
-- 分区表处理历史数据(按月份分区)
ALTER TABLE reservation_order PARTITION BY RANGE (YEAR(create_time)*100 + MONTH(create_time)) (
PARTITION p202401 VALUES LESS THAN (202402),
PARTITION p202402 VALUES LESS THAN (202403),
PARTITION p202403 VALUES LESS THAN (202404),
PARTITION p_max VALUES LESS THAN MAXVALUE
);
4.4 缓存策略设计
使用 Redis 缓存热点数据,减少数据库访问压力。
// Redis配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerializer序列化
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(Lazy更多推荐


所有评论(0)