An API for accessing and processing data stored in a data source (usually a relational database) using the Java™ programming language. This API includes a framework whereby different drivers can be installed dynamically to access different data sources. This API is specifically geared for passing SQL statements to a database though it may be used for reading and writing data from/to any data source that has a tabular format.
This API differs from the API in java.sql
in several ways.
It is worth emphasizing that this API is an alternate to the java.sql
API, not a replacement. There are many programs that can much more readily be
written using the java.sql
API as it has many features that are not
available in this API. For example this API provides almost no mechanism for
getting metadata.
This API is not an extension to the java.sql
API. It an independent
API and is used on its own without reference to java.sql.
The core feature of this API is that it is asynchronous. No method call will wait for a network operation.
Possibly blocking actions are represented as Operation
s. An
application using the API creates and submits one or more Operation
s.
The implementation executes these Operation
s asynchronously, reporting
their results via CompletionStage
s. An application
can respond to the results via the
CompletionStage
s or via callbacks that can be
configured on many of the Operation
s or both. Creating and submitting
Operation
s is strictly non-blocking. Handling the results of possibly
blocking Operation
s is done asynchronously. No application thread
will ever block on a call to a method in this API.
All Operation
s provide a
CompletionStage
. The value of that
CompletionStage
is the value of the
Operation
, set when the Operation
completes. Some
Operation
s provide callbacks for processing the result of the
Operation
independent of the
CompletionStage
. Those Operation
s can
be used for executing SQL that returns results of a specific type. For
example SQL that returns a row sequence would be executed with a
RowOperation
. A RowOperation
provides callbacks for
processing each row and for collecting the results of processing the rows.
Other Operation
s are specialized for SQL that returns a count or that
returns out parameters. The choice of Operation
is dependent on the
result to be processed and is independent of the particular kind of SQL
statement.
An OperationGroup
encapsulates a group of Operation
s and
executes them using common attributes. An OperationGroup
can be
unconditional or conditional, sequential or parallel, dependent or
independent, or any combination of these. Dependent/independent controls
error handling. If one member of a dependent OperationGroup
fails the
remaining not-yet-executed members are completed exceptionally. If the
OperationGroup
is independent, the member Operation
s are
executed regardless of whether one or more fails.
A single context in a data source is represented by a Session
. A
Session
is somewhat analogous to a logical java.sql.Connection
.
A physical java.sql.Connection
has no representation in this API; if
such an entity exists at all it is strictly internal to an implementation.
Within this spec this entity is referred to as a "data source resource".
A Session
is itself an OperationGroup
and so can be
conditional, parallel, or independent, but by default is unconditional,
sequential, dependent. While a Session
may be created with values
other than the defaults, using the defaults is by far the most common case.
The API provides convenience methods that support this case. Using these
convenience methods is recommended in all but the most unusual circumstances.
In particular making the Session
parallel introduces some
challenges that would require a full understanding of the details of the API.
It would almost certainly be better to create a parallel
OperationGroup
within the Session
.
ISSUE: Should we disallow Session.parallel()
?
The java.sql
API frequently provides many ways to do the same thing.
This API makes no attempt to do this. For those capabilities this API
supports, it frequently defines exactly one way to do something. Doing things
another way, for example calling methods in a non-standard order, frequently
results in an IllegalStateException. This approach is intended to make things
simpler for both the user and the implementor. Rather than having to
understand complicated interactions of many different components and methods
executed in any order, the intent is that there is only one way to do things
so only one path must be understood or implemented. Anything off that path is
an error. While this requires a programmer to write code in one specific way
it makes things easier on future maintainers of the code as the code will
conform to the standard pattern. Similarly the implementation is simplified
as only the standard use pattern is supported.
One way this API simplifies things in to define types as single use. Many
types are created, configured, used once, and are then no longer usable. Most
configuration methods can be called only once on a given instance. Once an
instance is configured it cannot be reconfigured. Once an instance is used it
cannot be reused. This simplifies things by eliminating the need to
understand and implement arbitrary sequences of method calls that reconfigure
and reuse instances. Since objects are single use there is no expectation
that an application cache or share Operation
s.
While the user visible types are single use, it is expected that an
implementation will cache and reuse data and Object
s that are worth
the effort. Rather than attempt to guess what an implementation should reuse
and capture that in the API, this API leaves it entirely up to the
implementation. Since the API specifies very little reuse, an implementation
is free to reuse whatever is appropriate. Since the pattern of use is
strictly enforced figuring out how to reuse objects is greatly
simplified.
The java.sql
API provides many tools for abstracting the database,
for enabling the user to write database independent code. This API does not.
It is not a goal of this API to enable users to write database independent
code. That is not to say it is not possible, just that this API does not
provide tools to support such. Abstraction features typically impose
performance penalties on some implementations. As this API is geared for
high-throughput programs it avoids such abstractions rather than reduce
performance.
One such abstraction feature is the JDBC escape sequences. Implementing these features requires parsing the SQL so as to identify the escape sequences and then generating a new String with the vendor specific SQL corresponding to the escape sequence. This is an expensive operation. Further each SQL must be parsed whether it contains an escape sequence or not imposing the cost on all JDBC users, not just the ones who use escape sequences. The same is true of JDBC parameter markers. The SQL accepted by this API is entirely vendor specific, including parameter markers. There is no need for pre-processing prior to SQL execution substantially reducing the amount of work the implementation must do.
Note: It would be a reasonable future project to develop a SQL builder API that creates vendor specific SQL from some more abstract representation.
This API is targeted at high-throughput apps. If a particular feature of this
API would have a surprising performance impact for a particular implementation
it is recommended that the implementation not implement that feature. It is
better that a feature be unsupported as opposed to users investing substantial
effort in an app using that feature only to discover in production that the
performance is unacceptable. For example, if an implementation can only support
Operation.timeout(java.time.Duration)
through active polling it would be better for that
implementation to throw UnsupportedOperationException
if
Operation.timeout(java.time.Duration)
is called. To this end every type and method is
optional except returning a DataSourceFactory
in response to a call to
DataSourceFactory.newFactory(java.lang.String)
with the appropriate name.
This section describes the function of a conforming implementation. It is not necessary for an implementation to be implemented as described only that the behavior be the same.
An Operation
has an action and a
CompletionStage
. Some Operation
s have
some form of result processor.
An Operation
is executed by causing the action to be performed,
processing the result of the action if there is a result processor, and
completing the CompletionStage
with the result
of the result processor if there is one. If the action or the result processing
causes an unhandled error the CompletionStage
is
completed exceptionally. The CompletionStage
is
completed asynchronously, as though it were created by calling an
async method on CompletionStage
.
Performing the action may require one or more interactions with the database. These interactions may be carried out in parallel with processing the result. If the database result is ordered, that result is processed in the order specified by the database.
An OperationGroup
has a collection of member Operation
s and
optionally a condition. For a sequential OperationGroup
Operation
s are selected from the collection in the order they were
submitted. For a parallel OperationGroup
Operation
s are
selected from the collection in any order.
The action of an OperationGroup
is performed as follows:
OperationGroup
has a condition, the value of the condition is
retrieved. If the value is Boolean.FALSE
the action is complete and
the CompletionStage
is completed with null. If
the condition value completes exceptionally the action is complete and the
CompletionStage
is completed exceptionally
with the same exception. If the condition value is Boolean.TRUE
or
there is no condition the Operation
s in the collection are executed
and their results processed. The action is complete when the
OperationGroup
is not held and all the Operation
s have been
executed.OperationGroup
is parallel more than one member
Operation
may be executed at a time.OperationGroup
is dependent and a member Operation
completes
exceptionally all member Operation
s that are yet to begin
execution are completed exceptionally with a SqlSkippedException
. The
cause of that exception is the Throwable
that caused the
Operation
to be completed exceptionally. If an Operation
is
in flight when another Operation
completes exceptionally the in
flight Operation
may either be allowed to complete uninterrupted or
it may be completed exceptionally. The OperationGroup
is dependent it
is completed exceptionally with the Throwable
that caused the
Operation
to complete exceptionally.
Note: the Operation
s returned by Session.closeOperation()
and OperationGroup.catchOperation()
are never skipped, i.e. never
completed exceptionally with SqlSkippedException
. The Operation
returned by OperationGroup.catchOperation()
never completes
exceptionally so the following Operation
is always executed normally.
No Operation
can be submitted after the Operation
returned by
Session.closeOperation()
has been submitted.
OperationGroup
is independent and an Operation
completes exceptionally all other Operation
s are executed regardless.
There is no result to be processed for an Operation
that completed
exceptionally. The OperationGroup
is not completed exceptionally as
the result of one or more Operation
s completing exceptionally.
A Session
is a distinguished OperationGroup
. A
Session
is executed upon being submitted.
This section describes the function of a conforming implementation. It is not necessary for an implementation to be implemented as described only that the behavior be the same.
An implementation has only limited control over transactions. SQL statements
can start, commit, and rollback transactions without the implementation
having any influence or even being aware. This specification only describes
the behavior of those transaction actions that are visible to and controlled
by the implementation, i.e. the endTransaction Operation
.
Transaction actions caused by SQL may interact with actions controlled by the
implementation in unexpected ways.
The creation of Operations and the subsequent execution of those Operations
are separated in time. It is quite reasonable to determine that a transaction
should commit after the Operation that ends the transaction is submitted. But
if the execution of the transaction does not result in the expected results
it might be necessary to rollback the transaction rather than commit it. This
determination depends on the execution of the Operations long after the
endTransaction Operation is submitted. To address this mismatch, the
endTransaction Operation is conditioned by a TransactionCompletion
. By
default, a TransactionCompletion
will cause an endTransaciton
Operation
to commit the transaction. At any time before the
endTransaction Operation
that references it is executed a
TransactionCompletion
can be set to rollback the transaction .
An endTransaction Operation
, like all Operation
s, is
immutable once submitted. But an endTransaction Operation
is created
with a TransactionCompletion
and that TransactionCompletion
can be set to
commit or rollback. A TransactionCompletion
controls the endTransaction
Operation
created with it. Using this mechanism an error handler,
result handler or other code can cause a subsequent endTransaction
Operation
to rollback instead of the default which is to commit.
TransactionCompletion t = session.getTransactionEnd();
session.countOperation(updateSql)
.resultProcessor( count -> {
if (count > 1) t.setRollbackOnly();
return null;
} )
.submit();
session.catchErrors();
session.commitMaybeRollback(t);
In this example if the update SQL modifies more than one row the result
processor will set the TransactionCompletion
to rollback only. When the
endTransaction Operation
submitted by
OperationGroup.commitMaybeRollback(jdk.incubator.sql2.TransactionCompletion)
is executed it will cause the
transaction to rollback.
If an implementation exposes any implementation specific types and methods, the implementation is expected to provide covariant overrides for all methods that return the standard super-type of the implementation specific type.
Consider an implementation that adds a method foo() to RowCountOperation. To do that it would have to expose a type FooRowCountOperation extends RowCountOperation. So that an application can transparently access foo, the implementation would also have to expose FooDataSource, FooOperationGroup and FooSession. Further each of these types would have to declare covariant overrides for every method that returns a direct super-type of one of these types.
The intent is to transparently expose the vendor extension without use of casts. Example:
FooDataSourceFactory factory = DataSourceFatory.newFactory("com.foo.FooDataSourceFatory");
FooDataSource dataSource = factory.builder()
.url("scott/tiger@host:port")
.build();
FooSession session = dataSource.getSession();
CompletionStage<Long> count = session.rowOperation(sql)
.set("param", value, AdbaType.VARCHAR)
.foo()
.submit()
.getCompletionStage();
Notice that there are no casts, yet both standard methods an the vendor extension method foo can be referenced. This is possible only if the implementation exposes all the necessary types and provides covariant overrides for every method that returns one of those types. Implementations are expected (required?) to do this.
If an implementation does not expose any implementation specific methods or types, that implementation is not required to provide covariant overrides that return implementation specific types.
Interface | Description |
---|---|
ArrayRowCountOperation<T> |
A database operation that returns a count that is executed multiple times
with multiple sets of parameter values in one database operation.
|
DataSource |
Uses the builder pattern to get a
Session . |
DataSource.Builder |
Instances of this type are used to build
DataSource s. |
DataSourceFactory |
This interface supports injecting a
DataSourceFactory . |
DataSourceProperty |
An attribute of a
DataSource that can be configured to influence its
behavior. |
LocalOperation<T> |
An
Operation that executes a user defined action when executed. |
MultiOperation<T> | |
Operation<T> |
A description of some work to be done by the database and how to process the
database output.
|
OperationGroup<S,T> |
A set of
Operation s that share certain properties, are managed as a
unit, and are executed as a unit. |
OutOperation<T> |
An
ParameterizedOperation for which the result is a set of out parameter
values and/or function results. |
ParameterizedOperation<T> |
An Operation that has in parameters.
|
ParameterizedRowCountOperation<T> |
A
ParameterizedRowCountOperation is a ParameterizedOperation that returns a count. |
ParameterizedRowOperation<T> |
An Operation that accepts parameters and processes a sequence of rows.
|
ParameterizedRowPublisherOperation<T> |
An Operation that accepts parameters, subscribes to a sequence of rows, and
returns a result.
|
PrimitiveOperation<T> |
A PrimitiveOperation can be submitted, nothing more.
|
Result | |
Result.Column |
A mutable handle to one value of an ordered sequence of columns of a row or
of out parameters.
|
Result.OutColumn |
Used by
OutOperation to expose the out parameters of a stored
procedure call. |
Result.RowColumn |
Used by
RowOperation to expose each row of a row sequence. |
Result.RowCount |
A
Result that is just a number of rows modified, a Long . |
RowCountOperation<T> |
An
Operation that returns a count. |
RowOperation<T> |
A
RowOperation is a database operation that returns a row sequence. |
RowPublisherOperation<T> | |
Session | |
Session.Builder |
A
Session builder. |
Session.SessionLifecycleListener |
A Listener that is notified of changes in a Session's lifecycle.
|
SessionProperty |
An attribute of a
Session that can be configured to influence its
behavior. |
ShardingKey |
Interface used to indicate that this object represents a Sharding Key.
|
ShardingKey.Builder |
A builder created from a
DataSource or object, used to create a
ShardingKey with sub-keys of supported data types. |
SqlBlob |
A reference to a BINARY LARGE OBJECT in the attached database.
|
SqlClob |
A reference to a CHARACTER LARGE OBJECT in the attached database.
|
SqlRef<T> | |
SqlType |
Identifies a SQL type.
|
Submission<T> |
The result of submitting an
Operation . |
TransactionCompletion |
A mutable object that controls whether a transactionCompletion Operation sends
a database commit or a database rollback to the server.
|
Class | Description |
---|---|
Examples |
Simple example code using various aspects of ADBA.
|
Examples.Item |
Enum | Description |
---|---|
AdbaDataSourceProperty |
Properties that apply to the DataSource as a whole, not to the individual
Session s that the DataSource creates. |
AdbaSessionProperty |
A set of
SessionProperty commonly supported. |
AdbaSessionProperty.Caching |
Specifies how much flexibility the
DataSource has in satisfying a
request for a Session possibly by using cached data source resources. |
AdbaSessionProperty.TransactionIsolation | |
AdbaType |
Defines the constants that are used to identify generic
SQL types, called JDBC types.
|
Examples.ExampleSessionProperty | |
Session.Lifecycle |
Identifies the operational state of a
Session . |
Session.Validation |
Specifiers for how much effort to put into validating a
Session . |
TransactionOutcome |
Possible outcomes for a database transaction.
|
Exception | Description |
---|---|
SqlException |
An exception that provides information on a database access error or other
errors.
|
SqlSkippedException |
Annotation Type | Description |
---|---|
SqlArray |
Identifies a type that represents an ARRAY SQL type.
|
SqlColumns |
Identifies a constructor or static factory method that can be used to construct
an instance of the containing type when the type is passed to
Result.Column.get(java.lang.Class<T>) . |
SqlParameter |
Identifies a method the result of which will be bound to a parameter in a SQL
statement when an instance of the containing type is passed to
ParameterizedOperation.set(java.lang.String, java.lang.Object, jdk.incubator.sql2.SqlType) . |
SqlStruct |
Identifies a type that represents a STRUCT SQL type.
|
SqlStruct.Field |
Describes a field of a SQL STRUCT type.
|
Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2017, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.
DRAFT JDBC 4.4 EA5