標籤:
都說Hibernate架構的使用可以很容易的讓你的研發平台支援多種不同類型的資料庫,但實踐表明,這裡的“容易”,是相對的。
想讓研發平台支援多種資料庫,並不是一件簡單的事,也可以這麼說:並不是只要使用了Hibernate架構就能實現的。
下面記錄一下我做這件事情的過程和一些感悟。
當我接到該任務時,我先大致的理了一下思路:
要完成遷移,總體上有2大塊工作要做,分別是:資料庫層面的遷移 和 平台底層代碼的改造
一、資料庫層面的遷移過程:
1、通過sqlServer Studio2008 工具將資料從Oracle匯入到SqlServer資料庫
從SSMS2008開始才支援此功能,具體操作步驟(右鍵點擊資料庫-選擇匯入-點下一步-選擇 Oracle Provider for OLE DB 資料來源-點擊屬性-填寫資料來源,格式為 IP:連接埠/執行個體名),後面的步驟根據嚮導一步步的操作即可。需要注意的是在 選擇源表和源視圖的步驟中:
(1)、要把【目標】列中的預設首碼去掉,這樣匯入的表才會預設關聯到dbo下,否則你每次查詢表都要帶上schema首碼,導致你之前的應用程式中的sql無法執行,因為你之前寫的那些sql肯定不會帶這種首碼。
(2)、先勾選你要匯入的源,然後雙擊每一行記錄,在彈出的對話方塊中檢查是否所有的類型都正確綁定好了,我在檢查的時候就遇到了oracle中是varchar2類型的,在該對話方塊顯示的表結構中變成了130,只能手動的去將所有130改成varchar類型(sqlserver裡沒有varchar2類型)。還有原來是clob類型的,現在變成了varchar,要手動改成text類型(因為clob類型的欄位比較少,所以可以通過在oracle中執行“select * from user_tab_columns c where c.data_type=‘CLOB‘;”來查看哪些表中用到了CLOB類型的欄位)。
2、增加to_date、to_char、to_number、concat等常用的函數
說明:我在編寫to_date函數的時候,只提供了一種格式“yyyy-mm-dd HH:mi:ss”,這是因為在sqlserver中是沒有和to_date函數的類似的函數的,只能使用convert函數實現,但是convert函數不支援傳入格式化字串,只能傳入格式字元對應的整型數字,而120對應的正是之前提到的“yyyy-mm-dd HH:mi:ss”格式;另外此次是遷移到Sqlserver2005,該版本是沒有內嵌concat函數的,根據官方文檔的說法,是從sqlServer2012開始才有concat函數的,所以這裡我要自己編寫一個concat函數。
------------------------------------------------------------------concat函數USE [skyplatform]GO/****** Object: UserDefinedFunction [dbo].[concat] Script Date: 03/10/2015 17:11:31 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [dbo].[concat](@param1 varchar(500),@param2 varchar(500))returns varchar(1000)asbeginDECLARE @returntext varchar(1000) if (@param1 is null) SELECT @returntext= @param2; else if (@param2 is null) SELECT @returntext= @param1; else SELECT @returntext= @param1 + @param2; return @returntext;end--------------------------------------------------------------------to_char函數USE [skyplatform]GO/****** Object: UserDefinedFunction [dbo].[to_char] Script Date: 03/10/2015 17:12:09 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [dbo].[to_char](@param1 datetime,@param2 varchar(20))returns varchar(20)asbeginreturn convert(varchar(20),@param1,120) end--------------------------------------------------------------------to_date函數USE [skyplatform]GO/****** Object: UserDefinedFunction [dbo].[to_date] Script Date: 03/10/2015 17:12:58 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [dbo].[to_date](@param1 varchar(20),@param2 varchar(20))returns datetimeasbeginreturn convert(datetime,@param1,120)--120 means that yyyy-mm-dd hh:mi:ss(24h) end--------------------------------------------------------------------to_number函數USE [skyplatform]GO/****** Object: UserDefinedFunction [dbo].[to_number] Script Date: 03/10/2015 17:13:09 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [dbo].[to_number](@param1 varchar)returns numericasbeginreturn convert(numeric,@param1) end
二、平台底層代碼的改造
1、引入SqlServer的jar包:sqljdbc4-4.0.jar
<groupId>com.microsoft.sqlserver</groupId><artifactId>sqljdbc4</artifactId><version>4.0</version>
2、修改db.properties中關於資料庫連接資訊的配置
jdbc.dialect=org.hibernate.dialect.SQLServerDialectjdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriverjdbc.url=jdbc:sqlserver://xx.xx.xx.xx:1433;DatabaseName=xxxjdbc.default_schema=dbojdbc.username=xxxjdbc.password=xxx
3、修改平台中使用的一些非sql標準的文法
在使用delete insert update這些dml語句的時候,切記不要使用別名,因為在oracle和sqlserver中,這些dml語句使用別名的文法是不一樣的。
4、各實體類主鍵策略的改造
最好都使用string類型的主鍵,但是因為之前的代碼中都用的sequence做主鍵策略,現在改成string類型工作量勢必很大,所以決定使用table策略來相容各種資料庫。
5、dao層對sql的處理
由於sqlserver中調用自訂純量值函式,必須在函數名前加上dbo.的首碼,但是這樣寫勢必會導致不能相容其它的關係型資料庫,所以只能從dao實現層,對sql進行統一的處理,處理規則就是:如果當前資料庫是sqlserver,並且sql中出現了concat、to_date、to_char、to_number等函數,就為這些函數名加上dbo.的首碼。
以上做完,基本就可以讓平台在sqlserver資料庫上跑了,同時也可以通過改設定檔切換到Oracle資料庫。
以上的做法可能並不是最優的方式,如果有更好的方案,希望各位大牛能給予指點。
採用Hibernate架構的研發平台如何能夠真正相容Oracle和sqlServer資料庫