提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。
在 Spring AI 1.0.0 中,JdbcChatMemoryRepository 是 ChatMemoryRepository 接口的一个实现类,它利用 JDBC(Java Database Connectivity)技术,将聊天记忆数据存储到关系型数据库中。
JdbcChatMemoryRepository 的主要功能是提供一种持久化的方式来管理聊天会话的相关信息,包括会话 ID、会话中的消息等。通过与关系型数据库交互,它可以在应用程序重启后依然保留聊天记忆数据,适用于对数据持久性有要求的场景。
注意,JdbcChatMemoryRepository 并不在 spring-ai-model-1.0.0.jar 包中,而是位于 spring-ai-model-chat-memory-repository-jdbc-1.0.0.jar 中,如下图:

根据上图,目前提供四种数据库方言,分别是 hsqldb、mariadb(mysql 也可用)、postgresql 和 sqlserver。
JdbcChatMemoryRepository 内部采用 JdbcTemplate 去与数据库交互,源码如下:
package org.springframework.ai.chat.memory.repository.jdbc;
//...
/**
* ChatMemoryRepository 接口的 JDBC 实现类,用于通过关系型数据库持久化存储聊天会话消息。
* 支持事务管理和多数据库方言适配,确保数据的持久性和操作的原子性。
*/
public final class JdbcChatMemoryRepository implements ChatMemoryRepository {
/**
* JDBC 操作模板,封装数据库连接和 SQL 执行逻辑
*/
private final JdbcTemplate jdbcTemplate;
/**
* 事务模板,用于管理数据库操作的事务(如保存消息时的删除旧数据+插入新数据的原子性)
*/
private final TransactionTemplate transactionTemplate;
/**
* 数据库方言,封装不同数据库的 SQL 语句差异(如 MySQL、PostgreSQL 等)
*/
private final JdbcChatMemoryRepositoryDialect dialect;
/**
* 日志记录器,用于记录操作日志
*/
private static final Logger logger = LoggerFactory.getLogger(JdbcChatMemoryRepository.class);
/**
* 构造方法,初始化 JDBC 模板、数据库方言和事务管理器
*
* @param jdbcTemplate JDBC 操作模板,不可为 null
* @param dialect 数据库方言,不可为 null
* @param txManager 事务管理器,可为 null(默认使用数据源事务管理器)
*/
private JdbcChatMemoryRepository(JdbcTemplate jdbcTemplate,
JdbcChatMemoryRepositoryDialect dialect, PlatformTransactionManager txManager) {
Assert.notNull(jdbcTemplate, "jdbcTemplate cannot be null");
Assert.notNull(dialect, "dialect cannot be null");
this.jdbcTemplate = jdbcTemplate;
this.dialect = dialect;
// 初始化事务模板,若未指定事务管理器则使用默认的数据源事务管理器
this.transactionTemplate = new TransactionTemplate(
txManager != null ? txManager : new DataSourceTransactionManager(jdbcTemplate.getDataSource())
);
}
/**
* 查询所有存在的会话 ID 列表
* @return 所有会话 ID 的列表,无会话时返回空列表
*/
public List<String> findConversationIds() {
// 通过方言获取查询会话 ID 的 SQL,执行查询并返回结果
return this.jdbcTemplate.queryForList(this.dialect.getSelectConversationIdsSql(), String.class);
}
/**
* 根据会话 ID 查询对应的消息列表
* @param conversationId 会话唯一标识,不可为 null 或空字符串
* @return 该会话的消息列表,会话不存在时返回空列表
* @throws IllegalArgumentException 若 conversationId 为 null 或空
*/
public List<Message> findByConversationId(String conversationId) {
Assert.hasText(conversationId, "conversationId cannot be null or empty");
// 通过方言获取查询消息的 SQL,使用 MessageRowMapper 映射结果集,并传入会话 ID 作为参数
return this.jdbcTemplate.query(
this.dialect.getSelectMessagesSql(),
new MessageRowMapper(),
new Object[]{conversationId}
);
}
/**
* 保存指定会话的消息列表(先删除旧消息,再批量插入新消息,操作在事务中执行)
*
* @param conversationId 会话唯一标识,不可为 null 或空字符串
* @param messages 待保存的消息列表,不可为 null 且不能包含 null 元素
* @throws IllegalArgumentException 若参数不满足合法性要求
*/
public void saveAll(String conversationId, List<Message> messages) {
Assert.hasText(conversationId, "conversationId cannot be null or empty");
Assert.notNull(messages, "messages cannot be null");
Assert.noNullElements(messages, "messages cannot contain null elements");
// 在事务中执行:先删除该会话的旧消息,再批量插入新消息
this.transactionTemplate.execute((status) -> {
this.deleteByConversationId(conversationId);
this.jdbcTemplate.batchUpdate(
this.dialect.getInsertMessageSql(),
new AddBatchPreparedStatement(conversationId, messages)
);
return null;
});
}
/**
* 根据会话 ID 删除对应的所有消息
*
* @param conversationId 会话唯一标识,不可为 null 或空字符串
* @throws IllegalArgumentException 若 conversationId 为 null 或空
*/
public void deleteByConversationId(String conversationId) {
Assert.hasText(conversationId, "conversationId cannot be null or empty");
// 通过方言获取删除消息的 SQL,执行删除操作
this.jdbcTemplate.update(this.dialect.getDeleteMessagesSql(), new Object[]{conversationId});
}
//...(省略内部类如 MessageRowMapper、AddBatchPreparedStatement 的实现)
}下面将以本地 MySQL 数据库为例。
首先,在项目中添加以下依赖:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-autoconfigure-model-chat-memory-repository-jdbc</artifactId> <version>1.0.0</version> </dependency> <!-- Spring Data JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <!-- mysql 驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> </dependency>
如果你还没有数据库,先在本地安装 mysql 数据库,然后创建名为 chat_db 的数据库。
完成 mysql 安装后,在 Spring Boot 配置中配置数据库,如下:
spring: application: name: springai_demo1 # 数据库配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/chat_db username: root password: aaaaaa
注意,还有一步不要忘了?就是创建数据库表,数据库表的结构可以参考依赖 jar 包中的 schema-*.sql 文件,如下:

schema-mariadb.sql 文件的内容如下:
CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY (
conversation_id VARCHAR(36) NOT NULL,
content TEXT NOT NULL,
type VARCHAR(10) NOT NULL,
`timestamp` TIMESTAMP NOT NULL,
CONSTRAINT TYPE_CHECK CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL'))
);
CREATE INDEX IF NOT EXISTS SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX
ON SPRING_AI_CHAT_MEMORY(conversation_id, `timestamp`);直接在 MySQL 上执行有错误,修改后的版本:
CREATE TABLE `SPRING_AI_CHAT_MEMORY` ( `conversation_id` varchar(36) NOT NULL, `content` text NOT NULL, `type` varchar(10) NOT NULL, `timestamp` timestamp NOT NULL, KEY `SPRING_AI_CHAT_MEMORY_timestamp_IDX` (`timestamp`) USING BTREE, CONSTRAINT `TYPE_CHECK` CHECK ((`type` in (_utf8mb4'USER',_utf8mb4'ASSISTANT',_utf8mb4'SYSTEM',_utf8mb4'TOOL'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
注意:可以通过 spring.ai.chat.memory.repository.jdbc.initialize-schema 参数进行配置,该配置决定了应用启动时,Spring AI 是否会自动处理(创建)聊天记忆相关的数据库表结构。具体行为取决于配置的值,常见取值包括:
always:每次应用启动时,都会执行建表语句(若表不存在则创建,若已存在可能会忽略或根据方言处理)。
embedded:仅在使用嵌入式数据库(如 H2、HSQLDB)时自动建表,适用于开发或测试场景。
never:不自动初始化表结构,需手动创建表(需严格遵循 JdbcChatMemoryRepository 预期的表结构定义)。
由于我们这里使用的是 mysql 数据库,配置为 always 将会抛出错误:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcChatMemoryScriptDatabaseInitializer' defined in class path resource [org/springframework/ai/model/chat/memory/repository/jdbc/autoconfigure/JdbcChatMemoryRepositoryAutoConfiguration.class]: No schema scripts found at location 'classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-mysql.sql'
...
原因是 schema-mysql.sql 脚本不存在。那就自己手动创建就可以了。
Spring AI 为 JdbcChatMemoryRepository 提供自动配置,可直接在应用中使用。
@Autowired private JdbcChatMemoryRepository chatMemoryRepository; ChatMemory chatMemory = MessageWindowChatMemory.builder() .chatMemoryRepository(chatMemoryRepository) .maxMessages(10) .build();
如需手动创建 JdbcChatMemoryRepository,可通过注入 JdbcTemplate 实例及 JdbcChatMemoryRepositoryDialect 实现:
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder() .jdbcTemplate(jdbcTemplate) .dialect(new PostgresChatMemoryDialect()) .build(); ChatMemory chatMemory = MessageWindowChatMemory.builder() .chatMemoryRepository(chatMemoryRepository) .maxMessages(10) .build();
完整示例代码如下:
package com.hxstrive.springai.springai_openai.chatMemoryRepository.chatMemoryRepository2;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class SpringAiDemoApplication implements CommandLineRunner {
@Autowired
private ChatModel chatModel;
@Autowired
private JdbcChatMemoryRepository chatMemoryRepository;
private ChatMemory chatMemory;
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// 创建 ChatMemory 实现
chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository) // 使用JdbcChatMemoryRepository作为存储仓库
.maxMessages(20) // 最多保存20条消息
.build();
StringBuilder builder = new StringBuilder();
// 唯一会话ID,同一个会话上下文中保持一致
String sessionId = "USER-251017100313";
String question = "四川大学是985吗?";
String ai = chat(sessionId, question);
builder.append(String.format("用户问题:%s\n", question));
builder.append(String.format("机器回复:%s\n", ai));
question = "是211吗?";
ai = chat(sessionId, question);
builder.append(String.format("用户问题:%s\n", question));
builder.append(String.format("机器回复:%s\n", ai));
System.out.println(builder.toString());
}
private String chat(String sessionId, String question) {
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是AI助手小粒,所有回复均使用中文。")
.defaultAdvisors(
new SimpleLoggerAdvisor() // 输出聊天日志
).build();
// 1. 将用户输入添加到记忆
UserMessage userMessage = new UserMessage(question);
chatMemory.add(sessionId, userMessage);
// 2. 获取记忆中的所有消息(上下文),传递给 AI 模型
ChatClient.CallResponseSpec responseSpec = chatClient.prompt().messages(chatMemory.get(sessionId)).call();
// 3. 将 AI 回复添加到记忆,更新上下文
AssistantMessage assistantMessage = responseSpec.chatResponse().getResult().getOutput();
chatMemory.add(sessionId, assistantMessage);
// 4. 返回 AI 回复内容
return assistantMessage.getText();
}
}运行结果如下:
Spring AI 通过方言抽象层支持多种关系型数据库,以下为开箱即用支持的数据库:
PostgreSQL
MySQL / MariaDB
SQL Server
HSQLDB
使用 JdbcChatMemoryRepositoryDialect.from(DataSource) 时可基于 JDBC URL 自动识别正确方言。源码如下:
static JdbcChatMemoryRepositoryDialect from(DataSource dataSource) {
try {
String url = dataSource.getConnection().getMetaData().getURL().toLowerCase();
if (url.contains("postgresql")) {
return new PostgresChatMemoryRepositoryDialect();
}
if (url.contains("mysql")) {
return new MysqlChatMemoryRepositoryDialect();
}
if (url.contains("mariadb")) {
return new MysqlChatMemoryRepositoryDialect();
}
if (url.contains("sqlserver")) {
return new SqlServerChatMemoryRepositoryDialect();
}
if (url.contains("hsqldb")) {
return new HsqldbChatMemoryRepositoryDialect();
}
} catch (Exception var2) {
}
return new PostgresChatMemoryRepositoryDialect(); // 默认采用 PostgresSQL 数据库
}然后,通过实现 JdbcChatMemoryRepositoryDialect 接口可扩展其他数据库支持。
spring.ai.chat.memory.repository.jdbc.initialize-schema 控制初始化 Schema 的时机。可选值:embedded(默认)、always(总是创建)、never(从不创建)。默认为 embedded
spring.ai.chat.memory.repository.jdbc.schema 用于初始化的 Schema 脚本位置。支持 classpath: URL 及平台占位符。默认为 classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-@@platform@@.sql
spring.ai.chat.memory.repository.jdbc.platform 若初始化脚本中使用 @@platform@@ 占位符,则指定其对应的平台标识。默认为 auto-detected
自动配置将在启动时使用特定于供应商的 SQL 脚本创建 SPRING_AI_CHAT_MEMORY 表。默认情况下,仅针对嵌入式数据库(H2、HSQL、Derby 等)执行 Schema 初始化。
可通过 spring.ai.chat.memory.repository.jdbc.initialize-schema 属性控制 Schema 初始化行为:
spring.ai.chat.memory.repository.jdbc.initialize-schema=embedded # Only for embedded DBs (default) spring.ai.chat.memory.repository.jdbc.initialize-schema=always # Always initialize spring.ai.chat.memory.repository.jdbc.initialize-schema=never # Never initialize (useful with Flyway/Liquibase)
要覆盖默认的 Schema 脚本位置,请使用:
spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql
要新增数据库支持,需实现 JdbcChatMemoryRepositoryDialect 接口并提供消息查询、插入及删除的 SQL 语句。随后可将自定义方言传入 Repository Builder。如下:
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder() .jdbcTemplate(jdbcTemplate) .dialect(new MyCustomDbDialect()) .build();
下面是 MySQL 方言官方实现:
package org.springframework.ai.chat.memory.repository.jdbc;
public class MysqlChatMemoryRepositoryDialect implements JdbcChatMemoryRepositoryDialect {
public MysqlChatMemoryRepositoryDialect() {
}
public String getSelectMessagesSql() {
return "SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY `timestamp`";
}
public String getInsertMessageSql() {
return "INSERT INTO SPRING_AI_CHAT_MEMORY (conversation_id, content, type, `timestamp`) VALUES (?, ?, ?, ?)";
}
public String getSelectConversationIdsSql() {
return "SELECT DISTINCT conversation_id FROM SPRING_AI_CHAT_MEMORY";
}
public String getDeleteMessagesSql() {
return "DELETE FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?";
}
}上述源码中就四条 SQL 语句,你可以仿照实现自己的数据库方言(如:SQLite、Oracle 等等)。更多信息请访问官方文档。
提示:如果不能访问 OpenAI,请点击 AiCode API 注册账号,通过代理访问。