You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Corda中创建类Spring风格服务存储非Vault节点数据库数据

我来帮你搞定在Corda里实现Spring风格Repository服务的事儿,一步步来,保证清晰:

核心思路:用@CordaService封装节点内数据访问逻辑

首先明确:@CordaService是节点级的单例服务,运行在Corda节点内部,不是客户端或Flow代码里。它可以直接访问节点的内置数据库(默认H2,可配置为PostgreSQL等),完美满足你避开Vault存储中间数据的需求。

1. 定义数据库实体类(对应数据库表)

先写你的Order实体,要符合JPA规范(Corda底层用Hibernate管理数据库),同时加上Corda的序列化注解保证RPC传输可用:

import net.corda.core.serialization.CordaSerializable;
import javax.persistence.*;
import java.time.LocalDateTime;

@CordaSerializable
@Entity
@Table(name = "ORDERS")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String orderNumber;
    private Double amount;
    private LocalDateTime createdAt;

    // JPA必需的无参构造
    public Order() {}

    // 业务构造方法
    public Order(String orderNumber, Double amount) {
        this.orderNumber = orderNumber;
        this.amount = amount;
        this.createdAt = LocalDateTime.now();
    }

    // 自行补充getter/setter方法
}

2. 实现类Spring风格的Repository

Corda支持直接用EntityManager操作数据库,我们可以封装成类似Spring Data的Repository结构,避免重复代码:

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

public class OrderRepository {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public Order save(Order order) {
        if (order.getId() == null) {
            entityManager.persist(order);
            return order;
        } else {
            return entityManager.merge(order);
        }
    }

    public Order findById(Long id) {
        return entityManager.find(Order.class, id);
    }

    public Order findByOrderNumber(String orderNumber) {
        return entityManager.createQuery(
                "SELECT o FROM Order o WHERE o.orderNumber = :orderNumber", Order.class)
                .setParameter("orderNumber", orderNumber)
                .getSingleResult();
    }
}

3. 用@CordaService封装业务服务

把Repository注入到CordaService中,作为节点内的核心服务,确保它是单例且能被RPC调用:

import net.corda.core.node.CordaService;
import net.corda.core.serialization.SingletonSerializeAsToken;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;

@CordaService
public class OrderService extends SingletonSerializeAsToken {
    @PersistenceContext
    private EntityManager entityManager;
    private final OrderRepository orderRepository;

    public OrderService() {
        this.orderRepository = new OrderRepository();
        // 手动注入EntityManager到Repository(Corda的注解仅对CordaService生效)
        // 这里用反射或者直接把Repository逻辑写在Service里也可以
        try {
            java.lang.reflect.Field field = OrderRepository.class.getDeclaredField("entityManager");
            field.setAccessible(true);
            field.set(orderRepository, entityManager);
        } catch (Exception e) {
            throw new RuntimeException("Failed to inject EntityManager into OrderRepository", e);
        }
    }

    // 暴露给RPC调用的方法
    public Order saveOrder(Order order) {
        return orderRepository.save(order);
    }

    public Order getOrderById(Long id) {
        return orderRepository.findById(id);
    }
}

注意:@CordaService必须继承SingletonSerializeAsToken,保证节点重启后服务状态的一致性。

4. 客户端REST Controller调用CordaService

你的REST Controller是运行在客户端应用里的,通过CordaRPCOps连接节点并调用服务方法:

import net.corda.core.messaging.CordaRPCOps;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/corda-api")
public class OrderController {
    private final CordaRPCOps proxy;

    // 构造注入CordaRPCOps(可通过Spring配置从节点RPC地址获取)
    public OrderController(CordaRPCOps proxy) {
        this.proxy = proxy;
    }

    @PostMapping("/orders")
    public Order addOrder(@RequestBody Order order) {
        // 通过RPC获取节点上的OrderService实例
        OrderService orderService = proxy.getAppService(OrderService.class);
        return orderService.saveOrder(order);
    }

    @GetMapping("/orders/{id}")
    public Order getOrder(@PathVariable Long id) {
        OrderService orderService = proxy.getAppService(OrderService.class);
        return orderService.getOrderById(id);
    }
}

关键注意事项

  • 代码位置:@CordaService、实体类、Repository必须放在cordapp模块(节点的业务代码模块)里,客户端代码只负责通过RPC调用。
  • 序列化:所有RPC传输的对象必须加@CordaSerializable注解,否则会序列化失败。
  • 事务管理:数据库操作必须加@Transactional注解,Corda会自动处理事务提交/回滚。
  • 数据库配置:节点的数据库在node.conf中配置,Corda会自动扫描@Entity注解的类生成表结构,无需额外配置Hibernate文件。

内容的提问来源于stack exchange,提问作者elmodeer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:22:00