原Oracle數據庫的項目同時兼容MySql步驟:
(一)修改資源配置文件applicationContext-dataSource.xml的數據庫連接
Oracle數據庫中加上from dual的原因:Oracle數據庫中自帶了一個虛擬表dual,這個的作用是測試數據庫是否正常使用。
(二)添加一個類用於獲取資源配置文件中當前使用的數據庫類型以及該方法繼承SqlMapClientDaoSupportExtend類,如果需要更多的方法,可以自行根據實際情況進行添加:
public class BaseDao extends SqlMapClientDaoSupportExtend{ @Autowired private DruidDataSource dataSource; public Object queryForObject(String statementName){ return this.queryForObject(statementName, new HashMap()); } /** * 查詢時並攜帶當前連接池數據庫類型作為參數 * @param statementName * @param parameterMap * @return */ public Object queryForObject(String statementName,Map parameterMap){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForObject(statementName, parameterMap); } public Object queryForObject(String statementName,Map parameterMap,Object resultObject){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForObject(statementName, parameterMap, resultObject); } /** * 查詢時並攜帶當前連接池數據庫類型作為參數 * @param statementName * @param parameterMap * @return */ public List queryForList(String statementName){ return this.queryForList(statementName, new HashMap()); } public List queryForList(String statementName,Map parameterMap){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForList(statementName, parameterMap); } public List queryForList(String statementName, int skipResults, int maxResults){ return this.queryForList(statementName, new HashMap(), skipResults, maxResults); } public List queryForList( final String statementName, final Map parameterMap, final int skipResults, final int maxResults){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForList(statementName, parameterMap, skipResults, maxResults); } public Map queryForMap( final String statementName, final Map parameterMap, final String keyProperty){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForMap(statementName, parameterMap, keyProperty); } public Map queryForMap( final String statementName, final Map parameterMap, final String keyProperty, final String valueProperty){ setDbType(parameterMap); return getSqlMapClientTemplate().queryForMap(statementName, parameterMap, keyProperty,valueProperty); } public int update(String statementName){ return update(statementName, new HashMap()); } public int update(final String statementName, final Map parameterMap){ setDbType(parameterMap); return getSqlMapClientTemplate().update(statementName, parameterMap); } public int delete(String statementName) throws DataAccessException { return delete(statementName, new HashMap()); } public int delete(final String statementName, final Map parameterMap){ setDbType(parameterMap); return getSqlMapClientTemplate().delete(statementName, parameterMap); } /** * 獲取數據庫類型 * @param parameterMap */ private void setDbType(final Map<String, Object> parameterMap) { String dataUrl = dataSource.getUrl(); dataUrl = dataUrl.substring(dataUrl.indexOf(":")+1); dataUrl = dataUrl.substring(0,dataUrl.indexOf(":")); parameterMap.put("dataBase", dataUrl); } }
詳細說明:
(1)DruidDataSource類的自動裝配
這個DruidDataSource類的來源就是要跟配置文件數據庫連接池的名字一致,這個就是阿里巴巴開源的Druid連接池
(2)獲取連接池里面的屬性值url里面的字段,即截取出相應的數據庫類型
執行過程分析:
String dataUrl = dataSource.getUrl();
獲取到的值是:dataUrl="jdbc:oracle:thin:@192.168.0.153:1521:OANET"
dataUrl = dataUrl.substring(dataUrl.indexOf(":")+1);
獲取到的值是:dataUrl=oracle:thin:@192.168.0.153:1521:OANET,dataUrl.indexOf(":")+1值就是5,即從下標5開始截取
dataUrl = dataUrl.substring(0,dataUrl.indexOf(":"));
獲取到的值是:dataUrl=oracle,截取部分開始下標為0,結束下標為第一個冒號的下標,但不包括下標為第一個冒號的下標的那個標,左閉右開
(3)繼承SqlMapClientDaoSupportExtend類,在每次寫方法的時候獲取當前的數據庫的類型,例如:
(4)如果正常來說,Sql腳本語言如果可以同時兼容MySql和Oracle的話就可以不用調用該類了,如果不能同時兼容的話就需要調用該類,其實該類的方法和SqlMapClientDaoSupportExtend類的區別就是傳遞多一個dataBase參數而已,這樣當我們我們發現Sql腳本語言不能兼容同時兼容MySql和Oracle時,我們的類就需要先繼承我們寫的BaseDao類:
不能同時兼容,需先繼承我們寫好的BaseDao:
同時可以兼容,直接繼承SqlMapClientDaoSupportExtend類即可:
(5)Sql腳本語言不能同時兼容MySql和Oracle的時,修改Sql的文件如下:
(6)Sql腳本語言出現不兼容問題例子
第一步:修改該方法相應類的繼承,改成繼承BaseDao
第二步:修改BaseDao里面的方法,由於BaseDao里面的queryForObject方法里不能傳String參數過去,所以就用一個Map對象將String的值傳過去
未改前:
public ReserveInfoVO findOuternetReserveInfoByReserveSeq(String reserveSeq) { Object obj = this.getSqlMapClientTemplate().queryForObject("outernetReserveInfo.findOuternetReserveInfoByReserveSeq", reserveSeq); if(obj != null && obj instanceof ReserveInfoVO){ return (ReserveInfoVO)obj; } return null; }
修改后:
public ReserveInfoVO findOuternetReserveInfoByReserveSeq(String reserveSeq) { Map param=new HashMap(); param.put("reserveSeq", reserveSeq); Object obj=queryForObject("outernetReserveInfo.findOuternetReserveInfoByReserveSeq", param); if(obj != null && obj instanceof ReserveInfoVO){ return (ReserveInfoVO)obj; } return null; }
第三步:修改完后,由於傳遞的參數由String變成了Map類型,所以Sql語句那邊接收的參數要修改成Map,因為之前接受參數是用String的
Sql腳本語言兼容Oracle和MySql需要的注意點:
功能 | Oracle | MySql |
轉換成字符串類型 | TO_CHAR | DATE_FORMAT |
轉換成數值類型 | TO_NUMBER | CAST |
轉換成日期類型 | TO_DATE | STR_TO_DATE |
字符拼接 | || | CONCAT |
判斷字段是否為空,為空則返回0,反之返回本身 | NVL | IFNULL |
Desc做字段 | C."DESC" | C.DESC |
數據庫合並行記錄 | WMSYS.WM_CONCAT | GROUP_CONCAT |
條件判斷 | DECODE(NVL(1, 0), 0, 5, 1) | CASE IFNULL(1, 0) WHEN 0 THEN 5 ELSE 1 END |
BLOB數據轉換成字符串 | UTL_RAW.CAST_TO_VARCHAR2 | CAST |
將字符串類型轉換為blob類型 | TO_BLOB | CAST |
遞歸函數 | START WITH......CONNECT BY | 自定義函數再調用 |
通過表名獲取表的主鍵 | WHERE CU.CONSTRAINT_NAME = AU.CONSTRAINT_NAME AND AU.CONSTRAINT_TYPE = 'P' AND AU.TABLE_NAME = #tableName# |
WHERE table_name=#tableName# AND COLUMN_KEY='PRI' |
獲取系統當前時間 | SYSDATE | NOW() |
獲取一條數據 | rownum | limit |
刪除表數據 | delete(可用可不用表別名) | delete(不能用表別名) |
1、To_char:轉換成字符串類型
MySql中的date_format(date,'%Y-%m-%d') -------------->oracle中的to_char();
例子1:獲取當前系統時間
Mysql:SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%S');
Oracle: SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') FROM DUAL
2、To_date:轉換成日期類型
MySql中的str_to_date(date,'%Y-%m-%d') -------------->oracle中的to_date();
例1:
Mysql:select str_to_date('2004-05-07 13:23:44','%Y-%m-%d %H:%i:%s')
Oracle:select to_date('2004-05-07 13:23:44','YYYY-MM-DD HH24:MI:SS') from dual
3、To_number:轉換成數值類型如:To_number('1234.5'),結果:1234.5
例1:數字字符轉換成整型:
MySql:CAST(a.sort AS SIGNED)
Oracle:to_number(a.sort)
4、字符拼接
MySql中concat('%','abc','%')------------------------>oracle中的'%' || 'abc' || '%'
例1:
MySql:CONCAT('%','不公示','%')
Oracle:'%'|| '不公示' ||'%'
5、判斷字段是否為空,為空則返回0,反之返回本身:
MySql:select IFNULL('',0) from dual
Oracle:select nvl('',0) from dual
6、Desc做字段的區別:
desc字段---------------------->oracle中'desc'
MySql:
SELECT C.KEY, C.VALUE, C.DESC FROM LZCITY_APPROVE_CONFIG C WHERE C.KEY ='SEQ_TYPE'
Oracle:
SELECT C.KEY, C.VALUE, C."DESC" FROM LZCITY_APPROVE_CONFIG C WHERE C.KEY = 'SEQ_TYPE'
7、數據庫合並行記錄
Oracle:WMSYS.WM_CONCAT(需要合並字段)
MySql:GROUP_CONCAT(需要合並字段)
8、條件判斷:
Oracle:decode(nvl(1, 0), 0, 5, 1) from dual
MySql:case IFNULL(1, 0) when 0 then 5 else 1 end
原理:如果為1,則為0;如果為0,則為5;如果都不是則為1
9、BLOB數據轉換成字符串(Oracle自帶系統包utlraw將RAW轉為VARCHAR2)
Oracle:UTL_RAW.CAST_TO_VARCHAR2(H.IMG_BODY)
MySql:CAST(H.IMG_BODY AS CHAR)
10、將字符串類型轉換為blob類型
Oracle:to_blob(字段)
MySql:CAST(字段 AS BINARY)
11、遞歸函數例子,通過父節點找到所有的節點
因為MySql沒有start with......connect by,所以要自己寫一個自定義函數
MySql:
delimiter $$ CREATE FUNCTION appr_index_tree_test(menu_root VARCHAR(200)) RETURNS VARCHAR(1000) BEGIN DECLARE sTemp VARCHAR(1000); DECLARE sTempChd VARCHAR(1000); SET sTemp='$'; SET sTempChd=menu_root; WHILE sTempChd IS NOT NULL DO SET sTemp=CONCAT(sTemp,',',sTempChd); SELECT GROUP_CONCAT(seq_code) INTO sTempChd FROM appr_index_tree WHERE FIND_IN_SET(parent_seq_code,sTempChd)>0; END WHILE; RETURN sTemp; END $$ delimiter;
SELECT appr_index_tree_test(父節點)
Oracle:
start with seq_code= 父節點 connect by prior seq_code = parent_seq_code
12、通過表名獲取表的主鍵
MySql:
SELECT DISTINCT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=#tableName# AND COLUMN_KEY='PRI'
Oracle:
SELECT CU.COLUMN_NAME FROM USER_CONS_COLUMNS CU, USER_CONSTRAINTS AU WHERE CU.CONSTRAINT_NAME = AU.CONSTRAINT_NAME AND AU.CONSTRAINT_TYPE = 'P' AND AU.TABLE_NAME = #tableName#
注意:其他相似例子
(1)往前一天:
Mysql:(Mysql則需要調用DATE_SUB函數,反之往后一天DATE_ADD)
select STR_TO_DATE(CONCAT(DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 1 DAY), '%Y-%m-%d'),' 00:00:01'),'%Y-%m-%d %H:%i:%s')
Oracle:(Oracle直接在當前系統時間減一,反之往后一天加一)
select TO_DATE(TO_CHAR((SYSDATE-1), 'YYYY-MM-DD') || ' 00:00:01','YYYY-MM-DD HH24:MI:SS') FROM dual
(2)往前一個月:
Mysql:select DATE_SUB(NOW(),INTERVAL 1 MONTH)
Oracle:select ADD_MONTHS(SYSDATE, -1) FROM dual
(3)上一個月最后一天:
Mysql:select LAST_DAY(DATE_SUB(NOW(),INTERVAL 1 MONTH))
Oracle:select LAST_DAY(ADD_MONTHS(SYSDATE, -1)) FROM dual
(4)上一個月最后一天再加一天:
Mysql:select DATE_ADD(LAST_DAY(DATE_SUB(NOW(),INTERVAL 1 MONTH)),INTERVAL 1 DAY)
Oracle:select LAST_DAY(ADD_MONTHS(SYSDATE, -1))+1 FROM dual
(5)MySql中,兩個顯示當天時間的區別:
(1)select CURDATE()
(2)select NOW()
結果:(1)2017-02-15
(2)2017-02-15 22:10:36
(13)獲取查詢結果的一條數據
MySql:
select * from temp where LIMIT 1
Oracle:
select * from temp where rownum=1
(14)刪除表中的數據
MySql:
delete from temp where ...
Oracle:
delete from temp where ...
delete from temp p where ...