Faunadb

Faunadb和google spanner都属于云分布式数据库天然支持分片(无需做分表分库操作,一库搞定,当然价格另说),国内的也有比如TiDB  Oceanbase等

本文使用java语言,其他语言可以跳过;有想直接使用的可以参考(无法访问外网,可以搞个vpn吧!!!,有时会遇到网络问题):GitHub - fauna/faunadb-jvm: Scala and Java driver for FaunaDB v4

此文旨在想了解的小伙伴看看(免费使用30天)

本文演示使用的jdk版本为jdk21

目录

1.登录账号

2.了解一下FQL

3. 创建数据库,创建集合

4.点击搜索框中的dashbord进入到控制台然后到控制台创建集合

5. 生成数据库秘钥

6.springboot整合项目

7.实体

8.service及接口

9.属性文件配置属性

10.controller

11.启动后postman试试


1.登录账号

使用github账号或者注册一个

Welcome to Fauna docs - Fauna Documentation

2.了解一下FQL

建议按照图看下去

3. 创建数据库,创建集合

最好是跟着官网文档走

4.点击搜索框中的dashbord进入到控制台然后到控制台创建集合

(参考:使用 Spring Boot 使用 Fauna 和 Java 开始构建_rxjava_云O生-云原生

最新的不一样,使用下面语法

Collection.create({
  name: 'todos'
})

5. 生成数据库秘钥

记住不要到account哪里去申请

6.springboot整合项目

依赖

<dependency>
<groupId>com.faunadb</groupId>
<artifactId>faunadb-java</artifactId>
<version>4.4.0</version>
<scope>compile</scope>
</dependency>

实体\service\controller均参考博文:使用 Spring Boot 使用 Fauna 和 Java 开始构建_rxjava_云O生-云原生

7.实体

参考这个也行:GitHub - fauna/faunadb-jvm: Scala and Java driver for FaunaDB v4

import lombok.Data;

@Data
public abstract class Entity {
    protected  String id;
}
import java.util.List;
import java.util.Optional;

public class Page <T> {

    private List<T> data;
    private Optional<String> before;
    private Optional<String> after;


    public Page(List<T> data, Optional<String> before, Optional<String> after) {
        this.data = data;
        this.before = before;
        this.after = after;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public Optional<String> getBefore() {
        return before;
    }

    public void setBefore(Optional<String> before) {
        this.before = before;
    }

    public Optional<String> getAfter() {
        return after;
    }

    public void setAfter(Optional<String> after) {
        this.after = after;
    }
}
package com.rulecheck.entity;

import java.util.Optional;

public class PaginationOptions {
    private Optional<Integer> size;
    private Optional<String> before;
    private Optional<String> after;


    public PaginationOptions(Optional<Integer> size, Optional<String> before, Optional<String> after) {
        this.size = size;
        this.before = before;
        this.after = after;
    }

    public Optional<Integer> getSize() {
        return size;
    }

    public void setSize(Optional<Integer> size) {
        this.size = size;
    }

    public Optional<String> getBefore() {
        return before;
    }

    public void setBefore(Optional<String> before) {
        this.before = before;
    }

    public Optional<String> getAfter() {
        return after;
    }

    public void setAfter(Optional<String> after) {
        this.after = after;
    }
}


import com.faunadb.client.types.FaunaConstructor;
import com.faunadb.client.types.FaunaField;

public class TodoEntity extends Entity {

    @FaunaField
    private String title;

    @FaunaField
    private String description;

    @FaunaConstructor
    public TodoEntity(@FaunaField("id") String id,
                      @FaunaField("title") String title,
                      @FaunaField("description") String description) {
        this.id = id;
        this.title = title;
        this.description = description;

    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
package com.rulecheck.entity;

public class CreateOrUpdateTodoData {

    private String title;
    private String description;

    public CreateOrUpdateTodoData(String title, String description) {
        this.title = title;
        this.description = description;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

8.service及接口

package com.rulecheck.service;

import com.faunadb.client.FaunaClient;
import com.faunadb.client.errors.NotFoundException;
import com.faunadb.client.query.Expr;
import com.faunadb.client.query.Pagination;
import com.faunadb.client.types.Value;
import com.rulecheck.entity.Entity;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import jakarta.annotation.Resource;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.faunadb.client.query.Language.*;

import java.lang.Class;

public abstract class FaunaRepository<T extends Entity > implements Repository<T>, IdentityFactory {

    @Resource
    private FaunaClient faunaClient;

    protected final Class<T> entityType;
    protected final String collectionName;
    protected final String collectionIndexName;


    protected FaunaRepository(Class<T> entityType, String collectionName, String collectionIndexName) {
        this.entityType = entityType;
        this.collectionName = collectionName;
        this.collectionIndexName = collectionIndexName;
    }

    // This method returns a unique valid Id leveraging Fauna's NewId function.
    @Override
    public CompletableFuture<String> nextId() {

        CompletableFuture<String> result =
                faunaClient.query(
                        NewId()
                )
                        .thenApply(value -> value.to(String.class).get());

        return result;
    }

    // This method saves an entity to the database using the saveQuery method below. It also returns the result of the saved entity.
    @Override
    public CompletableFuture<T> save(T entity) {
        CompletableFuture<T> result =
                faunaClient.query(
                        saveQuery(Value(entity.getId()), Value(entity))
                )
                        .thenApply(this::toEntity);

        return result;
    }

    // This method deletes from the data an entity(document) with the specified Id. 
    @Override
    public CompletableFuture<Optional<T>> remove(String id) {
        CompletableFuture<T> result =
                faunaClient.query(
                        Select(
                                Value("data"),
                                Delete(Ref(Collection(collectionName), Value(id)))
                        )
                )
                        .thenApply(this::toEntity);

        CompletableFuture<Optional<T>> optionalResult = toOptionalResult(result);

        return optionalResult;
    }

    // This method finds an entity by its Id and returns the entity result.
    @Override
    public CompletableFuture<Optional<T>> find(String id) {
        CompletableFuture<T> result =
                faunaClient.query(
                        Select(
                                Value("data"),
                                Get(Ref(Collection(collectionName), Value(id)))
                        )
                )
                        .thenApply(this::toEntity);

        CompletableFuture<Optional<T>> optionalResult = toOptionalResult(result);

        return optionalResult;
    }

    // This method returns all entities(documents) in the database collection using the paginationOptions parameters.
    @Override
    public CompletableFuture<Page<T>> findAll(PaginationOptions po) {
        Pagination paginationQuery = Paginate(Match(Index(Value(collectionIndexName))));
        po.getSize().ifPresent(size -> paginationQuery.size(size));
        po.getAfter().ifPresent(after -> paginationQuery.after(Ref(Collection(collectionName), Value(after))));
        po.getBefore().ifPresent(before -> paginationQuery.before(Ref(Collection(collectionName), Value(before))));

        CompletableFuture<Page<T>> result =
                faunaClient.query(
                        Map(
                                paginationQuery,
                                Lambda(Value("nextRef"), Select(Value("data"), Get(Var("nextRef"))))
                        )
                ).thenApply(this::toPage);

        return result;
    }


    // This is the saveQuery expression method used by the save method to persist the database.
    protected Expr saveQuery(Expr id, Expr data) {
        Expr query =
                Select(
                        Value("data"),
                        If(
                                Exists(Ref(Collection(collectionName), id)),
                                Replace(Ref(Collection(collectionName), id), Obj("data", data)),
                                Create(Ref(Collection(collectionName), id), Obj("data", data))
                        )
                );

        return query;
    }

    // This method converts a FaunaDB Value into an Entity.
    protected T toEntity(Value value) {
        return value.to(entityType).get();
    }

    // This method returns an optionalResult from a CompletableFuture<T> result.
    protected CompletableFuture<Optional<T>> toOptionalResult(CompletableFuture<T> result) {
        CompletableFuture<Optional<T>> optionalResult =
                result.handle((v, t) -> {
                    CompletableFuture<Optional<T>> r = new CompletableFuture<>();
                    if(v != null) r.complete(Optional.of(v));
                    else if(t != null && t.getCause() instanceof NotFoundException) r.complete(Optional.empty());
                    else r.completeExceptionally(t);
                    return r;
                }).thenCompose(Function.identity());

        return optionalResult;
    }

    // This method converts a FaunaDB Value into a Page with the Entity type.
    protected Page<T> toPage(Value value) {

        Optional<String> after = value.at("after").asCollectionOf(Value.RefV.class).map(c -> c.iterator().next().getId()).getOptional();
        Optional<String> before = value.at("before").asCollectionOf(Value.RefV.class).map(c -> c.iterator().next().getId()).getOptional();

        List<T> data = value.at("data").collect(entityType).stream().collect(Collectors.toList());

        Page<T> page = new Page(data, before, after);

        return page;
    }

}

import java.util.concurrent.CompletableFuture;

public interface IdentityFactory {

    CompletableFuture<String> nextId();
}


import com.rulecheck.entity.Entity;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public interface Repository<T extends Entity> {

    // This method saves the given Entity into the Repository.
    CompletableFuture<T> save(T entity);

    // This method finds an Entity for the given Id
    CompletableFuture<Optional<T>> find(String id);

    // This method retrieves a Page of TodoEntity entities for the given PaginationOptions
    CompletableFuture<Page<T>> findAll(PaginationOptions po);

    // This method finds the Entity for the given Id and removes it. If no Entity can be found for the given Id an empty result is returned.
    CompletableFuture<Optional<T>> remove(String id);
}
import com.rulecheck.entity.TodoEntity;
import org.springframework.stereotype.Repository;
@Repository
public class TodoRepository extends FaunaRepository<TodoEntity> {

    public TodoRepository(){
        super(TodoEntity.class, "todos", "all_todos");
    }

    //-- Custom repository operations specific to the TodoEntity will go below --//

}



import com.rulecheck.entity.CreateOrUpdateTodoData;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import com.rulecheck.entity.TodoEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@Service
public class TodoService {

    @Autowired
    private TodoRepository todoRepository;

    public CompletableFuture<TodoEntity> createTodo(CreateOrUpdateTodoData data) {
        CompletableFuture<TodoEntity> result =
                todoRepository.nextId()
                        .thenApply(id -> new TodoEntity(id, data.getTitle(), data.getDescription()))
                        .thenCompose(todoEntity -> todoRepository.save(todoEntity));

        return result;
    }

    public CompletableFuture<Optional<TodoEntity>> getTodo(String id) {
        return todoRepository.find(id);
    }

    public CompletableFuture<Optional<TodoEntity>> updateTodo(String id, CreateOrUpdateTodoData data) {
        CompletableFuture<Optional<TodoEntity>> result =
                todoRepository.find(id)
                        .thenCompose(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> todoRepository.save(new TodoEntity(id, data.getTitle(), data.getDescription())).thenApply(Optional::of))
                                        .orElseGet(() -> CompletableFuture.completedFuture(Optional.empty())));

        return result;
    }

    public CompletableFuture<Optional<TodoEntity>> deleteTodo(String id) {
        return todoRepository.remove(id);
    }

    public CompletableFuture<Page<TodoEntity>> getAllTodos(PaginationOptions po) {
        return todoRepository.findAll(po);
    }
}
import com.faunadb.client.FaunaClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;


/**
 * description:
 */

@Slf4j
@SpringBootApplication
public class RuleCheckApplication {

    @Value("${fauna-db.secret}")
    private String serverKey;

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public FaunaClient faunaConfiguration() {
        log.info("serverKey:{}", serverKey);
        FaunaClient faunaClient = FaunaClient.builder()
                .withSecret(serverKey)
                .build();

        return faunaClient;
    }

    public static void main(String[] args) {
        SpringApplication.run(RuleCheckApplication.class, args);
    }

}

9.属性文件配置属性

fauna-db.secret=fnAFN6K4SxAAQWm.........  自己生成数据库秘钥,非账户秘钥或者密码

10.controller

package com.rulecheck.controller;


import com.rulecheck.entity.CreateOrUpdateTodoData;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import com.rulecheck.entity.TodoEntity;
import com.rulecheck.service.TodoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@RestController
public class TodoRestController {

    @Autowired
    private TodoService todoService;


    @PostMapping("/todos")
    public CompletableFuture<ResponseEntity> createTodo(@RequestBody CreateOrUpdateTodoData data) {

        return todoService.createTodo(data)
                .thenApply(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.CREATED));
    }


    @GetMapping("/todos/{id}")
    public CompletableFuture<ResponseEntity> getTodo(@PathVariable("id") String id) {
        CompletableFuture<ResponseEntity> result =
                todoService.getTodo(id)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND))
                        );
        return result;
    }


    @PutMapping("/todos/{id}")
    public CompletableFuture<ResponseEntity> updateTodo(@PathVariable("id") String id, @RequestBody CreateOrUpdateTodoData data) {
        CompletableFuture<ResponseEntity> result =
                todoService.updateTodo(id, data)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND)
                                        )
                        );
        return result;
    }

    @DeleteMapping(value = "/todos/{id}")
    public CompletableFuture<ResponseEntity> deletePost(@PathVariable("id")String id) {
        CompletableFuture<ResponseEntity> result =
                todoService.deleteTodo(id)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todo -> new ResponseEntity(todo, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND)
                                        )
                        );
        return result;
    }

    @GetMapping("/todos")
    public CompletableFuture<Page<TodoEntity>> getAllTodos(
            @RequestParam("size") Optional<Integer> size,
            @RequestParam("before") Optional<String> before,
            @RequestParam("after") Optional<String> after) {
        PaginationOptions po = new PaginationOptions(size, before, after);
        CompletableFuture<Page<TodoEntity>> result = todoService.getAllTodos(po);
        return result;
    }
}

11. 参考pom依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.3</version>
        <relativePath></relativePath>
    </parent>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mybatis-plus-boot-starter>3.5.3.1</mybatis-plus-boot-starter>
        <mysql-connector-java>8.0.28</mysql-connector-java>
        <commons-io>2.11.0</commons-io>
    </properties>
<!--    <packaging>jar</packaging>-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus-boot-starter}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
           <version>${mysql-connector-java}</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus-boot-starter}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.faunadb</groupId>
            <artifactId>faunadb-java</artifactId>
            <version>4.4.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

11.启动后postman试试

http://localhost:8080/todos

{

    "title":"create a job",

    "description":"this post request is todos"

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值