連鎖軟件中,數據庫結構不外兩種,一種是所有數據都放同一個數據庫,包括總部,另一種是總部獨立數據庫,每個分店一個數據庫,而我常用的就是獨立的數據庫。
這兩種方法各有優勢,數據放同一個數據庫,各分店之間數據進行交互時會非常方便,有統計之類的,也是直接在數據庫上操作,沒那麼多麻煩,不好的地方就是,數據一多,不便於維護,也得去考慮分頁等問題。而第二個方法就是剛上和第一個的好壞相反,但是我覺得分開的話數據會非常清晰,維護方便,當然這只是針對我們軟件數據庫之間交互不多的情況,可能有的數據庫之間交互數據比較頻繁,就是用第一個方法,沒有什麼維護問題,也會選擇第一,各有好壞,看各人使用。
獨立數據庫就得處理創建分店時怎麼創建數據庫的問題,因爲軟件是一直在更新的,也就是數據庫也是一直更新,所以創建分店數據庫,也必須是靈活的。
(Mssql)最早用的的方法:會在總部放一個數據庫的備份文件(Bak),每次更新就是覆蓋Bak文件,而創建數據庫的思路,1.把model數據庫備份成model.bak,2.把bak文件還原到model中,3.直接用create database 語句就可以建一個分店數據庫了,4.用model.bak還原回model數據庫,【注意:創建數據庫時,都會以model數據庫模版來創建,這裏正是利用這個】
這個方法是可以實現創建分店,但是比較笨,每次更新都要在更新文件里加個數據庫bak文件,而且數據庫都一直在增大,雖然是空數據庫,只有表結構等這些東西,但也得8M+,這在更新時帶來很多麻煩,於是後面又想到一個方法,在原有基礎上改進。
(Mssql)改進的方法:1.在安裝軟件時,會在mssql server上創建一個模版數據庫,這個模版數據庫也可以看作一個分店的數據庫,軟件更新時,會更新這個數據庫,更新完會備份這個模版數據庫,覆蓋總部中的Bak文件,後面創建分店時怎麼創建數據庫的還是沒變,和上面一樣。這裏改進的主要就是數據庫模版問題,這樣做的話,就不用每次更新帶上數據庫文件了。
最初的軟件就一直使用這個方法到現在。
最近有一套新軟件,在數據庫的設計上又是遇到這問題,我總覺得改進過的方法也不是很方便,於是又想到下面的改進方法。
1.保持使用模版數據庫,模版數據庫隨分店的更新一同更新,Bak文件使用不上了,作廢。2.在創建分店時,先創建一個空的數據庫,然後通過程序讀取模版數據庫的所有結構到新數據庫上執行,簡單點說就是通過程序來複制模版數據庫的所有結構。
這樣就不用再使用Bak那樣的笨重文件了,而且數據庫可以獨立一個服務器,老方法是數據庫和軟件必須同一個服務器,因爲要依賴放在總部裏的Bak文件,而現在數據庫和軟件就可以脫離,模版數據庫保護最新,分店創建新數據庫複製模版數據庫的結構,問題都解決 了。
隨帶說一下Mysql,因爲我們軟件是兼容多種數據庫的,Mysql也是其中,前期mysql和mssql的思路是一樣的,都是通過更新數據庫文件,用數據庫備份文件來創建新數據庫,後面Mysql也改成這種最優的方法:1.軟件安裝完,自動創建一個模版數據庫,2.創建新分店時,會把數據庫備份成sql文件,再在程序中修改sql文件中的數據庫名稱,3.執行sql文件。這裏mysql和mssql不一樣的地方就是,mssql的複製表結構,必須一個一個去模版數據讀出來再在新數據庫上執行,而mysql的備份就是導出數據庫的所有結構,我們只需要修改一個數據庫名稱爲新的數據庫執行。
下面附上C#裏複製數據庫的方法:
public void InitialData(string ModelDataBaseName, string DataBaseName)
{
#region 處理表和表數據
string strSql_GetUserTable = string.Format("select * from {0}.dbo.GetUserTable order by id,columnsort ", ModelDataBaseName);
DataTable dt_GetUserTable = dbHelper.ExecuteQuery(CommandType.Text, strSql_GetUserTable, null).Tables[0];
if (dt_GetUserTable.Rows.Count > 0)
{
//id,tablename,columnsort,columnname,tablekey,columndatatype,columndatalen1
//columndatalen2,columndatafloat,allowisnull,defaultdata
string tableName = "";
StringBuilder strCreateTableSql = new StringBuilder();
StringBuilder strKeySql = new StringBuilder();
StringBuilder strInsertData = new StringBuilder();
foreach (DataRow dr in dt_GetUserTable.Rows)
{
if (dr["tablename"].ToString() != tableName)
{
if (!string.IsNullOrEmpty(strCreateTableSql.ToString()))
{
if (strKeySql.Length > 0)
{
strKeySql.Remove(strKeySql.Length - 1, 1);
strCreateTableSql.AppendFormat(" PRIMARY KEY CLUSTERED ( {0} )) ON [PRIMARY] ", strKeySql.ToString());
strKeySql.Remove(strKeySql.Length - 1, 1);
}
else
{
if (strCreateTableSql.ToString().EndsWith(","))
strCreateTableSql.Remove(strCreateTableSql.Length - 1, 1);
strCreateTableSql.Append(" )");
}
dbHelper.ExecuteNonQuery(DataBaseName, strCreateTableSql.ToString(), null);
dbHelper.ExecuteNonQuery(CommandType.Text, string.Format(" insert into {0}.dbo.{1} select * from {2}.dbo.{1} ", DataBaseName, tableName, ModelDataBaseName), null);
}
tableName = dr["tablename"].ToString();
strCreateTableSql.Clear(); strCreateTableSql = new StringBuilder();
strKeySql.Clear(); strKeySql = new StringBuilder();
strCreateTableSql.AppendFormat(" create table {0} (", tableName);
}
strCreateTableSql.Append(dbHelper.GetDataType(dr["columnname"].ToString(),dr["columndatatype"].ToString(), dbHelper.GetInt(dr["columndatalen2"].ToString()),
dbHelper.GetInt(dr["columndatafloat"].ToString()), dr["allowisnull"].ToString(), dr["tablekey"].ToString(),ref strKeySql));
}
if (!string.IsNullOrEmpty(strCreateTableSql.ToString()))
{
if (strKeySql.Length > 0)
{
strKeySql.Remove(strKeySql.Length - 1, 1);
strCreateTableSql.AppendFormat(" PRIMARY KEY CLUSTERED ( {0} )) ON [PRIMARY] ", strKeySql.ToString());
strKeySql.Remove(strKeySql.Length - 1, 1);
}
else
{
if (strCreateTableSql.ToString().EndsWith(","))
strCreateTableSql.Remove(strCreateTableSql.Length - 1, 1);
strCreateTableSql.Append(" )");
}
dbHelper.ExecuteNonQuery(DataBaseName, strCreateTableSql.ToString(), null);
dbHelper.ExecuteNonQuery(CommandType.Text, string.Format(" insert into {0}.dbo.{1} select * from {2}.dbo.{1} ", DataBaseName, tableName, ModelDataBaseName), null);
}
}
#endregion
#region 存儲過程、視圖、函數、觸發器
StringBuilder strSql = new StringBuilder();
strSql.AppendFormat(" select name,type,definition from {0}.dbo.GetUserPV ",ModelDataBaseName);
DataTable dt_GetUserPV = dbHelper.ExecuteQuery(CommandType.Text, strSql.ToString(), null).Tables[0];
if (dt_GetUserPV.Rows.Count > 0)
{
StringBuilder strTest = new StringBuilder();
foreach (DataRow dr in dt_GetUserPV.Rows)
{
dbHelper.ExecuteNonQuery(DataBaseName, string.Format("{0}", dr["definition"].ToString()), null);
}
}
#endregion
}