Apache Ignite 与 Spring Data 集成

发布于:2025-08-01 ⋅ 阅读:(19) ⋅ 点赞:(0)

这份文档是关于 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.0ignite-spring-data

✅ 引入后,Ignite 就能支持 CrudRepository 风格的编程模型了。


🧱 三、定义自己的 Repository 接口

1. 创建实体类 Person

public class Person {
    @QuerySqlField
    private Long id;

    @QuerySqlField
    private String firstName;

    @QuerySqlField
    private 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 {

    @Bean
    public 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) ✅ 容易统一数据访问层

✅ 最佳实践建议:

  1. 实体类加 @QuerySqlField:只有标记的字段才能用于 SQL 查询。
  2. 合理使用 @Query:复杂查询用注解写 SQL。
  3. 注意 key 管理save(entity) 不支持,必须用 save(key, entity)
  4. 开启对等类加载setPeerClassLoadingEnabled(true),避免节点间类不一致。
  5. 缓存名唯一:确保 @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 层调用示例

是否需要?😊


网站公告

今日签到

点亮在社区的每一天
去签到