New ACM paper, free-tier cloud, and open-source license

Lesson 6.3: Sessions and transactions

Opening sessions

With a connection established to the server via a driver object, we can now open sessions to specific databases on the server by instantiating a session object, as illustrated in the following code snippet.

DATABASE = "database-name"

with TypeDB.core_driver(ADDRESS) as driver:
    with driver.session(DATABASE, SessionType.DATA) as session:
        # code goes here

The session object takes two arguments, the database name and the session type, and should be instantiated using a context manager. There are two types of session, data sessions and schema sessions, denoted by the DATA and SCHEMA values of the SessionType enum respectively. Data sessions are used to read and write data, while schema sessions are used to make changes to the schema. Schema sessions are locking: only one can be opened at any time per database, and data writes cannot be performed in any active session while a schema session is open. Most applications will only require data sessions.

A data session should be kept open for the lifetime of a user’s session on the application. If the application requires access to multiple databases, one session must be used per database. Within a session, any number of transactions can be opened and executed in parallel, and TypeDB will optimise performance by storing regularly accessed information in a session cache.

Controlling transactions

Within the scope of a session, we can open transactions by instantiating a transaction object, as illustrated in the following code snippet.

with TypeDB.core_driver(ADDRESS) as driver:
    with driver.session(DATABASE, SessionType.DATA) as session:
        with session.transaction(TransactionType.READ) as transaction:
            # code goes here

The transaction object takes one argument, the transaction type, and should be instantiated using a context manager. There are two types of transaction, read transactions and write transactions, denoted by the READ and WRITE values of the TransactionType enum. Read transactions are used to retrieve data, while write transactions are used to modify data. This is in line with the principle of command-query separation, and leads to three different combinations of session and transaction types.

SessionType TransactionType Purpose

DATA

READ

Retrieving data.

DATA

WRITE

Modifying data.

SCHEMA

WRITE

Modifying the schema.

The fourth combination, a read transaction in a schema session, is deprecated and should not be used. Retrieval of schema types, as featured in Lesson 3.4, can be done using a data session.

When opened using a context manager as above, read transactions will be closed automatically. If a write transaction is closed in this way, then the transaction will be rolled back and any data writes will not be persisted to the database. In order to persist changes made during a write transaction, it must be committed by calling its commit method, as illustrated in the following code snippet.

with TypeDB.core_driver(ADDRESS) as driver:
    with driver.session(DATABASE, SessionType.DATA) as session:
        with session.transaction(TransactionType.WRITE) as transaction:
            # code goes here

            transaction.commit()

Committing a transaction also closes it on the server, and no further operations are permitted with it afterward. A transaction can also be manually rolled back and closed by calling its close method, or rolled back without closing by calling its rollback method (allowing further operations).

Unlike a session, a transaction should be short-lived and represents a single atomic unit of work on the database. TypeDB implements the ACID guarantees, and uses snapshot isolation and optimistic concurrency control to support concurrent transactions to read and write data without locks. As detailed above, some locks are implemented when a schema session is opened. For information, refer to the ACID guarantees page.

Provide Feedback