2. 什么是 Fauna?
Fauna 是一个多协议、多模型、多租户的分布式事务型数据库即服务(DBaaS)。听起来有点复杂?我们拆开看。
2.1. 数据库即服务(DBaaS)
简单粗暴地说,数据库即服务就是云厂商帮你托管数据库。你不用操心服务器维护、备份这些破事,只需要专注于业务逻辑——比如设计集合、索引、查询等。这样既保留了数据库的强大功能,又省去了运维的麻烦。
2.2. 分布式事务型数据库
分布式意味着数据库跑在多台服务器上。这带来两个好处:性能更高,容错性更强。一台服务器挂了,整个数据库照样跑。
事务型则保证数据操作的可靠性。事务内的操作要么全部成功,要么全部失败,不会出现数据半成品状态。
更关键的是,Fauna 提供了隔离级别,确保跨多个分布式节点的事务执行结果永远正确。这对分布式数据库至关重要——否则不同节点可能产生不同结果,导致数据不一致。
举个例子,两个事务操作同一条记录:
- 把值设为 "15"
- 值加 "3"
按顺序执行结果是 "18",反过来执行结果是 "15"。如果系统不同节点执行顺序不一致,数据就乱套了。
2.3. 多模型数据库
多模型数据库允许用不同方式存储各类数据,而且都在同一个数据库引擎里,用同一种连接访问。
Fauna 底层是文档数据库,每条记录都是 JSON 格式的结构化文档。这让它能:
- 当键值存储用(文档只有一个
value
字段) - 当表存储用(文档有多个扁平字段)
- 存储复杂结构(嵌套字段、数组等)
// 键值文档
{
"value": "Baeldung"
}
// 表格式文档
{
"name": "Baeldung",
"url": "https://www.baeldung.com/"
}
// 结构化文档
{
"name": "Baeldung",
"sites": [
{
"id": "cs",
"name": "Computer Science",
"url": "https://www.baeldung.com/cs"
},
{
"id": "linux",
"name": "Linux",
"url": "https://www.baeldung.com/linux"
},
{
"id": "scala",
"name": "Scala",
"url": "https://www.baeldung.com/scala"
},
{
"id": "kotlin",
"name": "Kotlin",
"url": "https://www.baeldung.com/kotlin"
},
]
}
此外,Fauna 还支持:
- 关系数据库特性:创建索引优化查询,跨集合约束保证数据一致性
- 图查询:构建跨集合的复杂数据结构,像操作单个图一样访问
- 时间模型:随时回溯数据库历史状态,查看记录变更历史或直接访问历史版本数据
2.4. 多租户数据库
多租户数据库支持多个用户共享同一个数据库服务。云托管数据库常见这种设计,一台服务器能服务多个客户。
但 Fauna 的实现有点特别:它用租户区分同一客户的不同数据子集。核心特性是支持数据库嵌套——可以创建子数据库,并为子数据库生成访问凭证。
关键点:
- 只能访问当前连接数据库的子数据库(只读)
- 不能访问父级或同级数据库
这种设计特别适合微服务架构:在父数据库下为每个服务创建子数据库,管理员可以跨所有子数据库查询(比如做数据分析时特别方便)。
2.5. 多协议数据库
提供多种方式访问同一份数据。
标准方式是使用 Fauna 查询语言(FQL)通过官方驱动访问,能发挥数据库全部能力。
另外还提供 GraphQL 接口:
- 优势:无需专用驱动,任何语言都能用 HTTP 客户端访问
- 限制:需要预先定义 GraphQL Schema,无法支持同一集合中不同结构的记录
3. 创建 Fauna 数据库
知道 Fauna 能做什么了,现在动手创建一个。
没有账号先注册。登录后仪表盘点击 "Create Database":
然后设置数据库名称和区域组(Region Group):
- 区域组影响费用(超出免费额度后)和外部访问的接口地址
- 可选预置示例数据,帮助快速上手
创建完成后,数据库就立即可用:
- 选了示例数据:包含预填充的集合、索引、自定义函数和 GraphQL Schema
- 没选示例数据:空数据库,等待你创建结构
最后需要创建密钥用于外部连接。在侧边栏 "Security" 标签页操作:
注意:创建后立即复制密钥!离开页面后就无法再查看(安全设计)。
4. 与 Fauna 交互
数据库就绪,开始交互。Fauna 提供三种方式:
- Fauna Shell(Web UI 内命令行)
- FQL 驱动(编程语言专用)
- GraphQL API(通用 HTTP 接口)
4.1. Fauna Shell
在 Web UI 直接执行命令,支持两种模式:
- 使用配置的密钥(效果等同于外部连接)
- 特殊管理员连接
实用场景:快速探索数据、测试应用查询(避免反复部署)。
4.2. 使用 FQL 连接
**需要官方驱动,支持 Java/Scala 等语言。Java 驱动要求 JDK 11+**。
Maven 依赖配置:
<dependency>
<groupId>com.faunadb</groupId>
<artifactId>faunadb-java</artifactId>
<version>4.2.0</version>
<scope>compile</scope>
</dependency>
创建客户端连接:
FaunaClient client = FaunaClient.builder()
.withEndpoint("https://db.us.fauna.com/") // 根据区域组调整
.withSecret("your-authorization-key-here") // 替换为你的密钥
.build();
关键特性:
- 客户端内置连接池,按需创建连接
- 应用启动时创建一次,全局复用
- 不同密钥需要不同客户端(比如访问同一父数据库下的多个子数据库)
执行查询示例:
client.query(
language.Get(language.Ref(language.Collection("customers"), 101))
).get();
4.3. 使用 GraphQL 连接
通过 GraphQL API 访问,只需 HTTP 客户端,无需专用驱动。
前置条件:必须先创建 GraphQL Schema,定义数据结构及其与 Fauna 集合/索引/函数的映射。完成后,任何 GraphQL 客户端(甚至 RestTemplate
)都能访问。
限制:只能操作数据,管理操作(如创建集合/索引)仍需 FQL 或 Web UI。
连接要点:
- 接口地址:
https://graphql.us.fauna.com/graphql
(美国区域) - 认证:在
Authorization
头部添加 Bearer Token(即密钥) - 请求方式:POST 请求,Body 包含查询/变更语句及可选变量
5. 在 Spring 中使用 Fauna
理解了基本用法,现在整合到 Spring 应用。Fauna 没有原生 Spring 驱动,我们需要配置标准 Java 驱动为 Spring Bean。
5.1. 基础配置
先配置两个关键参数:
- 区域(
fauna.region
):用于推导 FQL 和 GraphQL 接口地址 - 密钥(
fauna.secret
):数据库访问凭证
在 application.properties
添加:
fauna.region=us
fauna.secret=fnAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 替换为实际密钥
为什么只配区域不配 URL? 避免两个接口地址配置不一致的坑。
5.2. FQL 客户端配置
将 FaunaClient
注册为 Spring Bean:
@Configuration
class FaunaClientConfiguration {
@Value("https://db.${fauna.region}.fauna.com/")
private String faunaUrl;
@Value("${fauna.secret}")
private String faunaSecret;
@Bean
FaunaClient getFaunaClient() throws MalformedURLException {
return FaunaClient.builder()
.withEndpoint(faunaUrl)
.withSecret(faunaSecret)
.build();
}
}
使用方式:
- 直接注入
FaunaClient
,类似使用JdbcTemplate
- 可封装成领域对象,提供更友好的 API
5.3. GraphQL 客户端配置
GraphQL 没有标准客户端,我们用 RestTemplate
封装(WebFlux 应用可用 WebClient
):
@Component
public class GraphqlClient {
@Value("https://graphql.${fauna.region}.fauna.com/graphql")
private String faunaUrl;
@Value("${fauna.secret}")
private String faunaSecret;
private RestTemplate restTemplate = new RestTemplate();
public <T> T query(String query, Class<T> cls) {
return query(query, Collections.emptyMap(), cls);
}
public <T, V> T query(String query, V variables, Class<T> cls) {
var body = Map.of("query", query, "variables", variables);
var request = RequestEntity.post(faunaUrl)
.header("Authorization", "Bearer " + faunaSecret)
.body(body);
var response = restTemplate.exchange(request, cls);
return response.getBody();
}
}
设计亮点:
- 两个重载方法:支持带/不带变量的查询
- 泛型响应:自动反序列化到指定类型
- 隔离底层 HTTP 细节:业务代码只需关注查询逻辑
6. 总结
本文快速介绍了 Fauna 数据库的核心特性:
- 分布式事务:高可用 + 强一致性
- 多模型支持:文档/关系/图/时间模型混合使用
- 多租户设计:灵活的数据隔离方案
- 多协议访问:FQL 和 GraphQL 双模式
还展示了在 Spring 中的集成方式:通过配置类将 Fauna 客户端注入 Spring 容器,无论是 FQL 还是 GraphQL 都能丝滑使用。
下次新项目不妨试试 Fauna?这些特性说不定能解决你头疼的分布式数据问题。