news 2026/4/23 8:13:29

讲讲在Spring Boot项目中如何建立数据库和管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
讲讲在Spring Boot项目中如何建立数据库和管理

一、基础入门介绍

这里为了能让大家对人脸识别SDK结合数据库有个初步了解,我们先利用 ArcSoftFaceDemo ,讲解下此Demo是如何对人脸数据库进行管理的,以及如何正确地注册到 ArcFace SDK 的引擎中,以支持后续的人脸检测和识别功能。下面结合代码分析整个管理流程。

1、数据库环境准备

在开始使用 ArcsoftFaceDemo 前,需要先准备好 MySQL 数据库环境。为了快速搭建,可以直接使用 Docker 启动一个数据库实例。

使用 Docker 启动 MySQL 8.0

执行以下命令启动 MySQL 容器:

docker run -d \

--name arcsoft_mysql \

-e MYSQL_ROOT_PASSWORD=Root123 \

-e MYSQL_DATABASE=arcsoft_face \

-p 3306:3306 \

registry.cn-hangzhou.aliyuncs.com/china-images/mysql:8.0

说明:

--name arcsoft_mysql:容器名称,方便管理。

MYSQL_ROOT_PASSWORD=Root123:root 用户密码。

MYSQL_DATABASE=arcsoft_face:初始化创建数据库 arcsoft_face。

-p 3306:3306:将容器端口映射到宿主机,方便程序连接。

registry.cn-hangzhou.aliyuncs.com/china-images/mysql:8.0:指定使用 MySQL 8.0 阿里云镜像,如果有外网环境,可直接使用mysql:8.0代替。

如果你想了解更多 Docker 使用方式,可以参考其他 Docker 入门文档或教程。也可直接在物理操作系统上安装MySQL

数据库连接信息

启动完成后,你就可以通过以下信息连接数据库:

URL:物理机IP:3306

用户名:root

密码:Root123

数据库:arcsoft_face

这样就完成了数据库环境的搭建,为 ArcsoftFaceDemo 的人脸库管理做好了基础准备。

2、工程导入与数据库配置

在完成数据库环境准备后,下一步是导入 ArcSoftFaceDemo 工程,并将默认数据库配置改为 MySQL。

导入工程

从 ArcSoft 官网下载 ArcSoftFaceDemo 工程压缩包。

解压后,用 IntelliJ IDEA 打开工程目录。

修改数据库配置

工程默认使用的是 H2 内存数据库,适合快速演示和测试。但在正式环境中,建议切换到 MySQL 或其他持久化数据库。

打开 application.properties 文件,找到默认配置:

spring.datasource.url=jdbc:h2:file:./data/arcdb

spring.datasource.driver-class-name=org.h2.Driver

spring.datasource.username=sa

spring.datasource.password=password

spring.h2.console.enabled=true

spring.h2.console.path=/h2-console

spring.sql.init.mode=always

spring.sql.init.schema-locations=classpath:db/schema-h2.sql

说明:

spring.datasource.url:H2 数据库文件路径。

spring.datasource.driver-class-name:H2 数据库驱动。

spring.datasource.username / spring.datasource.password:数据库账号密码。

spring.h2.console.*:H2 Web 控制台相关配置,方便调试。

spring.sql.init.*:初始化 SQL 文件路径,用于创建示例表结构。

H2切换为MySQL

在正式环境中,我们需要将默认 H2 配置改为 MySQL。打开 application.properties,将数据库相关配置修改为 MySQL 连接信息:

spring.datasource.url=jdbc:mysql://localhost:3306/arcsoft_face?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.username=root

spring.datasource.password=Root123

spring.sql.init.mode=always

spring.sql.init.schema-locations=classpath:db/schema-mysql.sql

说明:

spring.datasource.url:MySQL 连接 URL,包含数据库名 arcsoft_face,字符集与时区设置。localhost地址根据实际数据库IP地址设置

spring.datasource.driver-class-name:MySQL 驱动类。

spring.datasource.username / spring.datasource.password:MySQL 账号密码,对应 Docker 启动 MySQL 时设置的用户名和密码。

spring.sql.init.*:初始化 SQL 文件路径,用于创建用户表结构(与 H2 不同,需要使用 MySQL 版本 SQL)。

验证数据库连接

启动 ArcSoftFaceDemo 工程。

检查启动日志,确认数据库连接成功:

HikariPool-1 - Starting...

HikariPool-1 - Start completed.

注意:使用 MySQL 客户端(如 mysql 命令行或 Navicat等)连接数据库,确认 arcsoft_face 数据库已创建成功。

创建用户表

如果 MySQL 数据库中没有表,需要执行初始化 SQL 创建 user_info 表:

CREATE TABLE IF NOT EXISTS user_info (

id BIGINT AUTO_INCREMENT PRIMARY KEY,

name VARCHAR(60) NOT NULL,

extra_info VARCHAR(500),

face_feature BLOB,

image_url VARCHAR(120),

create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

UNIQUE KEY user_info_name_uindex (name)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

关键字段说明:

id:用户唯一标识。

name:用户名。

face_feature:ArcSoft SDK 提取的人脸特征二进制数据。这里也可以根据业务来,使用text类型,存储base64编码后的字符串数据

image_url:注册证存储地址。

这样就完成了 MySQL 数据库接入 ArcSoftFaceDemo 的准备工作。

3、人脸注册过程说明(FaceService.java)

FaceService 是整个系统的人脸注册与管理核心逻辑,负责:

从数据库读取用户人脸信息

注册/更新人脸到 ArcFace SDK 内存引擎

删除人脸

系统启动时批量加载人脸

支持从数据库、本地图片、classpath 目录三种来源初始化

下面详细说明各功能模块的逻辑。

人脸注册核心方法:addUser

public void addUser(String name, byte[] faceFeature) {

UserInfo userInfo = userInfoMapper.selectOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getName, name));

if (userInfo == null) {

UserInfo userInfoInsert = new UserInfo();

userInfoInsert.setId((int) (System.currentTimeMillis() % 1_000_000_000)); //如果是MySQL数据库,可去掉这个,利用数据库自增长id来生成

userInfoInsert.setName(name);

userInfoInsert.setFaceFeature(faceFeature);

userInfoMapper.insert(userInfoInsert);

faceEngineService.registerFaceFeature2Engine(userInfoInsert.getId(), name, faceFeature);

} else {

UserInfo userInfoUpdate = new UserInfo();

userInfoUpdate.setId(userInfo.getId());

userInfoUpdate.setName(name);

userInfoUpdate.setFaceFeature(faceFeature);

userInfoMapper.updateById(userInfoUpdate);

faceEngineService.removeFaceFeature2Engine(userInfo.getId());

faceEngineService.registerFaceFeature2Engine(userInfo.getId(), name, faceFeature);

}

}

功能说明

addUser 是 ArcSoftFaceDemo 项目中最核心的人脸注册方法,主要功能是:

将输入的人脸特征(byte[])写入数据库

将人脸特征注册到 ArcFace 引擎的内存特征库(内存中的索引结构)

同步维护两端的数据一致性(数据库 ↔ 识别引擎)

ArcFace SDK 的识别能力依赖于内存中的特征库,因此每次注册、更新、删除都必须保持数据库与 SDK 内存库一致。在做新增的时候,同步两边需同时新增,保证数据一致性。

这里注册存储的时候,也可以同时带一些业务上的信息,如人员id,人员姓名,人员注册照存放地址等。这些信息,在数据库中可以以字段的形式进行存储归档,可参考上面user_info表进行字段扩展优化。如果想通过SDK的searchFaceFeature接口获取到这些额外信息,在registerFaceFeature接口中提供了faceTag的一个字符串类型,用于存放业务数据,可以把这些信息以JSON字符串形式存放到faceTag中去,当然也可通过searchId,再查询数据库的方式,把对应的人员信息查询出来

ArcFace SDK 提取的人脸特征是一个 byte[] 数组。5.0 的中模型特征长度在 2056字节,大模型特征特征长度3080字节,这里在做数据库字段大小的时候需要关注下

两种存储方式:SDK的特征类型是byte[]数组类型,存储到数据库方式:

1、可以直接使用BLOB类型,一般推荐用BLOB类型存储,可以减少编解码带来的性能损失

2、byte[]数组转成base64字符串,数据库用TEXT类型进行存储,如果涉及到网络传输,可使用Base64字符串

删除用户 removeUser

public void removeUser(String name) {

UserInfo userInfo = userInfoMapper.selectOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getName, name));

if (userInfo != null) {

faceEngineService.removeFaceFeature2Engine(userInfo.getId());

userInfoMapper.deleteById(userInfo.getId());

}

}

根据用户名查询用户

从 SDK 内存引擎移除人脸

从数据库删除记录

系统启动时自动加载人脸

@PostConstruct

public void loadImage2Engine() {

if ("true".equals(faceImageClear)) {

removeAllUser();

initSystemFace();

File file = new File(testImagePath);

if (file.isDirectory()) {

File[] files = file.listFiles();

log.info("开始加载本地人脸图片到引擎中");

for (File imageFile : files) {

String name = imageFile.getName();

if (name.endsWith(".jpg") || name.endsWith(".png")) {

String userName = name.substring(0, name.lastIndexOf("."));

register(userName, imageFile, null);

}

}

log.info("加载本地人脸图片到引擎中完成");

}

}else {

initDatabaseFace2Engine();

}

}

系统启动后执行,用于初始化内存人脸库,为了加快识别速度,建议每次启动服务后,就直接把数据库里的人脸注册信息放到SDK引擎里,减少下次识别读取数据库带来的耗时增加。Demo中提供了有两种模式,根据配置文件的register.faceimage.clean进行切换

register.faceimage.clean=true,每次启动会清空数据库,重新加载本地图片进行注册,同时存储到数据库和SDK

register.faceimage.clean=false,每次启动从数据库读取特征,加载到SDK。Demo为了测试,会同时把本地本次未注册的图片进行存储和注册,生产环境可只保留从数据库读取加载

4、人脸识别方式

这里再另外提一下,SDK人脸识别主要有以下两种方案,Demo采用的是第2种方案,也可根据实际业务使用第1种方案

①、使用 Map 列表 + compareFaceFeature 接口

原理:将注册的人脸特征存放在 Map 或列表中,通过 SDK 的 compareFaceFeature 接口进行循环比对。

优点:可灵活分组管理人脸库;支持多线程并发比对。

缺点:当人脸库量大时,频繁调用比对接口会增加性能损耗。

②、使用 SDK 提供的原生接口注册

原理:利用registerFaceFeature、removeFaceFeature、updateFaceFeature、searchFaceFeature 组合接口,实现对人脸的增删改查

优点:SDK 原生实现比对,性能快,资源消耗少。

缺点:不支持分组比对;系统重启后需重新注册特征;多引擎并发时,每个引擎的人脸库需单独管理,维护复杂。

​ 为了实现长久保存和分布式共享,人脸特征需进行合理存储

5、人脸引擎说明(FaceEngineService.java)

FaceEngineService 是人脸SDK 的核心部分,负责:

人脸检测、特征提取、活体检测、属性检测等

人员信息的新增、删除、修改、人脸搜索

下面详细说明各功能模块的逻辑。

人员新增:registerFaceFeature2Engine

public void registerFaceFeature2Engine(int searchId, String faceTag, byte[] faceFeature) {

FaceEngineFactory factory = (FaceEngineFactory) faceEngineComparePool.getFactory();

List<FaceEngine> allObjects = factory.getAllObjects();

FaceFeatureInfo faceFeatureInfo = new FaceFeatureInfo();

faceFeatureInfo.setSearchId(searchId);

faceFeatureInfo.setFaceTag(faceTag);

faceFeatureInfo.setFeatureData(faceFeature);

// log.info("Register:"+ JSON.toJSONString(faceFeatureInfo));

for (FaceEngine allObject : allObjects) {

int res = allObject.registerFaceFeature(faceFeatureInfo);

}、、

}

这里重点说明下,因为我们的FaceEngine用了线程池,同时初始化了多个引擎,所以我们在向SDK注册人员信息的时候,需要给每个引擎进行注册,删除同理。

人员新增:removeFaceFeature2Engine

public void removeFaceFeature2Engine(int searchId) {

FaceEngineFactory factory = (FaceEngineFactory) faceEngineComparePool.getFactory();

List<FaceEngine> allObjects = factory.getAllObjects();

for (FaceEngine allObject : allObjects) {

allObject.removeFaceFeature(searchId);

}

}

删除同注册接口,需要同步向所有FaceEngine库进行移除操作

二、人脸特征三层存储与分布式管理

上面已经介绍了基本的数据库接入和使用,那么在实际人脸识别场景下,系统的数据存储与识别通常采用三层设计:

MySQL:负责持久化存储人脸特征信息,实现可靠的长期保存。

Redis:用于异步更新与分布式缓存,实现多机器环境下的人脸特征共享。

内存(ConcurrentHashMap / 特征池):存储当前在线的活跃人脸特征,实现毫秒级识别。

这种设计保证了系统既能持久化存储,又能在识别时获得最佳性能。

在 Spring Boot 项目中,实现人脸特征的管理可以从数据库建表、服务层加载、Redis缓存、特征注册与比对几个方面进行详细设计。

在多台识别服务器部署的分布式环境中,人脸特征需要在各节点之间保持一致性、高可用和高性能。结合内存、Redis 和数据库三层存储,设计参考方案:

1、 启动加载策略

流程:

每台识别服务器启动时,先从 Redis 拉取最新的人脸特征到本地内存缓存。

如果 Redis 中没有特征数据(如初次部署),则从 MySQL 数据库加载。Redis 可作为 内存缓存 + 异步更新机制,保证各节点识别数据一致性

加载后,内存缓存即可支持毫秒级人脸识别。

实现示例:

@PostConstruct

public void loadFeaturesOnStartup() {

Set<String> keys = redisTemplate.keys("face:*");

if (keys != null && !keys.isEmpty()) {

for (String key : keys) {

byte[] featureData =(byte[]) redisTemplate.opsForValue().get(key);

if (featureData != null) {

featureMap.put(key.replace("face:", ""), featureData);

}

}

} else {

// Redis为空,从数据库加载

List<FaceFeature> features = repository.findAll();

for (FaceFeature f : features) {

featureMap.put(f.getUserId(), f.getFeature());

redisTemplate.opsForValue().set("face:" + f.getUserId(), f.getFeature());

}

}

}

优势:

避免每次识别都访问数据库,提高性能。

启动即加载最新特征,保证识别数据实时性。

2、 特征更新与同步策略

在分布式场景下,用户新增、删除或更新人脸特征时,需要保证所有节点内存保持一致:

更新顺序:

写内存:立即更新本地内存缓存,保证识别服务实时可用。

写 Redis:同步到 Redis,作为分布式共享层。

写数据库:异步持久化到 MySQL,保证长期数据安全。

同步机制:

利用 Redis Pub/Sub 或消息队列(Kafka、RabbitMQ)广播更新事件。

其他节点接收到更新事件后,刷新本地内存特征缓存。

示例逻辑:

public void updateFeature(String userId, byte[] feature) {

// 更新本地内存

featureMap.put(userId, feature);

// 更新 Redis

redisTemplate.opsForValue().set("face:" + userId, feature);

// 发布更新事件通知其他节点

redisTemplate.convertAndSend("face:update", userId);

// 异步更新数据库

asyncUpdateDatabase(userId, feature);

}

// 订阅事件刷新内存

@EventListener

public void handleRedisUpdateEvent(Message message) {

String userId = (String) message.getBody();

String feature = redisTemplate.opsForValue().get("face:" + userId);

if (feature != null) {

featureMap.put(userId, feature);

}

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 6:20:29

34、使用 awk 实现简单拼写检查器

使用 awk 实现简单拼写检查器 在文本处理中,拼写检查是一项常见且重要的任务。本文将详细介绍如何使用 awk 语言实现一个简单的拼写检查器,包括字典的加载、命令行选项的处理、后缀规则的应用等关键步骤,并给出完整的代码示例。 1. 字典的获取 在编写拼写检查器时,首先需…

作者头像 李华
网站建设 2026/4/21 2:52:43

Stata 18 多元统计 + 数据管理 让数据分析更专业安装教程

前言 Stata 18 该版本在历代版本基础上&#xff0c;聚焦因果推断、元分析、生存分析等核心研究领域&#xff0c;全面强化统计分析能力&#xff0c;同时优化数据管理、图表制作与结果报告等功能模块&#xff0c;广泛适用于经济学、医学、社会学等学科的实证研究工作。 版本亮点…

作者头像 李华
网站建设 2026/4/18 9:17:12

48、Unix 技术知识全解析:从基础命令到前沿概念

Unix 技术知识全解析:从基础命令到前沿概念 1. 重要 Unix 命令 在 Unix 系统中,存在众多用于进程管理和文件操作的重要命令,这些命令是系统操作的基础。 - 进程相关命令 :包括用于创建、删除或管理进程的命令,如 at 可在指定时间执行作业, batch 会在系统负载不…

作者头像 李华
网站建设 2026/4/21 8:30:02

别再乱选了!LLM应用实时通信技术SSE、WebSocket、WebRTC全方位对比

一、核心技术原理剖析 在为大型语言模型&#xff08;LLM&#xff09;应用构建实时前后端通信系统时&#xff0c;选择正确的底层技术至关重要。本章节将深入剖析三种主流技术的核心原理&#xff1a; Server-Sent Events (SSE)&#xff0c;它作为服务器主导的单向数据流的黄金标…

作者头像 李华
网站建设 2026/4/16 19:45:58

MySQL MOD()函数详解与Python对比

✅ 一、MySQL 的 MOD() 函数是怎么计算的&#xff1f;MOD(x, y) 是取余数的操作&#xff0c;即&#xff1a; &#x1f449; x % y&#xff08;在数学上就是 x 除以 y 的余数&#xff09;&#x1f50d; 示例解析&#xff1a;SELECT MOD(31, 8), MOD(234, 0), MOD(46.6, 6);表达式…

作者头像 李华