Class SQLSchemaUpdater
- Direct Known Subclasses:
SpringSQLSchemaUpdater
AbstractSchemaUpdater for SQL databases.
Required properties are the database initialization, update table initialization, and the updates themselves.
Applied updates are recorded in a special update table, which contains two columns: one for the unique
update name and one for a timestamp. The update table and column names
are configurable via setUpdateTableName(),
setUpdateTableNameColumn(), and setUpdateTableTimeColumn().
By default, this class detects a completely uninitialized database by the absence of the update table itself
in the schema (see databaseNeedsInitialization()).
When an uninitialized database is encountered, the configured database initialization
and update table initialization actions are applied first to initialize
the database schema.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringDefault name of the table that tracks schema updates,"SchemaUpdate".static final StringDefault name of the column in the updates table holding the unique update name,"updateName".static final StringDefault name of the column in the updates table holding the update's time applied,"updateTime".Fields inherited from class org.dellroad.stuff.schema.AbstractSchemaUpdater
log -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected voidapply(Connection c, DatabaseAction<Connection> action) Execute a database action within an existing transaction.protected voidCommit a previously opened transaction.protected booleanDetermine if the database needs initialization.Determine which updates have already been applied.Get the empty database initialization.intGet transaction isolation level for the schema check/migration transaction.Get the update table initialization.Get the name of the table that keeps track of applied updates.Get the name of the update name column in the table that keeps track of applied updates.Get the name of the update timestamp column in the table that keeps track of applied updates.protected booleanDetermine if an exception thrown duringdatabaseNeedsInitialization(java.sql.Connection)is consistent with an uninitialized database.voidinitializeAndUpdateDatabase(DataSource dataSource) Perform database schema initialization and updates.protected voidInitialize an uninitialized database.protected ConnectionopenTransaction(DataSource dataSource) Begin a transaction on the given connection.protected voidrecordUpdateApplied(Connection c, String updateName) Record an update as having been applied.protected voidRoll back a previously opened transaction.voidsetDatabaseInitialization(SQLCommandList databaseInitialization) Configure how an empty database gets initialized.voidsetTransactionIsolation(int transactionIsolation) Set transaction isolation level for the schema check/migration transaction.voidsetUpdateTableInitialization(SQLCommandList updateTableInitialization) Configure how the update table itself gets initialized.voidsetUpdateTableName(String updateTableName) Set the name of the table that keeps track of applied updates.voidsetUpdateTableNameColumn(String updateTableNameColumn) Set the name of the update name column in the table that keeps track of applied updates.voidsetUpdateTableTimeColumn(String updateTableTimeColumn) Set the name of the update timestamp column in the table that keeps track of applied updates.Methods inherited from class org.dellroad.stuff.schema.AbstractSchemaUpdater
applyInTransaction, generateMultiUpdateName, getAllUpdateNames, getOrderingTieBreaker, getUpdates, isIgnoreUnrecognizedUpdates, isValidUpdateName, setIgnoreUnrecognizedUpdates, setUpdates
-
Field Details
-
DEFAULT_UPDATE_TABLE_NAME
Default name of the table that tracks schema updates,"SchemaUpdate".- See Also:
-
DEFAULT_UPDATE_TABLE_NAME_COLUMN
Default name of the column in the updates table holding the unique update name,"updateName".- See Also:
-
DEFAULT_UPDATE_TABLE_TIME_COLUMN
Default name of the column in the updates table holding the update's time applied,"updateTime".- See Also:
-
-
Constructor Details
-
SQLSchemaUpdater
public SQLSchemaUpdater()
-
-
Method Details
-
getUpdateTableName
Get the name of the table that keeps track of applied updates.- Returns:
- the name of the update table
- See Also:
-
setUpdateTableName
Set the name of the table that keeps track of applied updates. Default value isDEFAULT_UPDATE_TABLE_NAME.This name must be consistent with the update table initialization.
- Parameters:
updateTableName- the name of the update table
-
getUpdateTableNameColumn
Get the name of the update name column in the table that keeps track of applied updates.- Returns:
- the name of the name column in the update table
- See Also:
-
setUpdateTableNameColumn
Set the name of the update name column in the table that keeps track of applied updates. Default value isDEFAULT_UPDATE_TABLE_NAME_COLUMN.This name must be consistent with the update table initialization.
- Parameters:
updateTableNameColumn- the name of the name column in the update table
-
getUpdateTableTimeColumn
Get the name of the update timestamp column in the table that keeps track of applied updates.- Returns:
- the name of the timestamp column in the update table
- See Also:
-
setUpdateTableTimeColumn
Set the name of the update timestamp column in the table that keeps track of applied updates. Default value isDEFAULT_UPDATE_TABLE_TIME_COLUMN.This name must be consistent with the update table initialization.
- Parameters:
updateTableTimeColumn- the name of the timestamp column in the update table
-
getUpdateTableInitialization
Get the update table initialization.- Returns:
- SQL commands to create the update table
- See Also:
-
setUpdateTableInitialization
Configure how the update table itself gets initialized. This update is run when no update table found, which (we assume) implies an empty database with no tables or content. This is a required property.This initialization should create the update table where the name column is the primary key. The name column must have a length limit greater than or equal to the longest schema update name.
The table and column names must be consistent with the values configured via
setUpdateTableName(),setUpdateTableNameColumn(), andsetUpdateTableTimeColumn().For convenience, pre-defined initialization scripts using the default table and column names are available at the following resource locations. These can be used to configure a
SQLCommandList:Database Resource MySQL (InnoDB) classpath:org/dellroad/stuff/schema/updateTable-mysql.sqlOracle classpath:org/dellroad/stuff/schema/updateTable-oracle.sqlPostgres classpath:org/dellroad/stuff/schema/updateTable-postgres.sqlHSQLDB classpath:org/dellroad/stuff/schema/updateTable-hsqldb.sql- Parameters:
updateTableInitialization- update table schema initialization- See Also:
-
getDatabaseInitialization
Get the empty database initialization.- Returns:
- SQL commands to initialize an empty database
- See Also:
-
setDatabaseInitialization
Configure how an empty database gets initialized. This is a required property.This update is run when no update table found, which (we assume) implies an empty database with no tables or content. Typically this contains the SQL script that gets automatically generated by your favorite schema generation tool.
This script is expected to initialize the database schema (i.e., creating all the tables) so that when completed the database is "up to date" with respect to the configured schema updates. That is, when this action completes, we assume all updates have already been (implicitly) applied (and they will be recorded as such).
Note this script is not expected to create the update table that tracks schema updates; that function is handled by the update table initialization.
- Parameters:
databaseInitialization- application database schema initialization
-
getTransactionIsolation
public int getTransactionIsolation()Get transaction isolation level for the schema check/migration transaction.Default is
Connection.TRANSACTION_SERIALIZABLE.- Returns:
- transaction isolation level, or -1 to leave it alone
-
setTransactionIsolation
public void setTransactionIsolation(int transactionIsolation) Set transaction isolation level for the schema check/migration transaction.Default is
Connection.TRANSACTION_SERIALIZABLE.- Parameters:
transactionIsolation- transaction isolation level, or -1 to leave it alone
-
apply
Description copied from class:AbstractSchemaUpdaterExecute a database action within an existing transaction.All database operations in
AbstractSchemaUpdaterare performed via this method; subclasses are encouraged to follow this pattern.The implementation in
AbstractSchemaUpdatersimply invokesaction.apply(); subclasses may override if desired.- Overrides:
applyin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- transaction within which to applyactionaction- operation to perform- Throws:
SQLException
-
initializeAndUpdateDatabase
Description copied from class:AbstractSchemaUpdaterPerform database schema initialization and updates.This method applies the following logic: if the database needs initialization, then initialize the database and record each update as having been applied; otherwise, apply any unapplied updates as needed.
Note this implies the database initialization must initialize the database to its current, up-to-date state (with respect to the set of all available updates), not its original, pre-update state.
The database initialization step, and each of the update steps, is performed within its own transaction.
- Overrides:
initializeAndUpdateDatabasein classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
dataSource- the database to initialize (if necessary) and update- Throws:
SQLException- if an update failsIllegalStateException- if the database needs initialization and either the database initialization or the update table initialization has not been configuredIllegalStateExceptionIllegalArgumentException- if any configured update has a required predecessor which is not also a configured update (i.e., if the updates are not transitively closed under predecessors)
-
openTransaction
Begin a transaction on the given connection.The implementation in
SQLSchemaUpdatercreates a serializable-level transaction.- Specified by:
openTransactionin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
dataSource- the database on which to open the transaction- Returns:
- new
Connectionwith an open transaction - Throws:
SQLException- if an error occurs while accessing the database
-
commitTransaction
Commit a previously opened transaction.The implementation in
SQLSchemaUpdaterjust invokesConnection.commit().- Specified by:
commitTransactionin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- the connection on which to commit the transaction- Throws:
SQLException- if an error occurs while accessing the database
-
rollbackTransaction
Roll back a previously opened transaction. This method will also be invoked ifcommitTransaction()throws an exception.The implementation in
SQLSchemaUpdaterjust invokesConnection.rollback().- Specified by:
rollbackTransactionin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- the connection on which to roll back the transaction- Throws:
SQLException- if an error occurs while accessing the database
-
databaseNeedsInitialization
Determine if the database needs initialization.The implementation in
SQLSchemaUpdatersimply invokesSELECT COUNT(*) FROM UPDATETABLEand checks for success or failure. If an exception is thrown,indicatesUninitializedDatabase(java.sql.Connection, java.sql.SQLException)is used to distinguish between an exception caused by an uninitialized database and a truly unexpected one.- Specified by:
databaseNeedsInitializationin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- connection to the database- Returns:
- true if the database needs initialization, otherwise false
- Throws:
SQLException- if an unexpected error occurs while accessing the database
-
indicatesUninitializedDatabase
Determine if an exception thrown duringdatabaseNeedsInitialization(java.sql.Connection)is consistent with an uninitialized database.This should return true if the exception would be thrown by an SQL query that attempts to access a non-existent table. For exceptions thrown by other causes, this should return false.
The implementation in
SQLSchemaUpdateralways returns true. Subclasses are encouraged to override with a more precise implementation.- Parameters:
c- connection on which the exception occurrede- exception thrown during database access indatabaseNeedsInitialization(java.sql.Connection)- Returns:
- true if
eindicates an uninitialized database - Throws:
SQLException- if an error occurs- See Also:
-
recordUpdateApplied
Record an update as having been applied.The implementation in
SQLSchemaUpdaterdoes the standard JDBC thing using an INSERT statement into the update table.- Specified by:
recordUpdateAppliedin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- SQL connectionupdateName- update name- Throws:
IllegalStateException- if the update has already been recorded in the databaseSQLException- if an error occurs while accessing the database
-
getAppliedUpdateNames
Determine which updates have already been applied.The implementation in
SQLSchemaUpdaterdoes the standard JDBC thing using a SELECT statement from the update table.- Specified by:
getAppliedUpdateNamesin classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- open transaction- Returns:
- set of already-applied updates
- Throws:
SQLException- if an error occurs while accessing the database
-
initializeDatabase
Description copied from class:AbstractSchemaUpdaterInitialize an uninitialized database. This should create and initialize the database schema and content, including whatever portion of that is used to track schema updates.- Specified by:
initializeDatabasein classAbstractSchemaUpdater<DataSource,Connection> - Parameters:
c- open transaction- Throws:
SQLException
-