有同事問到如何用caché數據庫連到Mysql數據,並且調用Mysql數據庫中的存儲過程,開始認爲mysql不可能爲m語言單獨寫驅動所以不能調用存儲過程。
在mysql官網可以看到mysql提供了以下幾種方式連接它,見下圖. (ODBC,NET,JDBC,Python,C++,C,PHP) 確實沒有M語言的連接驅動。
後面領導說可以看看sql gateway,去研究了下,發現caché有界面來配置SQL Gateway Settings界面,進入方式System Management Portal--Home>Configuration>Object/SQL Gateway Settings-SQL Gateway Connections,界面可以Create New Connection.
創建connection得先有數據庫,所以第一步安裝mysql數據庫
1. 下載mysql數據庫安裝程序,可以點這裏下載Mysql
安裝好後,在開始菜單框內輸入cmd,在cmd.exe上右鍵以管理員身份運行。
//開啓mysql服務
C:\Windows\system32>net start mysql
MySQL 服務正在啓動 ..............
MySQL 服務已經啓動成功。
//進入mysql數據庫, 默認用戶名root , 密碼爲空
C:\Windows\system32>mysql -h localhost -u root -p
Enter password:
//切換到test數據庫下
mysql>show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.06 sec)
mysql> use test;
Database changed
//建立測試表 dhc_user,並插入數據,在這就不一貼過程,最終查詢出來的樣子是
mysql>
select * from dhc_user;
+--------+------+-------+
| name | age | phone |
+--------+------+-------+
| w | 12 | NULL |
| h | 13 | NULL |
| wanghc | 11 | |
| wanghc | 12 | |
| wanghc | 13 | |
+--------+------+-------+
5 rows in set (0.09 sec)
//寫一get_age存儲過程, 通過name查詢age
mysql>
DELIMITER //
mysql> CREATE PROCEDURE get_age(n VARCHAR(50))
-> BEGIN
-> SELECT age from dhc_user where name=n;
-> END //
Query OK, 0 rows affected (0.07 sec)
mysql> DELIMITER ;
// 調用下get_age,能通過
mysql> call get_age("wanghc")
-> ;
+------+
| age |
+------+
| 11 |
| 12 |
| 13 |
+------+
3 rows in set (0.07 sec)
Query OK, 0 rows affected (0.07 sec)
2. 下載Mysql數據的ODBC驅動,點這裏下載mysql的ODBC驅動
Caché數據庫通過ODBC連接時就用到了驅動,
安裝好後,在開始菜單框內輸入odbc,打開數據源管理界面,在系統DSN界面中添加Mysql的DSN
3. 進入Home>Configuration>Object/SQL Gateway Settings-SQL Gateway Connections,界面可以Create New Connection界面,
點擊Test Connection,測試成功
4. 進入Home>SQL界面,選中DHC-APP名字空間,點擊Link Procedure Wizard
下一步,修改下包名與類型,生成一個
進入cahcé的terminal運行
DHC-APP>d ##class(web.test.mysql.DHCUser)."get_age"("wanghc")
運行會報錯,說mysql語法錯誤,看了下生成的"get_age"方法,生現call後面語句有問題,
DHC-APP>d
##class(web.test.mysql.DHCUser)."get_age"("wanghc")
沒有報錯,但也看不到返回值,進入Home>SQL 用call nullschema.get_age("wanghc")只說count是三條,看不到記錄。用sqldbx工具運行call nullschema.get_age("wanghc")倒是可以看到三條記錄與mysql內看到的一樣。應該是caché自身的SQL沒有從
5. 不用系統生成類方法,自己編寫.
ClassMethod Call(name) As %Status
{
set gc=##class(%SQLGatewayConnection).%New()
If gc=$$$NULLOREF quit $$$ERROR($$$GeneralError,"Cannot create %SQLGatewayConnection.")
//Make connection to target DSN
s pDSN="mysqltest"
s usr="root"
s pwd=""
set sc=gc.Connect(pDSN,usr,pwd,0)
If $$$ISERR(sc) quit sc
if gc.ConnectionHandle="" quit $$$ERROR($$$GeneralError,"Connection failed")
set sc=gc.AllocateStatement(.hstmt)
if $$$ISERR(sc) quit sc
set pQuery= "{call test.get_age(?)}"
set sc=gc.Prepare(hstmt,pQuery)
if $$$ISERR(sc) quit sc
set sc = gc.BindParameter(hstmt,1,1,1,12,25,0,25)
set sc = gc.SetParameter(hstmt,$lb(name),1)
//Execute statement
set sc=gc.Execute(hstmt)
if $$$ISERR(sc) quit sc
//Get list of columns returned by query
set sc=gc.DescribeColumns(hstmt, .columnlist)
if $$$ISERR(sc) quit sc
//display column headers delimited by ":"
set numcols=$listlength(columnlist)-1 //get number of columns
for colnum=2:1:numcols+1 {
Write $listget($listget(columnlist,colnum),1),":"
}
write !
//Return first 200 rows
set sc=gc.Fetch(hstmt)
if $$$ISERR(sc) quit sc
s rownum=1
while((gc.sqlcode'=100) && (rownum<=200)) {
for ii=1:1:numcols {
s sc=gc.GetData(hstmt, ii, 1, .val)
w " "_val
if $$$ISERR(sc) break
}
s rownum=rownum+1
write !
set sc=gc.Fetch(hstmt)
if $$$ISERR(sc) break
}
//Close cursor and then disconnect
set sc=gc.CloseCursor(hstmt)
if $$$ISERR(sc) quit sc
set sc=gc.Disconnect()
Quit sc
}
age:
11
12
13
ClassMethod MCall(name)
{
Set DLLName=$g(^%SYS("bindir"))_$s($$$isWINDOWS:"cgate.dll",$$$isUNIX:"cgate.so",$$$isVMS:"cgate.exe",1:"cgate.dll")
Set DLLHandle = $zf(-4,1,DLLName)
Set ConnectionHandle = $zf(-5,DLLHandle,45,"mysqltest","root","",15)
Set hstmt=$zf(-5,DLLHandle,5,ConnectionHandle)
Set sqlcode=$zf(-5,DLLHandle,3,hstmt,"{call test.get_age(?)}") ; Prepare=3
Set sqlcode=$zf(-5,DLLHandle,62,hstmt,1,1,1,12,25,0,25)
Set sqlcode=$zf(-5,DLLHandle,9,hstmt,$lb(name),1)
Set sqlcode=$zf(-5,DLLHandle,4,hstmt) ; Execute=4
;Set %ROWCOUNT=$zf(-5,DLLHandle,31,hstmt)
;Write "%ROWCOUNT=",%ROWCOUNT,!
Set sqlcode=$zf(-5,DLLHandle,7,hstmt) ;Fetch=7
while (sqlcode'=100){
Set val = $zf(-5,DLLHandle,25,hstmt, 1, 1) ;GetData=25
Write val,!
Set sqlcode=$zf(-5,DLLHandle,7,hstmt) ;Fetch=7
}
}
在teminal內運行下11
12
13
類代碼xml見附件,本地庫是2010.2.8