每个连接的临时模式?


8

我正在尝试将单元测试从H2迁移到Postgresql。

当前,H2为我提供了一个内存中架构,这样每个连接都映射到一个唯一的架构,创建表,运行测试并删除该架构。模式的创建和销毁由H2自动处理。

单元测试可以同时运行。

在Postgresql中执行此操作的最佳方法是什么?特别,

  1. 如何为每个连接获取唯一的架构?
    • 测试框架应该生成唯一的名称还是有内置的机制来做到这一点?
  2. 如何确保在删除连接时删除架构?
    • 当单元测试被杀死时,我不想以悬挂模式结束。
  3. 哪种方法将产生最高的性能?
    • 我需要每秒创建/删除数十个模式。

更新:我在这里找到了一个相关的答案但是如果运行单元测试的进程被杀死,它无法删除架构。

Answers:


13

pg_temp 是当前会话的临时架构的别名。

如果您SET search_path TO pg_temp在运行测试之前执行了a操作,那么它应该都可以正常工作(只要没有任何内容明确引用架构)。

如果您根本不想更改脚本,则将search_path测试登录的用户设置为:

> ALTER ROLE testuser SET search_path = pg_temp;

除非明确指定,否则用户创建的所有内容都将位于pg_temp中。

这是来自的示例psql,显示了别名解析为的实际模式(针对此连接):

> SET search_path TO pg_temp;
SET
> create table test();
CREATE TABLE
> \dt test
          List of relations
  Schema   | Name | Type  |  Owner
-----------+------+-------+----------
 pg_temp_4 | test | table | postgres
(1 row)

而且,正如您期望的那样,每个并行连接的模式都不同,并且在关闭连接后消失了。

注意,这也适用于函数,尽管在调用它们时必须显式引用pg_temp模式。


但是pg_temp,单一模式对吗?因此,当我运行并发单元测试时,它们不会破坏彼此的表/数据吗?
吉利2014年

1
否。它是当前会话的临时模式的别名。我将通过示例更新答案。
hbn 2014年

请记住,如果您只是关闭和打开连接,则可能会得到相同的临时模式,但是它将被清空。同时打开2以查看分配的不同对象。除非您是超级用户,否则您将看不到另一个会话的临时模式。
hbn 2014年

当然,我看到您提出了一条评论,询问何时设置此设置。无论如何-如果您只是执行一次SET search_path,则按会话设置 用于SET LOCAL search_path设置每个子事务,或者如果需要,可以在用户级别使用设置ALTER USER mytestuser SET search_path = 'pg_temp',或者在数据库级别使用ALTER DATABASE mytestdb SET search_path = 'pg_temp'
hbn设置

出于好奇,是否有任何方法可以在没有显式模式引用的情况下使此功能起作用?还是这对于pg_temp架构是不可能的?
吉利2014年

3

可以获取当前临时模式的名称(在创建第一个临时表之后),如添加的链接中所示:

SELECT nspname
FROM   pg_namespace
WHERE  oid = pg_my_temp_schema();

但是您当前的计划仍然没有多大意义。要在当前临时模式中创建表,只需创建临时表。就这样。默认情况下,search_path定义了,以便首先显示临时表。一个从来没有需要架构资格临时表。您永远不必以任何方式直接解决当前的临时模式- 是实现细节。


同意这是一个hack,但是它比参数化创建代码以允许创建临时表要简单得多。
hbn 2014年

好一点,除了@hbn提到的,我希望单元测试和生产代码运行相同的SQL脚本。前者应在临时模式下运行,而后者则不应。
吉利2014年

@hbn,出于好奇,参数化的创建代码是什么样的?我正在使用flywaydb.org,它只执行普通的SQL文件(无变量)。我可能不想走这条路。我很好奇所涉及的。
吉利2014年

我从没用过flywaydb。从根本上讲,您可以使用某种文本模板语言(例如Python中的Jinja2)来预处理创建脚本,还可以在创建表时添加“临时”脚本。如果您明确地创建函数,就(据我所知),临时模式破解可能是不可避免的,因为您不能直接创建临时函数。
hbn 2014年

@hbn ,If you're explicitly sequences ...:我想您的最后评论中有错字。您explicitly和之间的意思是什么sequences
吉利2014年

1

您的测试是否涉及交易?DDL在PostgreSQL中是事务性的,因此,如果在一个事务中创建架构和表,然后运行测试,然后又将其回滚,则该架构实际上不会提交,并且对其他会话不可见。

您仍然需要为架构使用一个可能唯一的名称(可能包括主机名和PID),因为CREATE SCHEMA如果已经存在相同名称的架构,该名称将立即失败;如果另一个会话在其中创建了一个相同名称的架构,则将阻止该名称。未提交的交易。

如果您能够修改数据库创建脚本来执行此操作,则替代方法可能只是使用临时表。


不错的窍门,但是在我的情况下这是行不通的,因为单个测试跨多个事务运行。每种测试方法都是一个Web客户端,它会触发多个服务器端事务。例如,它创建,查询和删除用户。每个调用都是一个单独的HTTP请求,并在其自己的事务中运行。
吉利2014年

公平地说,我的方法非常有限。
hbn 2014年

@Gili:请注意,这种永不提交的技术CREATE SCHEMA是唯一可以确保在单元测试被杀死时使它们消失的技术。
DanielVérité2014年

0

我才有主意

Postgresql保证会话无法看到另一个人的临时表。我猜这意味着当您创建临时表时,它将创建一个临时模式。因此,也许我可以执行以下操作:

  1. 创建(虚拟)临时表并查找其架构。
  2. 使用此架构进行测试(创建表,运行测试)。
  3. 关闭连接后,Postgresql将删除该架构。

我不喜欢依靠实现细节,但是在这种情况下,这似乎很安全。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.