org.dellroad.stuff.schema
Class SpringSQLSchemaUpdater

java.lang.Object
  extended by org.dellroad.stuff.schema.AbstractSchemaUpdater<DataSource,Connection>
      extended by org.dellroad.stuff.schema.SQLSchemaUpdater
          extended by org.dellroad.stuff.schema.SpringSQLSchemaUpdater
All Implemented Interfaces:
BeanFactoryAware, InitializingBean

public class SpringSQLSchemaUpdater
extends SQLSchemaUpdater
implements BeanFactoryAware, InitializingBean

SQLSchemaUpdater optimized for use with Spring.

An example of how this class can be combined with custom XML to define an updater, all its updates, and a SchemaUpdatingDataSource that automatically updates the database schema:

  <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:dellroad-stuff="http://dellroad-stuff.googlecode.com/schema/dellroad-stuff"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
      http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://dellroad-stuff.googlecode.com/schema/dellroad-stuff
        http://dellroad-stuff.googlecode.com/svn/wiki/schemas/dellroad-stuff-1.0.xsd">

     <!-- DataSource that automatically updates the database schema -->
     <bean id="dataSource" class="org.dellroad.stuff.schema.SchemaUpdatingDataSource"
       p:dataSource-ref="realDataSource" p:schemaUpdater-ref="schemaUpdater"/>

     <!--
          Database updater bean. This is used on first access to the DataSource above. Notes:
            - "databaseInitialization" is used to initialize the schema (first time only)
            - "updateTableInitialization" is used to initialize the update table (first time only)
            - In this example, we just use dellroad-stuff's update table initialization for MySQL
            - The <dellroad-stuff:sql-update> beans below will be auto-detected
     -->
     <bean id="schemaUpdater" class="org.dellroad.stuff.schema.SpringSQLSchemaUpdater">
         <property name="databaseInitialization">
             <dellroad-stuff:sql resource="classpath:databaseInit.sql"/>
         </property>
         <property name="updateTableInitialization">
             <dellroad-stuff:sql resource="classpath:org/dellroad/stuff/schema/updateTable-mysql.sql"/>
         </property>
     </bean>

      <!-- Schema update to add the 'phone' column to the 'User' table -->
      <dellroad-stuff:sql-update id="addPhone">ALTER TABLE User ADD phone VARCHAR(64)</dellroad-stuff:sql-update>

      <!-- Schema update to run some complicated external SQL script -->
      <dellroad-stuff:sql-update id="majorChanges" depends-on="addPhone" resource="classpath:majorChanges.sql"/>

      <!-- Multiple SQL commands that will be automatically separated into distinct updates -->
      <dellroad-stuff:sql-update id="renameColumn">
          ALTER TABLE User ADD newName VARCHAR(64);
          ALTER TABLE User SET newName = oldName;
          ALTER TABLE User DROP oldName;
      </dellroad-stuff:sql-update>

      <!-- Add more schema updates over time as needed and everything just works... -->

  </beans>
 

In the case no schema updates are explicitly configured, it is required that this updater and all of its schema updates are defined in the same ListableBeanFactory.


Field Summary
 
Fields inherited from class org.dellroad.stuff.schema.SQLSchemaUpdater
DEFAULT_UPDATE_TABLE_NAME, DEFAULT_UPDATE_TABLE_NAME_COLUMN, DEFAULT_UPDATE_TABLE_TIME_COLUMN
 
Fields inherited from class org.dellroad.stuff.schema.AbstractSchemaUpdater
log
 
Constructor Summary
SpringSQLSchemaUpdater()
           
 
Method Summary
 void afterPropertiesSet()
           
protected  void apply(Connection c, DatabaseAction<Connection> action)
          Apply a DatabaseAction to a Connection.
protected  Comparator<SchemaUpdate<Connection>> getOrderingTieBreaker()
          Get the preferred ordering of two updates that do not have any predecessor constraints (including implied indirect constraints) between them.
protected  boolean indicatesUninitializedDatabase(Connection c, SQLException e)
          Determine if an exception thrown during SQLSchemaUpdater.databaseNeedsInitialization(java.sql.Connection) is consistent with an uninitialized database.
 void setBeanFactory(BeanFactory beanFactory)
           
protected  DataAccessException translate(SQLException e, Connection c, String sql)
          Converts SQLExceptions into Spring DataAccessExceptions.
 
Methods inherited from class org.dellroad.stuff.schema.SQLSchemaUpdater
commitTransaction, databaseNeedsInitialization, getAppliedUpdateNames, getDatabaseInitialization, getUpdateTableInitialization, getUpdateTableName, getUpdateTableNameColumn, getUpdateTableTimeColumn, initializeAndUpdateDatabase, initializeDatabase, openTransaction, recordUpdateApplied, rollbackTransaction, setDatabaseInitialization, setUpdateTableInitialization, setUpdateTableName, setUpdateTableNameColumn, setUpdateTableTimeColumn
 
Methods inherited from class org.dellroad.stuff.schema.AbstractSchemaUpdater
applyInTransaction, generateMultiUpdateName, getUpdates, isIgnoreUnrecognizedUpdates, isValidUpdateName, setIgnoreUnrecognizedUpdates, setUpdates
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SpringSQLSchemaUpdater

public SpringSQLSchemaUpdater()
Method Detail

afterPropertiesSet

public void afterPropertiesSet()
                        throws Exception
Specified by:
afterPropertiesSet in interface InitializingBean
Throws:
Exception

setBeanFactory

public void setBeanFactory(BeanFactory beanFactory)
Specified by:
setBeanFactory in interface BeanFactoryAware

indicatesUninitializedDatabase

protected boolean indicatesUninitializedDatabase(Connection c,
                                                 SQLException e)
                                          throws SQLException
Determine if an exception thrown during SQLSchemaUpdater.databaseNeedsInitialization(java.sql.Connection) is consistent with an uninitialized database.

The implementation in SpringSQLSchemaUpdater looks for a BadSqlGrammarException.

Overrides:
indicatesUninitializedDatabase in class SQLSchemaUpdater
Parameters:
c - connection on which the exception occurred
e - exception thrown during database access in SQLSchemaUpdater.databaseNeedsInitialization(java.sql.Connection)
Throws:
SQLException - if an error occurs
See Also:
SQLSchemaUpdater.databaseNeedsInitialization(java.sql.Connection)

apply

protected void apply(Connection c,
                     DatabaseAction<Connection> action)
              throws SQLException
Apply a DatabaseAction to a Connection.

The implementation in SQLSchemaUpdater invokes the action and delegates to translate() to convert any SQLException thrown.

Overrides:
apply in class SQLSchemaUpdater
Throws:
SQLException - if an error occurs attempting to translate a thrown SQLException
DataAccessException - if an error occurs accessing the database
See Also:
translate()

translate

protected DataAccessException translate(SQLException e,
                                        Connection c,
                                        String sql)
                                 throws SQLException
Converts SQLExceptions into Spring DataAccessExceptions.

Throws:
SQLException

getOrderingTieBreaker

protected Comparator<SchemaUpdate<Connection>> getOrderingTieBreaker()
Get the preferred ordering of two updates that do not have any predecessor constraints (including implied indirect constraints) between them.

In the case no schema updates are explicitly configured, the Comparator returned by the implementation in SpringSQLSchemaUpdater sorts updates in the same order that they appear in the containing ListableBeanFactory. Otherwise, the superclass method is used.

Overrides:
getOrderingTieBreaker in class AbstractSchemaUpdater<DataSource,Connection>
Returns:
a Comparator that sorts incomparable updates in the order they should be applied