这个月总公司收购了一家小公司,这家小公司的数据库用的是32位的 Sql2000 ,已经使用很长一段时间了,系统也比较稳定。本着节约成本的原则,总公司保留原公司的一套管理系统,但要求重要数据每天上传到总公司的64位 Sql2005 数据库中去,这个简单的工作自然是交给我高升这样的小人物去完成了。
原想这是个很简单的差事,可是当我建好 LinkServer 以后却报出了如下错误,从此我的噩梦开始了:
OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "Unspecified error".
OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "The stored procedure required to complete this operation could not be found on the server. Please contact your system administrator.".
消息 7311,级别 16,状态 2,第 1 行
Cannot obtain the schema rowset "DBSCHEMA_TABLES_INFO" for OLE DB provider "SQLNCLI" for linked server "TEST_GAO". The provider supports the interface, but returns a failure code when it is used.
error 7311 : 安装在服务器"TEST_GAO" 的版本需要打升级吗?一查对方的服务器还是 sp3 的版本,于是下载了一个 sp4 的补丁,可是安装以后问题依旧。接着我又用自己的电脑上安装的 Sql2005 和远程的 Sql2000 建立了一个 LinkServer 测试了一下,结果很正常的就连上了,并且可以查询出数据。这个问题可真是奇怪了,难道发生了什么灵异事件?我自己的电脑和两台服务器都是安装的 windows server 2003 sp2 的操作系统,为什么同样是Sql2005我自己的就能连上,而服务器上的却不能连呢?
原来是因为32位的 Sql2000 升级到sp3或者sp4以后还需要手工执行补丁包内的 Instcat.sql 脚本才能连接上64位的 Sql2005 ,执行 cmd 进入命令行模式,输入如下语句,完成安装,这下 LinkServer 能够正常连接。
输入 : osql -U gaosheng -P sheng -S 127.0.0.1 -i C:/sql2ksp4/install/instcat.sql
-U:Sql2000的登陆名,要是具备管理权限的,最好是使用sa用户
-P:密码
-S:服务器名或IP地址
-i:脚本所在的路径及名称,注意大小写。
参考MSDN : http://support.microsoft.com/kb/906954/zh-tw
LinkServer 建好以后下一步就是查数据写数据了,Sql语句写起来是很简单,可是开启事务后又出现问题了:
OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "The partner transaction manager has disabled its support for remote/network transactions.".
消息 7391,级别 16,状态 2,第 1 行
The operation could not be performed because OLE DB provider "SQLNCLI" for linked server "TEST_GAO" was unable to begin a distributed transaction.
error 7391 : 这很显然由于开启了事务,需要分布式事务协调器的支持。打开控制面板 - 管理工具 - 服务,将两台服务器上的 Distributed Transaction Coordinator (MSDTC) 服务开启,注意 MSDTC 服务的登陆名必须选择 NETWORK SERVICE 用户。然后设置高级选项,运行 dcomcnfg.exe ,进入组件服务,选择我的电脑右键属性,MSDTC - 安全配置,勾选:网络DTC访问,允许入站,允许出站,并且不要求进行验证。其他的可以根据需要选择,不是必须选项。
OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "No transaction is active.".
消息 7391,级别 16,状态 2,第 1 行
The operation could not be performed because OLE DB provider "SQLNCLI" for linked server "TEST_GAO" was unable to begin a distributed transaction.
error 7391 : 怎么还是这个错误,没有活动事务,无法启动分布式事务?高级配置也做过了,并且已经不要求进行验证了,难道这样还是不行?那就麻烦了,两台服务器并不在同一个域中,这样怎么让他相互信任呢,那就需要配置hosts文件了。
C:/WINDOWS/system32/drivers/etc/hosts ,在系统目录下找到这个隐藏的hosts系统文件,在文件的末尾加上对方的IP地址和主机名,如果服务器是集群的还要加上cluster的地址和虚拟IP地址,如:
136.16.25.79 GAOSHENG_Cluster
136.16.25.40 GAOSHENG_V1
136.16.25.80 GAOSHENG_DB1
第一个是Cluster主机的IP和主机名,第二个是虚拟的IP和主机名,第三个才是真实地址,加上前两个地址是为了保证服务器宕机以后,Cluster做了故障转移LinkServer还能正常使用。如果不是集群服务器只需要第三个真实地址就行了,这样双方就能互相信任,正常使用分布式事务了。注意这个hosts文件两边都要配置的,配置的是对方的IP地址和文件名。
OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "Cannot start more transactions on this session.".
消息 7395,级别 16,状态 2,第 1 行
Unable to start a nested transaction for OLE DB provider "SQLNCLI" for linked server "TEST_GAO". A nested transaction was required because the XACT_ABORT option was set to OFF.
还来!怎么还是有错误啊?
error 7395 : 还好直接告诉我怎么做了,在 Begin Transaction 前加上 SET XACT_ABORT ON 即可。
现在总算是不抱错了,查询修改也没问题了,问题终于解决了。建一个简单的 LinkServer 居然就出现了这么多的问题,一方面是我学艺不精,另一方面反映出来的是平时都是单服务器的操作,很多问题根本就是遇不到的,光有理论是远远不够的。不过最后能够解决问题也反映出我解决问题的能力还是有的,搞不懂就问人,搞得懂就答人,没有人懂还可以问神。( MSDN 和 CSDN )
总结:
在实际工作中会出现各种各样的问题,老是在一台服务器上测试和学习得到的东西毕竟有限,所以下次遇到问题千万要自己学着解决,要多锻炼一下自己解决问题的能力吧。如果没有多个服务器的环境学习,我这里推荐一个个 Microsoft 软件 Virtual PC ,这个软件可以在一台电脑上模拟很多台电脑出来,有各自的IP,对我们学习多服务器的操作很有帮助。
程序员不光要会学代码,最重要的还是分析问题解决问题的能力,具备这些能力才能算是一个合格的程序员。当然多多交流也是很有必要的,但前提是有问题自己先动脑子去想,然后才去交流。我高升在这里也很希望能和丛多的程序员们多交流交流技术,虽然现在水平不高,但一点一点的积累总会有所成就的。
写两个初次使用 Sql Server 2005 远程连接时最容易报的错误,凑点字数。
OLE DB provider "SQLNCLI" for linked server "TEST" returned message "Login timeout expired".
OLE DB provider "SQLNCLI" for linked server "TEST" returned message "An error has occurred while establishing a connection to the server. When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections.".
Msg 65535, Level 16, State 1, Line 0
SQL Network Interfaces: Error Locating Server/Instance Specified [xFFFFFFFF].
这是新手在初次使用 Sql Server 2005 最最常见的一个错误,原因是默认的配置禁止了远程连接。很多对数据库不是很了解的人不了解如何去配置,所以 Sql Server 2005 提供了这个"外围应用配置器"中设置,把远程连接方式改成本地连接和远程连接,仅使用 TCP/IP ,注意这个选项改动以后是需要重启 SqlServer 的服务才能生效的。另外还有一个很重要的服务 SQL Server Browser ,开启了这个服务客户端才能正常访问。
Msg 15281, Level 16, State 1, Line 1
SQL Server blocked access to STATEMENT ‘OpenRowset/OpenDatasource‘ of component ‘Ad Hoc Distributed Queries‘ because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of ‘Ad Hoc Distributed Queries‘ by using sp_configure. For more information about enabling ‘Ad Hoc Distributed Queries‘, see "Surface Area Configuration" in SQL Server Books Online.
这个错误也是因为 Sql Server 2005 默认的配置的问题,默认关闭了使用 OpenRowset/OpenDatasource 的权限。解决也是在"外围应用配置器"中配置,将即席远程查询中的开启 OpenRowset/OpenDatasource 打勾。
当然这个也可以使用以下代码,执行如下代码:
sp_configure ‘show advanced options‘, 1; --开启高级配置
GO
RECONFIGURE;
GO
sp_configure ‘Ad Hoc Distributed Queries‘, 1; --开启即席查询
GO
RECONFIGURE;
GO
sp_configure ‘show advanced options‘, 0; --关闭高级配置
GO
RECONFIGURE;
GO
另外的一些基础配置:
1、关闭双方防火墙
2、启动双方MSDTC服务
3、事务开始前加入set xact_abort ON语句
4、管理工具――组件服务设置允许远程客户端、允许远程管理、允许入站、允许出站、不要求进行验证
5、DTC登陆账户为:NT Authority\NetworkService
6、服务器和名称解析,我这里直接用的ip地址应该不存在这个问题
下面是自己的一点经验:
一.上面的按照原来的做法 做到OLE DB provider "SQLNCLI" for linked server "TEST_GAO" returned message "No transaction is active.".这个地方就过不去了,折腾了一下午,最后用Dtcping.exe进行检测后发现问题,搞定。
具体的问题就是RCP拒绝访问,解决方法如下:
方法如下:
1.单击“开始”,单击“运行”,键入“gpedit.msc”,然后单击“确定”,打开组策略。
2.打开组策略后,选择“计算机配置->管理模板->系统->远过程调用->用于未验证的RPC客户端的限制”。
3.右键单击“用于未验证的RPC客户端的限制”,在弹出的右键菜单里选择“属性”,弹出“属性”对话框。在“设置”属性页里选择“已启用”,“要应用的RPC运行时未验证的客户端限制”选择“无”。单击“确定”完成设置。(这一步在windows server 2008中是双击用于未验证的RPC客户端的限制,然后打开相应配置,其他同此步的配置)
二.在配置host文件的时候主机名用ipconfig -all来确定。
下面是具体的代码
create trigger oppor_insert on [OpportunityBase] for insert --插入触发 as --定义变量 declare @id uniqueidentifier, @name varchar(300); --在inserted表中查询已经插入记录信息 select @id = [OpportunityId], @name = Name from inserted; insert into COMMONDB.common_opportunity values(@id, @name); print ‘添加成功!‘; go
create trigger oppor_insert on [Opportunity] for insert --插入触发 as --定义变量 declare @id uniqueidentifier, @name varchar(300); --在inserted表中查询已经插入记录信息 select @id = [OpportunityId], @name = Name from inserted; SET XACT_ABORT ON begin distributed tran insert into REMOTESERVER.CommonDB.dbo.common_opportunity(id,name) values(@id, @name); commit tran print ‘添加成功!‘; go