Repository: alibaba/spring-ai-alibaba
Pull request #516: update mysql to jdbc chat memory
Author: login: future0923
Created: 2025-03-25T06:16:13Z | Merged: 2025-03-31T07:59:20Z

### Describe what this PR does / why we need it

1. 聊天记忆功能将mysql实现改为对JdbcChatMemory抽象层，因为java jdbc是数据连接的抽象层，实际项目中驱动不即可切换数据库。
2. 默认提供了MysqlChatMemory、OracleChatMemory、PostgresChatMemory、SqlServerChatMemory
3. 去掉了之前的mysql对jdbcurl的格式，改为直接传入jdbcUrl，因为不同的数据库jdbcUrl不同，之前也无法对链接进行参数设置
4. 优化了表结构的创建，以支持对LLM返回的emoij表情的处理
5. 其他jdbc数据库只需要实现JdbcChatMemory抽象类接口即可扩展

### Does this pull request fix one issue?

<!--If that, add "Fixes #xxxx" below in the next line. For example, Fixes #15. Otherwise, add "NONE" -->

### Describe how you did it

对JdbcChatMemory抽象层，因为java jdbc是数据连接的抽象层，实际项目中驱动不即可切换数据库。

### Describe how to verify it

MysqlChatMemoryTest、OracleChatMemoryTest、PostgresChatMemoryTest、SqlServerChatMemoryTest的测试类通过

### Special notes for reviews


Linked issue #15: the document has error about hello-examples
the document has error about using hello-examples


**Which Component**
hello-examples

**Describe the bug**
the url is localhost:8080/ai/chat?input=?

**Simplest demo**
localhost:8080/ai/chat?input=?

Linked issue comments: user: login: chickenlj
created_at: 2024-09-23T05:51:48Z
body: Thanks, it's been fixed.
author_association: COLLABORATOR

Diff:
diff --git a/community/memories/spring-ai-alibaba-mysql-memory/pom.xml b/community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
similarity index 84%
rename from community/memories/spring-ai-alibaba-mysql-memory/pom.xml
rename to community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
index 2f93f15def..1ab3065de8 100644
--- a/community/memories/spring-ai-alibaba-mysql-memory/pom.xml
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
@@ -25,9 +25,9 @@
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
-    <artifactId>spring-ai-alibaba-mysql-memory</artifactId>
-    <name>spring-ai-alibaba-mysql-memory</name>
-    <description>Mysql ChatMemory implementation for Spring AI Alibaba</description>
+    <artifactId>spring-ai-alibaba-jdbc-memory</artifactId>
+    <name>spring-ai-alibaba-jdbc-memory</name>
+    <description>Jdbc ChatMemory implementation for Spring AI Alibaba</description>
     <packaging>jar</packaging>
     <url>https://github.com/alibaba/spring-ai-alibaba</url>
     <scm>
@@ -55,9 +55,34 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.32</version>
-            <optional>true</optional>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc8</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.microsoft.sqlserver</groupId>
+            <artifactId>mssql-jdbc</artifactId>
+            <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.xerial</groupId>
+            <artifactId>sqlite-jdbc</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
         <!-- test dependencies -->
         <dependency>
             <groupId>org.springframework.ai</groupId>
@@ -83,22 +108,6 @@
             <scope>test</scope>
         </dependency>
 
-        <!-- JUnit Jupiter API for testing -->
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
-            <version>5.8.2</version>
-            <scope>test</scope>
-        </dependency>
-        
-        <!-- JUnit Jupiter Engine for testing -->
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-engine</artifactId>
-            <version>5.8.2</version>
-            <scope>test</scope>
-        </dependency>
-
     </dependencies>
 
     <build>
diff --git a/community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/MysqlChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/JdbcChatMemory.java
similarity index 69%
rename from community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/MysqlChatMemory.java
rename to community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/JdbcChatMemory.java
index 0baf713cd0..11cdcf889b 100644
--- a/community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/MysqlChatMemory.java
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/JdbcChatMemory.java
@@ -13,61 +13,60 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.alibaba.cloud.ai.memory.mysql;
-
-import java.sql.DriverManager;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.PreparedStatement;
-import java.util.ArrayList;
-import java.util.List;
+package com.alibaba.cloud.ai.memory.jdbc;
 
+import com.alibaba.cloud.ai.memory.jdbc.serializer.MessageDeserializer;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.module.SimpleModule;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.springframework.ai.chat.memory.ChatMemory;
 import org.springframework.ai.chat.messages.Message;
 
-import com.alibaba.cloud.ai.memory.mysql.serializer.MessageDeserializer;
-
-public class MysqlChatMemory implements ChatMemory, AutoCloseable {
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
 
-	private static final Logger logger = LoggerFactory.getLogger(MysqlChatMemory.class);
+/**
+ * @author future0923
+ */
+public abstract class JdbcChatMemory implements ChatMemory, AutoCloseable {
 
-	private static final String DEFAULT_DATABASE = "spring_ai_alibaba_mysql";
+	private static final Logger logger = LoggerFactory.getLogger(JdbcChatMemory.class);
 
 	private static final String DEFAULT_TABLE_NAME = "chat_memory";
 
-	private static final String DEFAULT_URL = "127.0.0.1:3306";
+	private final Connection connection;
 
-	private static final String DEFAULT_USERNAME = "root";
+	private final String tableName;
 
-	private static final String DEFAULT_PASSWORD = "root";
+	private final ObjectMapper objectMapper = new ObjectMapper();
 
-	private final Connection connection;
+	protected abstract String jdbcType();
 
-	private final ObjectMapper objectMapper = new ObjectMapper();
+	protected abstract String hasTableSql(String tableName);
 
-	public MysqlChatMemory() {
+	protected abstract String createTableSql(String tableName);
 
-		this(DEFAULT_USERNAME, DEFAULT_PASSWORD, DEFAULT_URL);
+	protected JdbcChatMemory(String username, String password, String jdbcUrl) {
+		this(username, password, jdbcUrl, DEFAULT_TABLE_NAME);
 	}
 
-	public MysqlChatMemory(String username, String password, String url) {
+	protected JdbcChatMemory(String username, String password, String jdbcUrl, String tableName) {
 		// Configure ObjectMapper to support interface deserialization
 		SimpleModule module = new SimpleModule();
 		module.addDeserializer(Message.class, new MessageDeserializer());
 		this.objectMapper.registerModule(module);
-
+		this.tableName = tableName;
 		try {
-			this.connection = DriverManager.getConnection(
-					String.format("jdbc:mysql://%s/%s?serverTimezone=UTC", url, DEFAULT_DATABASE), username, password);
+			this.connection = DriverManager.getConnection(jdbcUrl, username, password);
 			checkAndCreateTable();
 		}
 		catch (SQLException e) {
@@ -75,14 +74,17 @@ public MysqlChatMemory(String username, String password, String url) {
 		}
 	}
 
-	public MysqlChatMemory(Connection connection) {
+	protected JdbcChatMemory(Connection connection) {
+		this(connection, DEFAULT_TABLE_NAME);
+	}
+
+	protected JdbcChatMemory(Connection connection, String tableName) {
 		// Configure ObjectMapper to support interface deserialization
 		SimpleModule module = new SimpleModule();
 		module.addDeserializer(Message.class, new MessageDeserializer());
 		this.objectMapper.registerModule(module);
-
 		this.connection = connection;
-
+		this.tableName = tableName;
 		try {
 			checkAndCreateTable();
 		}
@@ -92,15 +94,13 @@ public MysqlChatMemory(Connection connection) {
 	}
 
 	private void checkAndCreateTable() throws SQLException {
-
-		String checkTableQuery = String.format("SHOW TABLES LIKE '%s'", DEFAULT_TABLE_NAME);
+		String checkTableQuery = hasTableSql(tableName);
 		try (Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(checkTableQuery)) {
-
 			if (rs.next()) {
-				logger.info("Table " + DEFAULT_TABLE_NAME + " exists.");
+				logger.info("Table {} exists.", tableName);
 			}
 			else {
-				logger.info("Table " + DEFAULT_TABLE_NAME + " does not exist. Creating table...");
+				logger.info("Table {} does not exist. Creating table...", tableName);
 				createTable();
 			}
 		}
@@ -108,13 +108,11 @@ private void checkAndCreateTable() throws SQLException {
 
 	private void createTable() {
 		try (Statement stmt = connection.createStatement()) {
-			stmt.execute("USE spring_ai_alibaba_mysql");
-			stmt.execute(
-					"CREATE TABLE chat_memory( id BIGINT AUTO_INCREMENT PRIMARY KEY,conversation_id  VARBINARY(256)  NULL,messages TEXT NULL,UNIQUE (conversation_id));");
-			logger.info("Table " + DEFAULT_TABLE_NAME + " created successfully.");
+			stmt.execute(createTableSql(tableName));
+			logger.info("Table {} created successfully.", tableName);
 		}
 		catch (Exception e) {
-			throw new RuntimeException("Error creating table " + DEFAULT_TABLE_NAME + " ", e);
+			throw new RuntimeException("Error creating table " + tableName + " ", e);
 		}
 	}
 
@@ -122,13 +120,11 @@ private void createTable() {
 	public void add(String conversationId, List<Message> messages) {
 		try {
 			List<Message> all = this.selectMessageById(conversationId);
-
 			all.addAll(messages);
-
 			this.updateMessageById(conversationId, this.objectMapper.writeValueAsString(all));
 		}
 		catch (Exception e) {
-			logger.error("Error adding messages to MySQL chat memory", e);
+			logger.error("Error adding messages to {} chat memory", jdbcType(), e);
 			throw new RuntimeException(e);
 		}
 	}
@@ -140,7 +136,7 @@ public List<Message> get(String conversationId, int lastN) {
 			all = this.selectMessageById(conversationId);
 		}
 		catch (Exception e) {
-			logger.error("Error getting messages from MySQL chat memory", e);
+			logger.error("Error getting messages from {} chat memory", jdbcType(), e);
 			throw new RuntimeException(e);
 		}
 		return all != null ? all.stream().skip(Math.max(0, all.size() - lastN)).toList() : List.of();
@@ -148,7 +144,7 @@ public List<Message> get(String conversationId, int lastN) {
 
 	@Override
 	public void clear(String conversationId) {
-		StringBuilder sql = new StringBuilder("DELETE FROM " + DEFAULT_TABLE_NAME + " WHERE conversation_id = '");
+		StringBuilder sql = new StringBuilder("DELETE FROM " + tableName + " WHERE conversation_id = '");
 		sql.append(conversationId);
 		sql.append("'");
 		try (Statement stmt = connection.createStatement()) {
@@ -162,7 +158,6 @@ public void clear(String conversationId) {
 
 	@Override
 	public void close() throws Exception {
-
 		if (connection != null) {
 			connection.close();
 		}
@@ -171,22 +166,20 @@ public void close() throws Exception {
 	public void clearOverLimit(String conversationId, int maxLimit, int deleteSize) {
 		try {
 			List<Message> all = this.selectMessageById(conversationId);
-
 			if (all.size() >= maxLimit) {
 				all = all.stream().skip(Math.max(0, deleteSize)).toList();
 				this.updateMessageById(conversationId, this.objectMapper.writeValueAsString(all));
 			}
 		}
 		catch (Exception e) {
-			logger.error("Error clearing messages from MySQL chat memory", e);
+			logger.error("Error clearing messages from {} chat memory", jdbcType(), e);
 			throw new RuntimeException(e);
 		}
 	}
 
 	public List<Message> selectMessageById(String conversationId) {
 		List<Message> totalMessage = new ArrayList<>();
-		StringBuilder sql = new StringBuilder(
-				"SELECT messages FROM " + DEFAULT_TABLE_NAME + " WHERE conversation_id = '");
+		StringBuilder sql = new StringBuilder("SELECT messages FROM " + tableName + " WHERE conversation_id = '");
 		sql.append(conversationId);
 		sql.append("'");
 		try (Statement stmt = connection.createStatement()) {
@@ -202,7 +195,7 @@ public List<Message> selectMessageById(String conversationId) {
 			}
 		}
 		catch (SQLException | JsonProcessingException e) {
-			logger.error("select message by mysql error，sql:{}", sql, e);
+			logger.error("select message by {} error，sql:{}", jdbcType(), sql, e);
 			throw new RuntimeException(e);
 		}
 		return totalMessage;
@@ -211,7 +204,6 @@ public List<Message> selectMessageById(String conversationId) {
 	public void updateMessageById(String conversationId, String messages) {
 		// Remove newlines and escape single quotes
 		messages = messages.replaceAll("[\\r\\n]", "").replace("'", "''");
-
 		String sql;
 		if (this.selectMessageById(conversationId).isEmpty()) {
 			sql = "INSERT INTO chat_memory (messages, conversation_id) VALUES (?, ?)";
@@ -219,20 +211,13 @@ public void updateMessageById(String conversationId, String messages) {
 		else {
 			sql = "UPDATE chat_memory SET messages = ? WHERE conversation_id = ?";
 		}
-
 		try (PreparedStatement stmt = this.connection.prepareStatement(sql)) {
-			if (this.selectMessageById(conversationId).isEmpty()) {
-				stmt.setString(1, messages);
-				stmt.setString(2, conversationId);
-			}
-			else {
-				stmt.setString(1, messages);
-				stmt.setString(2, conversationId);
-			}
+			stmt.setString(1, messages);
+			stmt.setString(2, conversationId);
 			stmt.executeUpdate();
 		}
 		catch (SQLException e) {
-			logger.error("update message by mysql error，sql:{}", sql, e);
+			logger.error("update message by {} error，sql:{}", sql, jdbcType(), e);
 			throw new RuntimeException(e);
 		}
 	}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemory.java
new file mode 100644
index 0000000000..83f15806b9
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * @author future0923
+ */
+public class MysqlChatMemory extends JdbcChatMemory {
+
+	private static final String JDBC_TYPE = "mysql";
+
+	public MysqlChatMemory(String username, String password, String jdbcUrl) {
+		super(username, password, jdbcUrl);
+	}
+
+	public MysqlChatMemory(String username, String password, String jdbcUrl, String tableName) {
+		super(username, password, jdbcUrl, tableName);
+	}
+
+	public MysqlChatMemory(Connection connection) {
+		super(connection);
+	}
+
+	public MysqlChatMemory(Connection connection, String tableName) {
+		super(connection, tableName);
+	}
+
+	@Override
+	protected String jdbcType() {
+		return JDBC_TYPE;
+	}
+
+	@Override
+	protected String hasTableSql(String tableName) {
+		return String.format("SHOW TABLES LIKE '%s'", tableName);
+	}
+
+	@Override
+	protected String createTableSql(String tableName) {
+		return String.format(
+				"CREATE TABLE %s( id BIGINT AUTO_INCREMENT PRIMARY KEY,conversation_id  VARCHAR(256)  NULL,messages TEXT NULL,UNIQUE (conversation_id)) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;",
+				tableName);
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemory.java
new file mode 100644
index 0000000000..eb9a21fecb
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * @author future0923
+ */
+public class OracleChatMemory extends JdbcChatMemory {
+
+	private static final String JDBC_TYPE = "oracle";
+
+	public OracleChatMemory(String username, String password, String url) {
+		super(username, password, url);
+	}
+
+	public OracleChatMemory(String username, String password, String url, String tableName) {
+		super(username, password, url, tableName);
+	}
+
+	public OracleChatMemory(Connection connection) {
+		super(connection);
+	}
+
+	public OracleChatMemory(Connection connection, String tableName) {
+		super(connection, tableName);
+	}
+
+	@Override
+	protected String jdbcType() {
+		return JDBC_TYPE;
+	}
+
+	@Override
+	protected String hasTableSql(String tableName) {
+		return String.format("SELECT table_name FROM user_tables WHERE table_name = '%s'", tableName.toUpperCase());
+	}
+
+	@Override
+	protected String createTableSql(String tableName) {
+		return String.format(
+				"CREATE TABLE %s ( id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, conversation_id VARCHAR2(256), messages CLOB, CONSTRAINT uniq_conversation_id UNIQUE (conversation_id));",
+				tableName);
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemory.java
new file mode 100644
index 0000000000..fdd7306952
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * @author future0923
+ */
+public class PostgresChatMemory extends JdbcChatMemory {
+
+	private static final String JDBC_TYPE = "postgresql";
+
+	public PostgresChatMemory(String username, String password, String url) {
+		super(username, password, url);
+	}
+
+	public PostgresChatMemory(String username, String password, String jdbcUrl, String tableName) {
+		super(username, password, jdbcUrl, tableName);
+	}
+
+	public PostgresChatMemory(Connection connection) {
+		super(connection);
+	}
+
+	public PostgresChatMemory(Connection connection, String tableName) {
+		super(connection, tableName);
+	}
+
+	@Override
+	protected String jdbcType() {
+		return JDBC_TYPE;
+	}
+
+	@Override
+	protected String hasTableSql(String tableName) {
+		return String.format(
+				"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' AND table_name LIKE '%s'",
+				tableName);
+	}
+
+	@Override
+	protected String createTableSql(String tableName) {
+		return String.format(
+				"CREATE TABLE %s ( id BIGSERIAL PRIMARY KEY, conversation_id VARCHAR(256), messages TEXT, UNIQUE (conversation_id));",
+				tableName);
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemory.java
new file mode 100644
index 0000000000..e86dea2753
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * @author future0923
+ */
+public class SQLiteChatMemory extends JdbcChatMemory {
+
+	private static final String JDBC_TYPE = "sqlite";
+
+	public SQLiteChatMemory(String username, String password, String jdbcUrl) {
+		super(username, password, jdbcUrl);
+	}
+
+	public SQLiteChatMemory(String username, String password, String jdbcUrl, String tableName) {
+		super(username, password, jdbcUrl, tableName);
+	}
+
+	public SQLiteChatMemory(Connection connection) {
+		super(connection);
+	}
+
+	public SQLiteChatMemory(Connection connection, String tableName) {
+		super(connection, tableName);
+	}
+
+	@Override
+	protected String jdbcType() {
+		return JDBC_TYPE;
+	}
+
+	@Override
+	protected String hasTableSql(String tableName) {
+		return String.format("SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE '%s'", tableName);
+	}
+
+	@Override
+	protected String createTableSql(String tableName) {
+		return String.format(
+				"CREATE TABLE IF NOT EXISTS %s ( id INTEGER PRIMARY KEY AUTOINCREMENT, conversation_id TEXT, messages TEXT, UNIQUE (conversation_id));",
+				tableName);
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemory.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemory.java
new file mode 100644
index 0000000000..71c220d4aa
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * @author future0923
+ */
+public class SqlServerChatMemory extends JdbcChatMemory {
+
+	private static final String JDBC_TYPE = "sqlserver";
+
+	public SqlServerChatMemory(String username, String password, String url) {
+		super(username, password, url);
+	}
+
+	public SqlServerChatMemory(String username, String password, String jdbcUrl, String tableName) {
+		super(username, password, jdbcUrl, tableName);
+	}
+
+	public SqlServerChatMemory(Connection connection) {
+		super(connection);
+	}
+
+	public SqlServerChatMemory(Connection connection, String tableName) {
+		super(connection, tableName);
+	}
+
+	@Override
+	protected String jdbcType() {
+		return JDBC_TYPE;
+	}
+
+	@Override
+	protected String hasTableSql(String tableName) {
+		return String.format("SELECT name FROM sys.tables WHERE name LIKE '%s';", tableName);
+	}
+
+	@Override
+	protected String createTableSql(String tableName) {
+		return String.format(
+				"CREATE TABLE %s ( id BIGINT IDENTITY(1,1) PRIMARY KEY, conversation_id NVARCHAR(256), messages NVARCHAR(MAX), CONSTRAINT uq_conversation_id UNIQUE (conversation_id));",
+				tableName);
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/serializer/MessageDeserializer.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/serializer/MessageDeserializer.java
similarity index 98%
rename from community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/serializer/MessageDeserializer.java
rename to community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/serializer/MessageDeserializer.java
index a56052cc85..4f3872e558 100644
--- a/community/memories/spring-ai-alibaba-mysql-memory/src/main/java/com/alibaba/cloud/ai/memory/mysql/serializer/MessageDeserializer.java
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/main/java/com/alibaba/cloud/ai/memory/jdbc/serializer/MessageDeserializer.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.alibaba.cloud.ai.memory.mysql.serializer;
+package com.alibaba.cloud.ai.memory.jdbc.serializer;
 
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.type.TypeReference;
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemoryTest.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemoryTest.java
new file mode 100644
index 0000000000..96ee31e171
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ *
+ */
+class MysqlChatMemoryTest {
+
+	@Test
+	public void test() {
+		MysqlChatMemory mock = mock(MysqlChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void mysql() {
+		MysqlChatMemory chatMemory = new MysqlChatMemory("root", "123456",
+				"jdbc:mysql://127.0.0.1:3306/spring_ai_alibaba_chat_memory");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.system("你是一个AI聊天小助手，给人提供情绪价值。")
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemoryTest.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemoryTest.java
new file mode 100644
index 0000000000..8bdebd8cde
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/OracleChatMemoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+import org.springframework.ai.chat.memory.ChatMemory;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ *
+ */
+class OracleChatMemoryTest {
+
+	@Test
+	public void test() {
+		OracleChatMemory mock = mock(OracleChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void oracle() {
+		ChatMemory chatMemory = new OracleChatMemory("system", "123456", "jdbc:oracle:thin:@localhost:1521/XEPDB1");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemoryTest.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemoryTest.java
new file mode 100644
index 0000000000..a6e91865d5
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/PostgresChatMemoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+import org.springframework.ai.chat.memory.ChatMemory;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ *
+ */
+class PostgresChatMemoryTest {
+
+	@Test
+	public void test() {
+		PostgresChatMemory mock = mock(PostgresChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void postgresql() {
+		ChatMemory chatMemory = new PostgresChatMemory("root", "123456",
+				"jdbc:postgresql://127.0.0.1:5432/spring_ai_alibaba_chat_memory");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemoryTest.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemoryTest.java
new file mode 100644
index 0000000000..2e7892c0ef
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SQLiteChatMemoryTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ */
+public class SQLiteChatMemoryTest {
+
+	@Test
+	public void test() {
+		SQLiteChatMemory mock = mock(SQLiteChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void sqlite() {
+		SQLiteChatMemory chatMemory = new SQLiteChatMemory(null, null, "jdbc:sqlite:spring_ai_alibaba_chat_memory.db");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.system("你是一个AI聊天小助手，给人提供情绪价值。")
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
diff --git a/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemoryTest.java b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemoryTest.java
new file mode 100644
index 0000000000..733694a71f
--- /dev/null
+++ b/community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/SqlServerChatMemoryTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+import org.springframework.ai.chat.memory.ChatMemory;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ *
+ */
+class SqlServerChatMemoryTest {
+
+	@Test
+	public void test() {
+		SqlServerChatMemory mock = mock(SqlServerChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void sqlServer() {
+		ChatMemory chatMemory = new SqlServerChatMemory("sa", "qWeR124563",
+				"jdbc:sqlserver://localhost:1433;database=spring_ai_alibaba_chat_memory;encrypt=true;trustServerCertificate=true");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
diff --git a/pom.xml b/pom.xml
index a1683108fb..15feb0be99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -96,7 +96,7 @@
         <module>community/vector-stores/spring-ai-alibaba-starter-opensearch-store</module>
 
         <module>community/memories/spring-ai-alibaba-redis-memory</module>
-        <module>community/memories/spring-ai-alibaba-mysql-memory</module>
+        <module>community/memories/spring-ai-alibaba-jdbc-memory</module>
 
         <module>community/openmanus</module>
 


Reviews:
user: login: yuluo-yx
body: LGTM, tks for your contribution.
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-29T04:18:05Z
user: login: yuluo-yx
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-31T05:12:49Z
user: login: yuluo-yx
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-31T05:13:55Z
user: login: future0923
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T05:18:26Z
user: login: yuluo-yx
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-31T07:58:24Z
user: login: yuluo-yx
body: LGTM, tks for your contribution
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-31T07:59:08Z

Review comments:
diff_hunk: @@ -55,9 +55,34 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.32</version>
-            <optional>true</optional>
+            <scope>test</scope>
path: community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
user: login: yuluo-yx
body: 这里的 <optional>true</optional> 应该是需要的？
顺便检查下同类问题
created_at: 2025-03-31T05:12:49Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,61 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.memory.jdbc;
+
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * @author future0923
+ *
+ */
+class MysqlChatMemoryTest {
+
+	@Test
+	public void test() {
+		MysqlChatMemory mock = mock(MysqlChatMemory.class);
+		Assertions.assertNotNull(mock);
+	}
+
+	// @Test
+	public void mysql() {
+		MysqlChatMemory chatMemory = new MysqlChatMemory("root", "123456",
+				"jdbc:mysql://127.0.0.1:3306/spring_ai_alibaba_chat_memory");
+		String apiKey = System.getenv().getOrDefault("AI_DASHSCOPE_API_KEY", "test-api-key");
+		ChatClient chatClient = ChatClient.create(new DashScopeChatModel(new DashScopeApi(apiKey)));
+		String content1 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.system("你是一个AI聊天小助手，给人提供情绪价值。")
+			.user("我是张三😄")
+			.call()
+			.content();
+		System.out.println(content1);
+		String content2 = chatClient.prompt()
+			.advisors(new MessageChatMemoryAdvisor(chatMemory))
+			.user("我是谁")
+			.call()
+			.content();
+		System.out.println(content2);
+		Assertions.assertTrue(content2.contains("张三"));
+	}
+
+}
path: community/memories/spring-ai-alibaba-jdbc-memory/src/test/java/com/alibaba/cloud/ai/memory/jdbc/MysqlChatMemoryTest.java
user: login: yuluo-yx
body: 最后加一个空行 不然会出现下面的标志，其他测试文件也有此问题，一起修复一下

![image](https://github.com/user-attachments/assets/32856a03-4316-40ab-b5f3-af72b383421c)

created_at: 2025-03-31T05:13:55Z
author_association: COLLABORATOR
diff_hunk: @@ -55,9 +55,34 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.32</version>
-            <optional>true</optional>
+            <scope>test</scope>
path: community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
user: login: future0923
body: 我这里的作用只有在test中生效，不会打包到jar中，项目使用的之后由外部程序指定jdbc驱动，避免与应用驱动不同版本的jar冲突
created_at: 2025-03-31T05:18:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,9 +55,34 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.32</version>
-            <optional>true</optional>
+            <scope>test</scope>
path: community/memories/spring-ai-alibaba-jdbc-memory/pom.xml
user: login: yuluo-yx
body: got

created_at: 2025-03-31T07:58:24Z
author_association: COLLABORATOR

PR comments:
user: login: future0923
created_at: 2025-03-27T05:50:41Z
body: @yuluo-yx 有合并的打算吗
author_association: CONTRIBUTOR
user: login: yuluo-yx
created_at: 2025-03-29T03:58:10Z
body: > @yuluo-yx 有合并的打算吗

我来本地验证下，有的，可以先修一下 ci

author_association: COLLABORATOR
user: login: yuluo-yx
created_at: 2025-03-29T04:05:40Z
body: ![image](https://github.com/user-attachments/assets/9ebdac23-ab54-49bf-813c-2501cd58cbe6)
这里的逻辑似乎有些重复？
author_association: COLLABORATOR
user: login: yuluo-yx
created_at: 2025-03-29T04:15:57Z
body: ![image](https://github.com/user-attachments/assets/e7fcc8a5-bd7a-4783-8694-f128a9031e35)

这里的测试可以 new 一些 Message 存进去在操作取出来看看呢？
直接调用模型这个可以加一个条件，当前环境存在 apikey 的环境变量时执行
author_association: COLLABORATOR
user: login: yuluo-yx
created_at: 2025-03-29T04:17:41Z
body: 我本地测试通过了，劳烦有空看看 comments，另外可以考虑添加一个 sqlite 的实现吗？😆
author_association: COLLABORATOR
user: login: future0923
created_at: 2025-03-31T01:11:44Z
body: @yuluo-yx 已修改并增加sqlite实现
author_association: CONTRIBUTOR
user: login: future0923
created_at: 2025-03-31T08:01:25Z
body: > LGTM, tks for your contribution

Thank you for your guidance.
author_association: CONTRIBUTOR