自动化数据库更新
2012-03-13 13:23 康杜 阅读(749) 评论(0) 编辑 收藏 举报简介
在我们的开发和运维过程中,通常会维护不同的数据库。由于在某个时间点,各个数据库的结构和状态是不一样的,所以我们开发人员需要在不同的数据库中运行相同的数据库脚本(SQL),比如我们修改了某个字段的长度并编写了一段SQL语句,我们需要在开发数据库、测试数据库、客户测试数据库、生产数据库中运行这段相同的SQL脚本。重复的工作不仅增加我们的工作量同时还增加我们出错的机会。
为了让我们的工作更加轻松,我们需要通过某种自动化的手段来解决这个问题。本文就我在工作中的做法进行阐述。
解决方案
自动化编译服务器+自动化数据库脚本。 在这种方案下,每个数据库都知道它自己已经运行了什么样的数据库脚本。通过在数据库中维护表DB_SCRIPT来解决,如下面表所示
SQL> desc DB_SCRIPT; Name Type Nullable Default Comments -------- ------------- -------- ------- -------- ID NUMBER(9) EXE_DATE DATE Y sysdate VERSION VARCHAR2(20) Y REMARK VARCHAR2(800) Y
在build-all工程里,我们按照日期加编号的形式添加数据库脚本。
然后DbScript.groovy将查询数据库,根据当前数据库所运行的SQL语句来决定在build-all功能中哪些数据库SQL语句应该运行。具体的Groovy脚本请看下节。
Groovy脚本
import groovy.sql.*;
def sql = Sql.newInstance("jdbc:oracle:thin:@192.168.141.128:1521:orcl", "root","111111", "oracle.jdbc.driver.OracleDriver")sql.withTransaction {def createDBScriptTableClosure = {row ->if (row[0] == 0){
//如果找不到表'DB_SCRIPT', 那么就建立一个表
println '数据库没有表DB_SCRIPT, 现在建立一个表'def createSeq = "CREATE SEQUENCE DB_SCRIPTSEQ INCREMENT BY 1 START WITH 1 MAXVALUE 99999"
sql.execute createSeqdef creatTableSql = "create table DB_SCRIPT(ID number(9) primary key not null, EXE_DATE date default sysdate, VERSION varchar2(20), REMARK varchar2(800))";
sql.execute creatTableSql}}sql.eachRow("select count(*) from tab where tname ='DB_SCRIPT'", createDBScriptTableClosure)
}//最后执行的SQL语句
def lastExecutedSqlsql.withTransaction {def firstRow = sql.firstRow("SELECT VERSION FROM DB_SCRIPT WHERE ID = (SELECT MAX(ID) FROM DB_SCRIPT)")
if (firstRow !=null ){lastExecutedSql = firstRow.getAt(0)}}//把dbscript目录中的脚本缓存起来下来
def scripts = [:]def maxFile = ''Thread.currentThread().getContextClassLoader().getResource("").each {it ->new File(it.getPath()+"\\dbscript").eachFile {//把所有SQL文件放到MAP中
file ->def currentFileName = file.getName()scripts.put currentFileName, fileif (currentFileName > maxFile){
maxFile = currentFileName}}}def insertSql = "INSERT INTO DB_SCRIPT(ID, VERSION, REMARK) values(DB_SCRIPTSEQ.NEXTVAL, ?, ?)"
def keys = scripts.keySet().sort()def sqlExecutionClosure = {key ->println keydef sqlFile = scripts.get(key)def sqlCommand = sqlFile.textdef sqlCds = sqlCommand.split(';')sqlCds.each {sqlCd ->println 'executing ' + sqlCdsql.execute sqlCd}sql.execute insertSql, [key, sqlCommand]}//如果还没有语句执行
sql.withTransaction{if (lastExecutedSql == null) {println '在这个数据库中还没有任何数据库补丁脚本运行,将依次运行如下脚本'keys.each {key ->sqlExecutionClosure(key)}}else{
keys.each {key ->println lastExecutedSqlif (key > lastExecutedSql){
sqlExecutionClosure(key)}}}}