Skip to content

Commit 7924115

Browse files
Explicit transactions (#3)
1 parent 2f1611c commit 7924115

File tree

4 files changed

+314
-4
lines changed

4 files changed

+314
-4
lines changed

modules/ROOT/content-nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
* xref:index.adoc[]
22
* xref:authentication-authorization.adoc[]
33
* xref:query.adoc[]
4+
* xref:transactions.adoc[]
45
* xref:routing.adoc[]
56
* xref:query-counters.adoc[]
67
* xref:profile-query.adoc[]

modules/ROOT/pages/endpoints.adoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ This page contains a list of the endpoints that the Query API provides, plus poi
1616
|To submit queries. +
1717
For more information, see xref:query.adoc[].
1818

19+
|/db/<databaseName>/query/v2/tx
20+
|To open an explicit transaction. +
21+
For more information, see xref:transactions.adoc[].
22+
23+
|/db/<databaseName>/query/v2/tx/<transactionID>
24+
|To submit queries to an open transaction with ID `<transactionID>`. +
25+
A `DELETE` request results in a rollback. +
26+
For more information, see xref:transactions.adoc#_execute_queries[Run transactions -> Execute queries].
27+
28+
|/db/<databaseName>/tx/query/v2/<transactionID>/commit
29+
|To commit an open transaction with ID `<transactionID>`. +
30+
For more information, see xref:transactions.adoc#_commit_a_transaction[Run transactions -> Commit a transaction].
31+
1932
|===
2033

2134

modules/ROOT/pages/query.adoc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ http://<host>:<port>/db/<databaseName>/query/v2
1212
1313
The server wraps the submitted Cypher query in a (implicit) <<transaction>> for you.
1414
This means that in case any part of the query fails, the database will be reverted back to its status before any part of the query was executed.
15-
16-
It's currently not possible to control the lifecycle of transactions through the Query API.
17-
If you need that flexibility, checkout the link:https://neo4j.com/docs/http-api/current[HTTP API] and link:https://neo4j.com/docs/create-applications/[language libraries].
15+
To run an explicit transaction, see xref:transactions.adoc[].
1816

1917
[TIP]
2018
Each request must include an `Authorization` header, see xref:authentication-authorization.adoc[] for more information.
@@ -82,7 +80,7 @@ The only exception is authentication errors, which result in a `401` status code
8280
<3> Query result values, in the same order as `fields`. +
8381
For more information on what format the values may take, see xref:result-formats.adoc[].
8482
<4> Entity ID within the database.
85-
`elementId` should be used with care, as no guarantees are given about the mapping between ID values and elements outside the scope of a single transaction.
83+
Use `elementId` with care, as no guarantees are given about the mapping between ID values and elements outside the scope of a single transaction.
8684
For example, using an `elementId` to `MATCH` an element across different transactions is risky.
8785
<5> Bookmarks are used to enforce an ordering to transactions. +
8886
For more information, see xref:bookmarks.adoc[].

modules/ROOT/pages/transactions.adoc

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
= Run transactions
2+
3+
Use transactions to group together related queries which work together to achieve a single logical database operation.
4+
As Neo4j is <<ACID>> compliant, queries within a <<transaction>> will either be executed as a whole or not at all: you cannot get a part of the transaction succeed and another fail.
5+
6+
[NOTE]
7+
Cypher queries with link:{neo4j-docs-base-uri}/cypher-manual/current/clauses/call-subquery/#subquery-call-in-transactions[`CALL {} IN TRANSACTIONS`] can not be executed in explicit transactions.
8+
Submit those queries with xref:query.adoc[implicit transactions] instead.
9+
10+
11+
== Create a transaction
12+
13+
To open a new (explicit) transaction, submit a `POST` request to the following endpoint:
14+
15+
----
16+
http://<host>:<port>/db/<databaseName>/query/v2/tx
17+
----
18+
19+
- `<host>` is where the Neo4j instance is located (example: `localhost`, `xxx.databases.neo4j.io`),
20+
- `<port>` is the port on which the Neo4j HTTP server is set to listen on (optional; default `7474`),
21+
- `<databaseName>` is the database you want to query (example: `neo4j`).
22+
23+
[TIP]
24+
Each request must include an `Authorization` header, see xref:authentication-authorization.adoc[] for more information.
25+
26+
The body of the request may either:
27+
28+
- contain a `statement` object with the Cypher query to execute
29+
- contain an empty `statement` object
30+
- be entirely empty.
31+
32+
The two latter options are for avoiding the transaction from timing out. +
33+
The server will respond with the location of the new transaction.
34+
35+
====
36+
[discrete]
37+
=== Example request
38+
39+
[source, headers]
40+
----
41+
POST http://localhost:7474/db/neo4j/query/v2/tx
42+
Accept: application/json
43+
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
44+
Content-Type: application/json
45+
----
46+
47+
[source, JSON]
48+
----
49+
{
50+
"statement": "MERGE (n:Person {name: $name, age: $age}) RETURN n AS alice",
51+
"parameters": {
52+
"name": "Alice",
53+
"age": 42
54+
}
55+
}
56+
----
57+
58+
[discrete]
59+
=== Example response
60+
61+
[source, headers]
62+
----
63+
202: Accepted // <1>
64+
Content-Type: application/json
65+
neo4j-cluster-affinity: MTAuOC41Ljc6MTc0NzQ= // <2>
66+
----
67+
68+
[source, JSON]
69+
----
70+
{
71+
"data": {
72+
"fields": [ // <3>
73+
"alice"
74+
],
75+
"values": [ // <4>
76+
{
77+
"elementId": "4:ff04df25-ff2b-4b55-98f8-6888297b025e:0", // <5>
78+
"labels": [
79+
"Person"
80+
],
81+
"properties": {
82+
"name": "Alice",
83+
"age": 42
84+
}
85+
}
86+
]
87+
},
88+
"bookmarks": [ // <6>
89+
"FB:kcwQ/wTfJf8rS1WY+GiIKXsCXgmQ"
90+
],
91+
"transaction": { // <7>
92+
"id": "lyU",
93+
"expires": "2024-10-22T15:48:29Z"
94+
}
95+
}
96+
----
97+
98+
<.> Because the server does not know whether the request will be successful or not when it sends the HTTP status code, all API requests return a `202` status code, regardless of whether the statements were successfully executed.
99+
The only exception is authentication errors, which result in a `401` status code.
100+
<.> The header `neo4j-cluster-affinity` identifies the cluster member handling the transaction.
101+
It must be included as a header to all subsequent requests, including commit/rollback requests.
102+
<.> Query result keys.
103+
<.> Query result values, in the same order as `fields`. +
104+
For more information on what format the values may take, see xref:result-formats.adoc[].
105+
<.> Entity ID within the database.
106+
Use `elementId` with care, as no guarantees are given about the mapping between ID values and elements outside the scope of a single transaction.
107+
For example, using an `elementId` to `MATCH` an element across different transactions is risky.
108+
<.> Bookmarks are used to enforce an ordering to transactions. +
109+
For more information, see xref:bookmarks.adoc[].
110+
<.> Transaction metadata.
111+
Use the ID for subsequent request URIs.
112+
====
113+
114+
115+
== Execute queries
116+
117+
Once a transaction is open, you can submit queries to it by sending more `POST` requests to the following endpoint:
118+
119+
----
120+
http://<host>:<port>/db/<databaseName>/query/v2/tx/<transactionID>
121+
----
122+
123+
You can find the transaction ID under the `transaction.id` key of your first request result.
124+
125+
The request must include the header `neo4j-cluster-affinity`, replaying the value the server sent when the transaction was opened.
126+
127+
====
128+
[discrete]
129+
=== Example request
130+
131+
[source, headers]
132+
----
133+
POST http://localhost:7474/db/neo4j/tx/lyU
134+
Accept: application/json
135+
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
136+
Content-Type: application/json
137+
neo4j-cluster-affinity: MTAuOC41Ljc6MTc0NzQ=
138+
----
139+
140+
[source, JSON]
141+
----
142+
{
143+
"statement": "MERGE (n:Person {name: $name, age: $age}) RETURN n AS bob",
144+
"parameters": {
145+
"name": "Bob",
146+
"age": 43
147+
}
148+
}
149+
----
150+
151+
[discrete]
152+
=== Example response
153+
154+
[source, headers]
155+
----
156+
202: Accepted
157+
Content-Type: application/json
158+
----
159+
160+
[source, JSON, role=nocollapse]
161+
----
162+
{
163+
"data": {
164+
"fields": [
165+
"bob"
166+
],
167+
"values": [
168+
{
169+
"elementId": "4:ff04df25-ff2b-4b55-98f8-6888297b034e:0",
170+
"labels": [
171+
"Person"
172+
],
173+
"properties": {
174+
"name": "Bob",
175+
"age": 43
176+
}
177+
}
178+
]
179+
},
180+
"bookmarks": [
181+
"FB:kcwQ/wTfJf8rS1WY+GiIKXsCXgmQ"
182+
],
183+
"transaction": {
184+
"id": "lyU",
185+
"expires": "2024-10-22T15:48:29Z"
186+
}
187+
}
188+
----
189+
====
190+
191+
192+
== Transaction expiration and keep alive
193+
194+
Transactions expire automatically after a period of inactivity, after which they are rolled back.
195+
By default the timeout is 60 seconds, but you can set a different value in the server configuration (link:{neo4j-docs-base-uri}/operations-manual/current/configuration/configuration-settings#config_server.queryapi.transaction_idle_timeout[`server.queryapi.transaction_idle_timeout`]).
196+
197+
The transaction expiration time is reported in each response, under the `transaction` key.
198+
To keep a transaction alive without submitting new queries, you can submit an empty statement to the transaction URI.
199+
200+
Attempting to submit queries to an expired transaction results in an error:
201+
202+
[source, JSON]
203+
----
204+
{
205+
"errors": [ {
206+
"code": "Neo.ClientError.Request.Invalid",
207+
"message": "Transaction with Id: \"lyU\" was not found. It may have timed out and therefore rolled back or the routing header 'neo4j-cluster-affinity' was not provided."
208+
} ]
209+
}
210+
----
211+
212+
[TIP]
213+
If a response does not contain the `transaction` key, the corresponding transaction has been closed.
214+
This usually happens after an error is raised.
215+
216+
217+
== Commit a transaction
218+
219+
To commit a transaction, send a `POST` request to the following endpoint:
220+
221+
----
222+
http://<host>:<port>/db/<databaseName>/tx/<transactionID>/query/v2/commit
223+
----
224+
225+
Committing a transaction results in its changes becoming permanent on the database.
226+
227+
The request can optionally include a final `statement` object, which will be executed before closing the transaction.
228+
229+
====
230+
[discrete]
231+
=== Example request
232+
233+
[source, headers]
234+
----
235+
POST http://localhost:7474/db/neo4j/tx/lyU/commit
236+
Accept: application/json
237+
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
238+
Content-Type: application/json
239+
neo4j-cluster-affinity: MTAuOC41Ljc6MTc0NzQ=
240+
----
241+
242+
[discrete]
243+
=== Example response
244+
245+
[source, headers]
246+
----
247+
202: Accepted
248+
Content-Type: application/json
249+
----
250+
====
251+
252+
253+
== Rollback a transaction
254+
255+
To rollback a transaction, submit a `DELETE` request to the following endpoint:
256+
257+
----
258+
http://localhost:7474/db/neo4j/tx/query/v2/<transactionID>
259+
----
260+
261+
When a transaction is rolled back, the status of the database gets restored to before the transaction was opened.
262+
All the changes your queries would make to the database are thus discarded.
263+
264+
====
265+
[discrete]
266+
=== Example request
267+
268+
[source, headers]
269+
----
270+
DELETE http://localhost:7474/db/neo4j/query/v2/tx/lyU
271+
Accept: application/json
272+
Authorization: Basic bmVvNGo6dmVyeXNlY3JldA==
273+
neo4j-cluster-affinity: MTAuOC41Ljc6MTc0NzQ=
274+
----
275+
276+
[discrete]
277+
=== Example response
278+
279+
[source, headers]
280+
----
281+
202: Accepted
282+
Content-Type: application/json
283+
----
284+
====
285+
286+
287+
== Authentication failure on open transactions
288+
289+
An authentication error (`Neo.ClientError.Security.Unauthorized`) in a request to an open transaction results in a rollback.
290+
The transaction remains open though.
291+
292+
293+
ifndef::backend-pdf[]
294+
[discrete.glossary]
295+
== Glossary
296+
297+
include::{partials}/glossary.adoc[]
298+
endif::[]

0 commit comments

Comments
 (0)