SqlServer调用外部程序实现数据同步
2016-03-03 09:22
435 查看
FreeSaber
不自见故明,不自是故彰,不自伐故有功,不自矜故长.夫唯不争,故天下莫能与之争.
博客园
博问
闪存
新随笔
联系
管理
随笔-385 评论-58 文章-0 trackbacks-0
在SyncA和SyncB中分别创建Source表和Target表,实际业务中,两张表的结构大多不相同。
然后创建一个类库的项目:MySync(注意项目的版本,Sql08不支持的.net 4.0及更高版本)
下面是同步程序代码:
接下来要对类库项目进行签名,签名后编译【项目】:
启用CLR功能:默认情况下,Sql Server中的CLR是关闭的,所以我们要执行如下命令打开SyncA数据库的CLR。
注册DLL:
为了调用我们写的那个方法,需要在SQL Server中注册我们刚刚编译好的那个DLL。在此之前,要知道在这个项目中如果要访问服务器之外的资源是要配置权限的。如果不配置,后面操作中会出现类似下面的错误。我找到的关于授权配置的内容:连接。
创建登录名和密钥,如果程序集有变更,要删除密钥和登录名重新创建:
创建程序集,DLL变更后要删除重新创建:
然后创建一个函数用于调用这个DLL:
先来测试一下,在SyncA中执行查询:
SyncB中添加了一条数据:
下面使用触发器自动的从SyncA中将数据同步到SyncB中,其中的tt表是我临时创建的,用于保存触发器调用返回的结果:
直接执行函数没有问题,但是触发器去调用函数执行却出现异常:
这个错误中包含了一个false值,说明触发器调用时已经可以走到DLL这一步了。考虑到在查询中直接执行函数,走到DLL这一步是没有错误的。那么错误就发生在触发器和DLL调用产生的冲突,冲突在访问数据库上面,再深入的原因,我也没有找到。
下面使用另外一种方式实现同步,因为错误是触发器和DLL的数据库访问冲突,那么我就绕过数据库的访问。将触发器产生的SQL脚本保存到某个目录下面,然后通过其他程序监听这个目录,执行脚本文件,实现同步。
类库代码
另外创建一个监听程序:MyListen
只要将监听程序打开,就可以实现对数据的同步。项目和数据库下载。
参考:
http://msdn.microsoft.com/zh-cn/library/Microsoft.SqlServer.Server.SqlFunctionAttribute_properties(v=vs.100).aspx
http://blog.sina.com.cn/s/blog_59c41d0d0100esjn.html
http://www.cnblogs.com/wshcn/archive/2011/12/02/2271630.html
http://www.cnblogs.com/edong/archive/2010/03/10/1682172.html
http://www.cnblogs.com/hsrzyn/archive/2013/05/28/1976555.html
分类:
Sql/数据库
好文要顶
关注我
收藏该文联系我
FreeSaber
关注 - 61
粉丝 - 79
+加关注
0
1
(请您对文章做出评价)
«
上一篇:DirFile
»
下一篇:C#实现局域网文件传输
posted on 2015-01-08 15:46
FreeSaber 阅读(1774) 评论(3)
编辑
收藏
评论:
#1楼
2015-01-08 16:19 |
12饕餮21
这。。。。
有复制、订阅功能不用。。。。
支持(0)反对(0) http://pic.cnblogs.com/face/172799/20150607225858.png
#2楼
2015-01-08 17:27 |
TC小班
@12饕餮21
请教复制,订阅功能
支持(0)反对(0)
#3楼31039652015/1/9
19:51:08 2015-01-09 19:51 |
12饕餮21
http://www.cnblogs.com/yuqilin/archive/2011/04/28/2031274.html
不自见故明,不自是故彰,不自伐故有功,不自矜故长.夫唯不争,故天下莫能与之争.
博客园
博问
闪存
新随笔
联系
管理
随笔-385 评论-58 文章-0 trackbacks-0
SqlServer调用外部程序实现数据同步
首先创建两个数据库:SyncA是数据源,SyncB是对SyncA进行同步的数据库。在SyncA和SyncB中分别创建Source表和Target表,实际业务中,两张表的结构大多不相同。
然后创建一个类库的项目:MySync(注意项目的版本,Sql08不支持的.net 4.0及更高版本)
下面是同步程序代码:
using System; using System.Data; using System.Data.Sql; using Microsoft.SqlServer.Server; using System.Data.SqlClient; using System.Data.SqlTypes; namespace MySync { public class SyncDataBase { [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read, DataAccess = DataAccessKind.Read)] public static string Sync(string strSql) { string result = "true"; string strConn = @"Data Source=localhost;Initial Catalog=SyncB;User ID=sa;Password=123@abc;"; try { using (SqlConnection connection = new SqlConnection(strConn)) { connection.Open(); SqlCommand command = new SqlCommand(strSql, connection); command.CommandType = CommandType.Text; command.ExecuteNonQuery(); connection.Close(); } } catch (Exception ex) { result = "false:" + ex.ToString(); } return result; } } }
接下来要对类库项目进行签名,签名后编译【项目】:
启用CLR功能:默认情况下,Sql Server中的CLR是关闭的,所以我们要执行如下命令打开SyncA数据库的CLR。
exec sp_configure 'clr enabled',1 reconfigure go
注册DLL:
为了调用我们写的那个方法,需要在SQL Server中注册我们刚刚编译好的那个DLL。在此之前,要知道在这个项目中如果要访问服务器之外的资源是要配置权限的。如果不配置,后面操作中会出现类似下面的错误。我找到的关于授权配置的内容:连接。
创建登录名和密钥,如果程序集有变更,要删除密钥和登录名重新创建:
USE master; GO CREATE ASYMMETRIC KEY SQLCLRSyncKey FROM EXECUTABLE FILE = 'C:\MySync.dll' CREATE LOGIN SQLCLRSyncLogin FROM ASYMMETRIC KEY SQLCLRSyncKey GRANT EXTERNAL ACCESS ASSEMBLY TO SQLCLRSyncLogin; GO
DROP LOGIN SQLCLRSyncLogin DROP ASYMMETRIC KEY SQLCLRSyncKey
创建程序集,DLL变更后要删除重新创建:
USE SyncA; GO create ASSEMBLY MySync FROM 'C:\MySync.dll' WITH PERMISSION_SET = EXTERNAL_ACCESS; GO
然后创建一个函数用于调用这个DLL:
CREATE FUNCTION dbo.fun_sync ( @strSql nvarchar(max) ) RETURNS nvarchar(max) AS EXTERNAL NAME [MySync].[MySync.SyncDataBase].[Sync]
先来测试一下,在SyncA中执行查询:
SELECT dbo.fun_sync('insert into Target(Id,Name,SyncTime) values (null,null,getdate())')
SyncB中添加了一条数据:
下面使用触发器自动的从SyncA中将数据同步到SyncB中,其中的tt表是我临时创建的,用于保存触发器调用返回的结果:
create Trigger tr_source on [Source] for INSERT AS begin declare @strSql nvarchar(max) select @strSql='insert into Target(Id,Name,SyncTime) values ('''+cast(Id as nvarchar)+''','''+Title+''',getdate())' from inserted --执行 declare @result nvarchar(max) select @result=dbo.fun_sync(@strSql) insert into tt(tt) values (@result) end
直接执行函数没有问题,但是触发器去调用函数执行却出现异常:
false:System.Data.SqlClient.SqlException: 其他会话正在使用事务的上下文。 在 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest) 在 System.Data.SqlClient.SqlInternalConnectionTds.PropagateTransactionCookie(Byte[] cookie) 在 System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx) 在 System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx) 在 System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction) 在 System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction) 在 System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject) 在 System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) 在 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 在 System.Data.SqlClient.SqlConnection.Open() 在 MySync.SyncDataBase.Sync(String strSql)
这个错误中包含了一个false值,说明触发器调用时已经可以走到DLL这一步了。考虑到在查询中直接执行函数,走到DLL这一步是没有错误的。那么错误就发生在触发器和DLL调用产生的冲突,冲突在访问数据库上面,再深入的原因,我也没有找到。
下面使用另外一种方式实现同步,因为错误是触发器和DLL的数据库访问冲突,那么我就绕过数据库的访问。将触发器产生的SQL脚本保存到某个目录下面,然后通过其他程序监听这个目录,执行脚本文件,实现同步。
类库代码
using System; using System.Data; using System.Data.Sql; using Microsoft.SqlServer.Server; using System.Data.SqlClient; using System.Data.SqlTypes; using System.IO; namespace MySync { public class SyncDataBase { [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read, DataAccess = DataAccessKind.Read)] public static string Sync(string strSql) { string result = "true"; try { if (!Directory.Exists("c:\\SyncLog")) { Directory.CreateDirectory("c:\\SyncLog"); } string fileName = @"c:\\SyncLog\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt"; if (File.Exists(fileName)) File.Delete(fileName); using (StreamWriter sw = File.CreateText(fileName)) { sw.WriteLine(strSql); } } catch (Exception ex) { result = "false:" + ex.ToString(); } return result; } } }
另外创建一个监听程序:MyListen
using System; using System.Data; using System.Data.Sql; using System.Data.SqlClient; using System.Data.SqlTypes; using System.Configuration; using System.Threading; using System.IO; namespace MyListen { class Program { static void Main(string[] args) { string connSync = ConfigurationManager.ConnectionStrings["connSync"].ToString(); string filePath = ConfigurationManager.AppSettings["filePath"]; while (true) { //所有txt文件 string[] fileList = DirFile.GetFileNames(filePath, "*.txt", true); foreach (var f in fileList) { string strSql = ""; using (StreamReader sr = new StreamReader(f)) { string line; while ((line = sr.ReadLine()) != null) { strSql += line + " "; } sr.Close(); } try { using (SqlConnection connection = new SqlConnection(connSync)) { connection.Open(); SqlCommand command = new SqlCommand(strSql, connection); command.CommandType = CommandType.Text; command.ExecuteNonQuery(); connection.Close(); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } File.Delete(f); } //每10秒扫描一次 Thread.Sleep(5 * 1000); } } } }
只要将监听程序打开,就可以实现对数据的同步。项目和数据库下载。
参考:
http://msdn.microsoft.com/zh-cn/library/Microsoft.SqlServer.Server.SqlFunctionAttribute_properties(v=vs.100).aspx
http://blog.sina.com.cn/s/blog_59c41d0d0100esjn.html
http://www.cnblogs.com/wshcn/archive/2011/12/02/2271630.html
http://www.cnblogs.com/edong/archive/2010/03/10/1682172.html
http://www.cnblogs.com/hsrzyn/archive/2013/05/28/1976555.html
分类:
Sql/数据库
好文要顶
关注我
收藏该文联系我
FreeSaber
关注 - 61
粉丝 - 79
+加关注
0
1
(请您对文章做出评价)
«
上一篇:DirFile
»
下一篇:C#实现局域网文件传输
posted on 2015-01-08 15:46
FreeSaber 阅读(1774) 评论(3)
编辑
收藏
评论:
#1楼
2015-01-08 16:19 |
12饕餮21
这。。。。
有复制、订阅功能不用。。。。
支持(0)反对(0) http://pic.cnblogs.com/face/172799/20150607225858.png
#2楼
2015-01-08 17:27 |
TC小班
@12饕餮21
请教复制,订阅功能
支持(0)反对(0)
#3楼31039652015/1/9
19:51:08 2015-01-09 19:51 |
12饕餮21
http://www.cnblogs.com/yuqilin/archive/2011/04/28/2031274.html
相关文章推荐
- 数据库框架之Greendao从无到有(一)
- oracle下lag和lead分析函数
- mysql 查询死锁以及解锁
- SQL SERVER with递归示例一则
- redis-windows服务安装
- Mac 安装 MySQL
- MSsql 增删改某个表时,用触发器调用DLL通知外部窗体程序
- SQL Server 2008中新增的变更数据捕获(CDC)和更改跟踪
- 解析Mysql字符集概念
- PB数据窗口使用数组参数执行SQL的IN方法[转]
- SQLITE报错database is locked的解决办法
- SQL读书笔记(五)
- SQL读书笔记(四)
- mysql的基本使用方法
- IOS sqlite3 数据增删改查
- MySQL用户授权 和 bin-log日志 详解和实战
- IOS sqlite3 使用简单介绍 使用简单介绍
- linux redis安装
- linux上安装Oracle 11g R2 标准版 64位
- Hibernate学习篇03——Oracle sequence