Ensemble(Cache)通過ODBC連接Mysql數據庫並調用其存儲過程

       有同事問到如何用caché數據庫連到Mysql數據,並且調用Mysql數據庫中的存儲過程,開始認爲mysql不可能爲m語言單獨寫驅動所以不能調用存儲過程。

     在mysql官網可以看到mysql提供了以下幾種方式連接它,見下圖. (ODBC,NET,JDBC,Python,C++,C,PHP) 確實沒有M語言的連接驅動。

      mysql連接方式

後面領導說可以看看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

dsnmysqldns

3. 進入Home>Configuration>Object/SQL Gateway Settings-SQL Gateway Connections,界面可以Create New Connection界面,

  

 點擊Test Connection,測試成功

4. 進入Home>SQL界面,選中DHC-APP名字空間,點擊Link Procedure Wizard

    

下一步,修改下包名與類型,生成一個web.test.mysql.DHCUser.cls類生成"get_age"方法

進入cahcé的terminal運行

 DHC-APP>d ##class(web.test.mysql.DHCUser)."get_age"("wanghc")

運行會報錯,說mysql語法錯誤,看了下生成的"get_age"方法,生現call後面語句有問題{call """".get_age(?)}改成{call test.get_age(?)},再運行

 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沒有從%sqlcontext內拿ResultSet顯示出來,只是顯示了SQLCODE與Message,ROWCOUNT。

5. 不用系統生成類方法,自己編寫. 

    看了下生成的代碼有個關鍵類%Library.SQLGatewayConnection,看了下他的api與例子,
    在web.test.mysql.DHCUser.cls內增加了個方法,沒有用portal>sql gateway settings,用了dsn連mysql,再去運行 test.get_age()
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
}
進入terminal運行下
DHC-APP>d ##class(web.test.mysql.DHCUser).Call("wanghc")
age:
 11
 12
 13
Call方法是用OOP寫的,再參考了下生成的"get_age"方法寫了另一MCall方法

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內運行下
DHC-APP>d ##class(web.test.mysql.DHCUser).MCall("wanghc")
11
12
13
也能出來結果。
MCall方法大量用到了$zf。$zf是調用的active dll有興趣的可以看下。
調用的是caché數據庫安裝目錄bin下的cgate.dll,通過這個dll再去調用dns。
 

類代碼xml見附件,本地庫是2010.2.8







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章