xiejun
2024-11-01 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a
Source/BladeX-Tool/blade-starter-flowable/src/main/java/org/flowable/common/engine/impl/db/LiquibaseBasedSchemaManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,191 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.flowable.common.engine.impl.db;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.common.engine.impl.context.Context;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.SQLException;
/**
 * @author Filip Hrisafov
 */
public abstract class LiquibaseBasedSchemaManager implements SchemaManager {
   protected final Logger logger = LoggerFactory.getLogger(getClass());
   protected final String context;
   protected final String changeLogFile;
   protected final String changeLogPrefix;
   public LiquibaseBasedSchemaManager(String context, String changeLogFile, String changeLogPrefix) {
      this.context = context;
      this.changeLogFile = changeLogFile;
      this.changeLogPrefix = changeLogPrefix;
   }
   public void initSchema(String databaseSchemaUpdate) {
      try {
         if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP.equals(databaseSchemaUpdate)) {
            schemaCreate();
         } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE.equals(databaseSchemaUpdate)) {
            schemaDrop();
            schemaCreate();
         } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE.equals(databaseSchemaUpdate)) {
            schemaUpdate();
         } else if (AbstractEngineConfiguration.DB_SCHEMA_UPDATE_FALSE.equals(databaseSchemaUpdate)) {
            //取消自检查
            //schemaCheckVersion();
         }
      } catch (Exception e) {
         throw new FlowableException("Error initialising " + context + " data model", e);
      }
   }
   @Override
   public void schemaCreate() {
      Liquibase liquibase = null;
      try {
         liquibase = createLiquibaseInstance(getDatabaseConfiguration());
         liquibase.update(context);
      } catch (Exception e) {
         throw new FlowableException("Error creating " + context + " engine tables", e);
      } finally {
         closeDatabase(liquibase);
      }
   }
   @Override
   public void schemaDrop() {
      Liquibase liquibase = null;
      try {
         liquibase = createLiquibaseInstance(getDatabaseConfiguration());
         liquibase.dropAll();
      } catch (Exception e) {
         throw new FlowableException("Error dropping " + context + " engine tables", e);
      } finally {
         closeDatabase(liquibase);
      }
   }
   @Override
   public String schemaUpdate() {
      Liquibase liquibase = null;
      try {
         liquibase = createLiquibaseInstance(getDatabaseConfiguration());
         liquibase.update(context);
      } catch (Exception e) {
         throw new FlowableException("Error updating " + context + " engine tables", e);
      } finally {
         closeDatabase(liquibase);
      }
      return null;
   }
   @Override
   public void schemaCheckVersion() {
      Liquibase liquibase = null;
      try {
         liquibase = createLiquibaseInstance(getDatabaseConfiguration());
         liquibase.validate();
      } catch (Exception e) {
         throw new FlowableException("Error validating " + context + " engine schema", e);
      } finally {
         closeDatabase(liquibase);
      }
   }
   protected abstract LiquibaseDatabaseConfiguration getDatabaseConfiguration();
   protected Liquibase createLiquibaseInstance(LiquibaseDatabaseConfiguration databaseConfiguration) throws SQLException {
      Connection jdbcConnection = null;
      boolean closeConnection = false;
      try {
         CommandContext commandContext = Context.getCommandContext();
         if (commandContext == null) {
            jdbcConnection = databaseConfiguration.getDataSource().getConnection();
            closeConnection = true;
         } else {
            jdbcConnection = commandContext.getSession(DbSqlSession.class).getSqlSession().getConnection();
         }
         // A commit is needed here, because one of the things that Liquibase does when acquiring its lock
         // is doing a rollback, which removes all changes done so far.
         // For most databases, this is not a problem as DDL statements are not transactional.
         // However for some (e.g. sql server), this would remove all previous statements, which is not wanted,
         // hence the extra commit here.
         if (!jdbcConnection.getAutoCommit()) {
            jdbcConnection.commit();
         }
         DatabaseConnection connection = new JdbcConnection(jdbcConnection);
         Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
         database.setDatabaseChangeLogTableName(changeLogPrefix + database.getDatabaseChangeLogTableName());
         database.setDatabaseChangeLogLockTableName(changeLogPrefix + database.getDatabaseChangeLogLockTableName());
         String databaseSchema = databaseConfiguration.getDatabaseSchema();
         if (StringUtils.isNotEmpty(databaseSchema)) {
            database.setDefaultSchemaName(databaseSchema);
            database.setLiquibaseSchemaName(databaseSchema);
         }
         String databaseCatalog = databaseConfiguration.getDatabaseCatalog();
         if (StringUtils.isNotEmpty(databaseCatalog)) {
            database.setDefaultCatalogName(databaseCatalog);
            database.setLiquibaseCatalogName(databaseCatalog);
         }
         return new Liquibase(changeLogFile, new ClassLoaderResourceAccessor(), database);
      } catch (Exception e) {
         // We only close the connection if an exception occurred, otherwise the Liquibase instance cannot be used
         if (jdbcConnection != null && closeConnection) {
            jdbcConnection.close();
         }
         throw new FlowableException("Error creating " + context + " liquibase instance", e);
      }
   }
   protected void closeDatabase(Liquibase liquibase) {
      if (liquibase != null) {
         Database database = liquibase.getDatabase();
         if (database != null) {
            // do not close the shared connection if a command context is currently active
            if (Context.getCommandContext() == null) {
               try {
                  database.close();
               } catch (DatabaseException e) {
                  logger.warn("Error closing database for {}", context, e);
               }
            }
         }
      }
   }
}