@PublicApi public interface

DatabaseAccessor

com.atlassian.jira.database.DatabaseAccessor
Known Indirect Subclasses

@PublicApi

This interface is designed for plugins to consume (call its methods).

Clients of @PublicApi can expect that programs compiled against a given version will remain binary compatible with later versions of the @PublicApi as per each product's API policy as long as the client does not implement/extend @PublicApi interfaces or classes (refer to each product's API policy for the exact guarantee---usually binary compatibility is guaranteed at least across minor versions).

Note: since @PublicApi interfaces and classes are not designed to be implemented or extended by clients, we may perform certain types of binary-incompatible changes to these classes and interfaces, but these will not affect well-behaved clients that do not extend/implement these types (in general, only classes and interfaces annotated with @PublicSpi are safe to extend/implement).

Class Overview

Provides access to database connections from the Database Connection Pool.

Important: Note that due to how customers configure DB connections, you must include the schema name in your queries if one is configured.

Summary

Public Methods
<R> R executeQuery(ConnectionFunction<R> callback)
Executes SQL statements as defined in the callback function.
@Nonnull DatabaseVendor getDatabaseVendor()
Returns the vendor of the database that we are connected to.
@Nonnull Optional<String> getSchemaName()
Returns the configured schema name of the configured database connection.
<R> R runInTransaction(Function<Connection, R> callback)
Executes SQL statements as defined in the callback function and manages transaction semantics.

Public Methods

public R executeQuery (ConnectionFunction<R> callback)

Executes SQL statements as defined in the callback function.

This method will borrow a new connection from the pool, pass it to the callback function and then return it to the pool after the callback has completed. Even if OfBiz is currently running in a ThreadLocal transaction, this will retrieve a fresh connection from the pool. If you want to run in an existing OfBiz transaction then see instead #runInTransaction(ConnectionFunction)

Because database connections are limited resources, your code should do its database operations and return from the callback as soon as possible in order to not starve other threads of this resource. In particular, you should not call any code that may in turn borrow a second connection from the pool (this can lead to a deadlock). In general avoid doing anything "slow" (eg I/O) nor await on other limited resources (eg locks).

Do not close the given connection - DatabaseAccessor will return it to the pool for you after the method is complete. If the ConnectionFunction callback throws a RuntimeException and the connection is not in auto-commit mode, then this method will perform a rollback on the connection (no explicit rollback is required).

Do not hold onto the Connection after your callback completes. Once the callback completes, the connection will be returned to the pool and can be immediately borrowed by another thread.

The connection will have the default auto-commit value as defined by the JIRA connection pool. As at JIRA 7.0 this means autocommit == true. See org.apache.commons.dbcp.PoolableConnectionFactory#activateObject(Object) for details. Note that this is very different to the behaviour of runInTransaction(Function) where the transaction is completely managed for you.

Example Usage for autocommit:

     databaseAccessor.execute(connection -> runMyQuery(connection.getJdbcConnection()));
 

Example Usage with transaction:

     databaseAccessor.executeQuery(
         connection -> {
             connection.setAutoCommit(false);
             // throws RuntimeException to indicate rollback
             doSomeUpdates(connection.getJdbcConnection());
             connection.commit();
         }
     );
 

Parameters
callback the callback function that can run one or more queries with the managed connection.
Returns
  • the value as returned by the callback function

@Nonnull public DatabaseVendor getDatabaseVendor ()

Returns the vendor of the database that we are connected to.

Returns
  • the vendor of the database that we are connected to.
Throws
IllegalStateException if the connected DB is not one of the supported DB vendors as defined in DatabaseVendor

@Nonnull public Optional<String> getSchemaName ()

Returns the configured schema name of the configured database connection. If this is not empty then SQL will need to qualify the table name with this schema name.

Returns
  • the configured database schema name

public R runInTransaction (Function<Connection, R> callback)

Executes SQL statements as defined in the callback function and manages transaction semantics.

This method will attempt to run the callback within an existing OfBiz transaction if one is running within this thread. For that reason, the commit and rollback will be completely managed for you. If the callback returns successfully, then this indicates that the underlying transaction is allowed to be committed at the appropriate time. If you want to rollback the transaction then throw a RuntimeException. The transaction will be marked as "rollback required" such that the code that started the transaction will eventually call rollback on the Connection and the exception will be propagated.

Because the connection (borrowing and returning from the pool) and its transaction are managed for you, then specific Connection methods are illegal to call and will cause a RuntimeException including:

  • setAutoCommit(boolean) autocommit is always false
  • commit()
  • commit will occur in the broader transaction context if no errors are encountered
  • rollback()
  • rollback will occur if a RuntimeException is thrown from the callback function
  • close()
  • the connection will be returned to the pool for you at the appropriate time
Note that this is very different to the behaviour of executeQuery(ConnectionFunction) where the transaction is not managed.

Example Usage:

     databaseAccessor.runInTransaction(
         connection -> {
             // throws RuntimeException to indicate rollback required
             doSomeUpdates(connection);
         }
     );
 

Parameters
callback the callback function that can run one or more queries with the managed connection.
Returns
  • the value as returned by the callback function