这篇文章最初发表于2017年,当时宣布CockroachDB对Hibernate的支持处于测试阶段。今天,我们很高兴地宣布一个重大消息:CockroachDB对Hibernate的方言是 正式推出!🥳
Hibernate现在为CockroachDB提供了一流的支持。 你可以在这篇博文中了解到更多关于方言的信息,以及我们的发展历程。
我们正在努力使CockroachDB具有可扩展性和健壮性,而且使用简单。我们的方法之一是增加对现有对象关系映射器(ORM)的支持,这使得开发与CockroachDB交互的应用变得快速而简单。为了确定首先支持哪些ORM,我们询问了客户和社区Slack的用户,进行了开发者调查,并进行了其他研究。Hibernate出现的频率最高,这可能是因为Java有庞大的开发者社区,而Hibernate在这个世界上很受欢迎。这篇文章主要是关于我们的Hibernate兼容性,但我们最初做的一些SQL兼容性工作也有助于为其他ORM的兼容性铺平道路。
第一阶段(2017年):引导ORM支持
当我们刚开始做这个项目的时候,我们有一个雄心勃勃的目标,就是让五个ORM的支持落地。Hibernate在我们的列表中名列前茅,并且有两条潜在的前进道路。
- 实现Hibernate运行所需的SQL功能。这是可行的,因为Cockroach支持Postgres wire协议和它的大部分语法。因为很多ORM都支持PostgreSQL,这个方案涉及到添加ORM需要的但CockroachDB缺乏的SQL功能。
- 为每个ORM创建一个CockroachDB适配器。虽然SQL有一套标准,但是每个常用的数据库都与标准有很大的偏差,并且/或者有专有的SQL功能。这就要求ORM为它连接的每个数据库都有一个适配器。因此,选项2是创建一个扩展,使用CockroachDB已经支持的功能来执行ORM的特定任务。
在2017年,我们想快速发布Hibernate支持。另外,经过一些调查,我们发现其他ORM需要的SQL功能有很大的重叠性。所以,我们一开始就选择了1号方案。当时,我们决定,从长远来看,通过适合他们预期的接口来利用预建适配器,比为每个单独的ORM或工具创建一个自定义适配器要省力。
那么,这些功能是什么?ORM发出两种基本类型的查询。第一组包括CRUD(CREATE、READ、UPDATE、DELETE)查询。考虑到我们现有的这些SQL语句的实现,这是相对简单的。存在一些小问题,如不兼容的日期和时间格式,但很容易解决。
绝大多数的工作涉及支持模式同步。
模式同步
ORM的重要职责之一是确保数据库中的表、列和索引与代码所定义的模型一致。例如,考虑这个Hibernate ORM模型。
private static final SessionFactory sessionFactory =
new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Account.class)
.buildSessionFactory();
@Entity
@Table(name="accounts")
public static class Account {
@Id
@Column(name="id")
public long id;
@Column(name="balance")
public long balance;
}
在启动过程中,Hibernate执行了以下动作。
- 创建
accounts表,如果它不存在的话。由于函数调用addAnnotatedClass(Account.class),Hibernate "知道 "这个表。 - 如果
id列不存在,则将其添加到accounts中,并使其成为accounts的主键。 - 如果
balance列不存在,就把它添加到accounts。
Hibernate知道它希望accounts* 表的结构是基于@Table,@Column, 和@Id 注解的。现在,它需要知道accounts 是否已经存在,如果存在,它的当前模式是什么。
模式同步:pg_catalog vs. information_schema
模式同步使数据库模式与模型(例如,在上面的例子中,Account )一致。要做到这一点,Hibernate必须通过数据库提供的机制来检索数据库模式。
information_schema是SQL定义的一组标准视图,用来暴露数据库的结构,供客户反省。不幸的是,我们测试的ORM在连接到PostgreSQL时并没有使用这个。相反,他们使用PostgreSQL特有的pg_catalog模式中的关系。因此,我们已经实现了Hibernate所需的pg_catalog视图的子集。这使得Hibernate应用可以连接到CockroachDB,就好像它是PostgreSQL一样。
这个过程相对简单,但涉及到对SQL执行、类型系统和其他各种代码的重大改变。它也锻炼了我们的SQL引擎中以前未被使用的部分。例如,考虑一下Hibernate在运行一个示例应用程序时发出的这个查询。
SELECT NULL::text AS PKTABLE_CAT,
pkn.nspname AS PKTABLE_SCHEM,
[15 lines omitted]
CASE con.confdeltype
WHEN 'c' THEN 0
WHEN 'n' THEN 2
WHEN 'd' THEN 4
WHEN 'r' THEN 1
WHEN 'a' THEN 3
ELSE NULL
END AS DELETE_RULE,
[8 lines omitted]
FROM pg_catalog.pg_namespace pkn,
pg_catalog.pg_class pkc,
pg_catalog.pg_attribute pka,
pg_catalog.pg_namespace fkn,
pg_catalog.pg_class fkc,
pg_catalog.pg_attribute fka,
pg_catalog.pg_constraint con,
pg_catalog.generate_series(1, 32) pos(n),
pg_catalog.pg_depend dep,
pg_catalog.pg_class pkic
WHERE pkn.oid = pkc.relnamespace
AND pkc.oid = pka.attrelid
AND pka.attnum = con.confkey[pos.n]
AND con.confrelid = pkc.oid
AND fkn.oid = fkc.relnamespace
AND fkc.oid = fka.attrelid
AND fka.attnum = con.conkey[pos.n]
AND con.conrelid = fkc.oid
AND con.contype = 'f'
AND con.oid = dep.objid
AND pkic.oid = dep.refobjid
AND pkic.relkind = 'i'
AND dep.classid = 'pg_constraint'::regclass::oid
AND dep.refclassid = 'pg_class'::regclass::oid
AND fkn.nspname = 'public'
AND fkc.relname = 'orders'
ORDER BY pkn.nspname,
pkc.relname,
con.conname,
pos.n
如果你看了这个查询几分钟,仍然不明白它要做什么,这也是合理的。这个查询使用pg_catalog中的关系,检索了公共模式中订单表的外键。
Hibernate使用pg_catalog而不是information_schema并不是唯一的做法。其他几个ORM,包括我们在2017年一轮ORM兼容性中优先考虑的其他四个ORM也使用pg_catalog。幸运的是,我们也确认这些ORM大多使用了与Hibernate相同的pg_catalog的部分。
第二阶段(2020年):构建一个Cockroach/Hibernate方言
自从最初对Hibernate的测试支持以来,我们已经对CockroachDB的Postgres兼容性做了很大的改进。即便如此,我们还是想确保Hibernate对CockroachDB有一流的支持,并且我们可以解决一些不太常用的Postgres兼容性问题,这些问题在我们的路线图中没有出现。
这就是为什么,在改进SQL兼容性的同时,我们决定创建我们自己的Hibernate方言。CockroachDB Hibernate方言允许我们通过引入CockroachDB特有的语义来为开发者提供更好的体验。与Postgres方言相比,CockroachDB方言可以自动处理缺失的BLOB存储和Identity列支持。
我们与Hibernate的维护者合作,从v5.4.19开始,CockroachDB方言成为Hibernate官方版本的一部分。今后,我们的团队还将有机会通过CockroachDB的特定功能进一步扩展CockroachDB方言。由于方言在Hibernate的主版本中,它将被永久地维护,而与Hibernate主版本的整合有助于我们提供更好的持续支持。感谢Hibernate团队在帮助我们实现合并方面所做的努力。
ORM兼容性的后续步骤
除了Hibernate,我们还在CockroachDB中实现了对ActiveRecord(Ruby)、SQLAlchemy(Python)、GORM(Go)和TypeORM(Typescript)的支持。CockroachDB支持的ORM和其他第三方数据库工具的完整列表可以在这里找到。想使用其他ORM吗?我们可能已经在做了。你可以先在我们的问题追踪器中搜索ORM。如果你找到了相关的问题,请用GitHub反应来表达你的支持。
我们非常欢迎添加ORM相关功能的拉动请求。CockroachDB核心是开源的,并从社区的拉动请求中获益良多。如果这不可行,请提交一个包括测试脚本或使用ORM的单元测试的问题。如果我们不需要首先投入精力去了解它和它的不兼容性,那么优先支持就会更容易。
如果你想用Hibernate ORM和CockroachDB构建一个应用程序,请今天就开始使用 构建一个 构建一个使用Hibernate的Java应用.