Apache Ignite 与 Spring Data 集成
这份文档是关于 Apache Ignite 与 Spring Data 集成 的官方指南。它展示了如何像使用 Spring Data JPA
操作数据库一样,用统一的、声明式的接口来操作 Ignite 缓存数据。
我们来一步步通俗易懂地解析这段内容,帮助你彻底理解:
💡 核心思想:让开发者可以用“写接口 + 方法命名”的方式,自动实现对 Ignite 缓存的增删改查,而无需手动写 SQL 或缓存 API。
🌟 一、为什么要用 Spring Data + Ignite?
在没有 Spring Data 之前,你要操作 Ignite 缓存,得这样写代码:
IgniteCache<Long, Person> cache = ignite.cache("PersonCache");
cache.put(1L, new Person(...));
List<Long> ids = cache.query(new SqlQuery<>("Person", "orgId > ?")).getAll();
这很繁琐,而且业务逻辑和缓存 API 耦合严重。
而用了 Spring Data 后,你可以像操作数据库一样:
personRepository.save(1L, person);
List<Person> list = personRepository.findByFirstName("John");
✅ 好处:
- 接口驱动,代码简洁
- 方法名自动生成 SQL 查询
- 统一数据访问层风格(和 JPA、MongoDB 等保持一致)
- 易于测试和替换底层存储
📦 二、添加依赖(Maven)
<dependency><groupId>org.apache.ignite</groupId><artifactId>ignite-spring-data_2.2</artifactId><version>{ignite.version}</version>
</dependency>
📌 注意:
ignite-spring-data_2.2
是针对 Spring Data 2.2+ 的版本。- 如果你用的是老版本 Spring Data(如 2.0),要用
ignite-spring-data_2.0
或ignite-spring-data
。
✅ 引入后,Ignite 就能支持
CrudRepository
风格的编程模型了。
🧱 三、定义自己的 Repository 接口
1. 创建实体类 Person
public class Person {@QuerySqlFieldprivate Long id;@QuerySqlFieldprivate String firstName;@QuerySqlFieldprivate String lastName;// getter/setter...
}
⚠️ 注意:要用
@QuerySqlField
注解标记可以用于 SQL 查询的字段。
2. 创建 Repository 接口
@RepositoryConfig(cacheName = "PersonCache")
public interface PersonRepository extends IgniteRepository<Person, Long> {List<Person> findByFirstName(String name);Cache.Entry<Long, Person> findTopByLastNameLike(String name);@Query("SELECT id FROM Person WHERE orgId > ?")List<Long> selectId(long orgId, Pageable pageable);
}
我们逐行解释:
✅ @RepositoryConfig(cacheName = "PersonCache")
- 告诉 Spring Data:这个接口对应的是哪个 Ignite 缓存(Cache)。
- 所有操作都会作用于名为
"PersonCache"
的分布式缓存。
✅ extends IgniteRepository<Person, Long>
Person
:缓存中存储的值类型(value)。Long
:缓存的键类型(key)。- 这个接口继承了
CrudRepository
的基本操作(如findById
,deleteById
等),但也做了适配。
✅ 方法一:findByFirstName(String name)
- 方法名遵循 Spring Data 命名规范。
- 框架会自动解析为 SQL 查询:
SELECT * FROM Person WHERE firstName = ?
- 返回
List<Person>
,即使只有一条也返回列表。
✅ 方法二:findTopByLastNameLike(String name)
Top
表示只取第一条。Like
表示模糊匹配(支持%
通配符)。- 自动转为:
SELECT * FROM Person WHERE lastName LIKE ? LIMIT 1
- 返回
Cache.Entry<Long, Person>
:包含 key 和 value。
✅ 方法三:@Query("SELECT id FROM Person WHERE orgId > ?")
- 使用
@Query
注解写自定义 SQL 查询。 - 支持分页参数
Pageable
。 - 只查
id
字段,性能更高。
⚠️ 四、哪些 CRUD 操作不支持?为什么?
Spring Data 的 CrudRepository
有这些方法:
save(S entity) // ❌ 不支持
save(Iterable<S> entities) // ❌ 不支持
delete(T entity) // ❌ 不支持
delete(Iterable<? extends T> entities) // ❌ 不支持
❓ 为什么?
因为 Ignite 是 Key-Value 存储,不像数据库有自动生成主键机制。
比如:
personRepository.save(new Person("John")); // 没给 key,Ignite 不知道存到哪个 key 下!
✅ 替代方案(必须显式提供 key):
// ✅ 正确方式:必须带 key
save(ID key, S entity)
save(Map<ID, S> entities)
deleteAll(Iterable<ID> ids)
例如:
repo.save(1L, new Person(1L, "John"));
repo.save(personsMap); // Map<Long, Person>
🔔 所以:在 Ignite 中使用 Spring Data,必须自己管理 key。
⚙️ 五、配置类:启用 Ignite Repositories
@Configuration
@EnableIgniteRepositories
public class SpringAppCfg {@Beanpublic Ignite igniteInstance() {IgniteConfiguration cfg = new IgniteConfiguration();cfg.setIgniteInstanceName("springDataNode");cfg.setPeerClassLoadingEnabled(true);CacheConfiguration ccfg = new CacheConfiguration("PersonCache");ccfg.setIndexedTypes(Long.class, Person.class); // 启用 SQL 查询支持cfg.setCacheConfiguration(ccfg);return Ignition.start(cfg);}
}
关键点:
✅ @EnableIgniteRepositories
- 启用 Ignite 的 Spring Data 支持。
- 扫描所有
@RepositoryConfig
标记的接口,自动生成实现类。
✅ @Bean public Ignite igniteInstance()
- 必须提供一个
Ignite
实例 Bean。 - 这个节点将用于连接集群,并被所有
IgniteRepository
使用。
✅ ccfg.setIndexedTypes(Long.class, Person.class)
- 启用 SQL 查询功能。
- 告诉 Ignite:
Person
类可以通过 SQL 查询(如SELECT * FROM Person
)。
🚀 六、使用 Repository(示例)
ctx = new AnnotationConfigApplicationContext();
ctx.register(SpringAppCfg.class);
ctx.refresh();// 获取 Repository 实例
PersonRepository repo = ctx.getBean(PersonRepository.class);// 插入数据(必须带 key)
TreeMap<Long, Person> persons = new TreeMap<>();
persons.put(1L, new Person(1L, "John", "Smith"));
repo.save(persons);// 查询数据
List<Person> johns = repo.findByFirstName("John");
for (Person p : johns) {System.out.println(">>> " + p);
}// 模糊查询
Cache.Entry<Long, Person> top = repo.findTopByLastNameLike("Smi%");
System.out.println(">>> Top: " + top.getValue());
🧠 七、核心机制总结(它是怎么工作的?)
步骤 | 说明 |
---|---|
1️⃣ | 你定义一个接口,继承 IgniteRepository<T, ID> |
2️⃣ | 加上 @RepositoryConfig(cacheName="xxx") 绑定缓存 |
3️⃣ | 写方法名如 findByXxxAndYyy(...) |
4️⃣ | Spring Data 在启动时动态生成实现类 |
5️⃣ | 根据方法名自动翻译成 Ignite SQL 查询 |
6️⃣ | 调用时自动执行 SQL 并返回结果 |
🔍 类似于 MyBatis 的 Mapper 接口,但这里是基于方法命名规则自动生成 SQL。
🎯 八、适用场景 & 最佳实践
场景 | 是否推荐 |
---|---|
微服务中访问 Ignite 缓存 | ✅ 推荐,风格统一 |
需要频繁 SQL 查询缓存数据 | ✅ 推荐 |
只做简单 key-value 存取 | ❌ 不必要,直接用 IgniteCache 更简单 |
已有 Spring Data 架构(如 JPA) | ✅ 容易统一数据访问层 |
✅ 最佳实践建议:
- 实体类加
@QuerySqlField
:只有标记的字段才能用于 SQL 查询。 - 合理使用
@Query
:复杂查询用注解写 SQL。 - 注意 key 管理:
save(entity)
不支持,必须用save(key, entity)
。 - 开启对等类加载:
setPeerClassLoadingEnabled(true)
,避免节点间类不一致。 - 缓存名唯一:确保
@RepositoryConfig(cacheName)
对应的缓存在集群中已创建或配置。
🧩 九、一句话总结
Apache Ignite 通过实现 Spring Data 的
CrudRepository
接口,让你可以用“接口 + 方法命名”的方式,像操作数据库一样操作分布式缓存,自动将方法名转换为 SQL 查询,极大提升了开发效率和代码可读性,尤其适合已有 Spring Data 技术栈的项目。
✅ 十、对比:Ignite + Spring Boot vs Ignite + Spring Data
特性 | Spring Boot Autoconfigure | Spring Data |
---|---|---|
目的 | 自动启动 Ignite 节点或 Thin Client | 提供声明式数据访问接口 |
配置方式 | application.yml + @Bean | @EnableIgniteRepositories + @RepositoryConfig |
编程模型 | 手动调用 IgniteCache API | 声明式接口(类似 JPA) |
是否生成 SQL | 否(需手动写) | ✅ 是(方法名自动转 SQL) |
适合场景 | 基础集成、缓存管理 | 复杂查询、统一数据访问层 |
✅ 实际项目中,两者可以结合使用:
- 用 Spring Boot 自动配置 Ignite 节点
- 用 Spring Data 定义 Repository 接口进行数据操作
如果你需要,我可以为你生成一个完整的示例项目结构,包含:
pom.xml
application.yml
Person.java
PersonRepository.java
AppConfig.java
Service
层调用示例
是否需要?😊