有同事问到如何用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