SqlServer调用外部程序实现数据同步
首先创建两个数据库:SyncA是数据源,SyncB是对SyncA进行同步的数据库。 在SyncA和SyncB中分别创建Source表和Target表,实际业务中,两张表的结构大多不相同。 然后创建一个类库的项目:MySync(注意项目的版本,Sql08不支持的.net 4.0及更高版本) 下面是同
首先创建两个数据库:SyncA是数据源,SyncB是对SyncA进行同步的数据库。
在SyncA和SyncB中分别创建Source表和Target表,实际业务中,两张表的结构大多不相同。
然后创建一个类库的项目:MySync(注意项目的版本,Sql08不支持的.net 4.0及更高版本)
下面是同步程序代码:
<span>using</span><span> System; </span><span>using</span><span> System.Data; </span><span>using</span><span> System.Data.Sql; </span><span>using</span><span> Microsoft.SqlServer.Server; </span><span>using</span><span> System.Data.SqlClient; </span><span>using</span><span> System.Data.SqlTypes; </span><span>namespace</span><span> MySync { </span><span>public</span> <span>class</span><span> SyncDataBase {<br> [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read, DataAccess = DataAccessKind.Read)] </span><span>public</span> <span>static</span> <span>string</span> Sync(<span>string</span><span> strSql) { </span><span>string</span> result = <span>"</span><span>true</span><span>"</span><span>; </span><span>string</span> strConn = <span>@"</span><span>Data Source=localhost;Initial Catalog=SyncB;User ID=sa;Password=123@abc;</span><span>"</span><span>; </span><span>try</span><span> { </span><span>using</span> (SqlConnection connection = <span>new</span><span> SqlConnection(strConn)) { connection.Open(); SqlCommand command </span>= <span>new</span><span> SqlCommand(strSql, connection); command.CommandType </span>=<span> CommandType.Text; command.ExecuteNonQuery(); connection.Close(); } } </span><span>catch</span><span> (Exception ex) { result </span>= <span>"</span><span>false:</span><span>"</span> +<span> ex.ToString(); } </span><span>return</span><span> result; } } }</span>
接下来要对类库项目进行签名,签名后编译【项目】:
启用CLR功能:默认情况下,Sql Server中的CLR是关闭的,所以我们要执行如下命令打开SyncA数据库的CLR。
<span>exec</span> sp_configure <span>'</span><span>clr enabled</span><span>'</span>,<span>1</span> <span>reconfigure</span> <span>go</span>
注册DLL:
为了调用我们写的那个方法,需要在SQL Server中注册我们刚刚编译好的那个DLL。在此之前,要知道在这个项目中如果要访问服务器之外的资源是要配置权限的。如果不配置,后面操作中会出现类似下面的错误。我找到的关于授权配置的内容:连接。
创建登录名和密钥,如果程序集有变更,要删除密钥和登录名重新创建:
<span>USE</span><span> master; </span><span>GO</span> <span>CREATE</span> ASYMMETRIC <span>KEY</span> SQLCLRSyncKey <span>FROM</span> EXECUTABLE <span>FILE</span> <span>=</span> <span>'</span><span>C:\MySync.dll</span><span>'</span> <span>CREATE</span> LOGIN SQLCLRSyncLogin <span>FROM</span> ASYMMETRIC <span>KEY</span><span> SQLCLRSyncKey </span><span>GRANT</span> EXTERNAL ACCESS ASSEMBLY <span>TO</span><span> SQLCLRSyncLogin; </span><span>GO</span>
<span>DROP</span><span> LOGIN SQLCLRSyncLogin </span><span>DROP</span> ASYMMETRIC <span>KEY</span> SQLCLRSyncKey
创建程序集,DLL变更后要删除重新创建:
<span>USE</span><span> SyncA; </span><span>GO</span> <span>create</span><span> ASSEMBLY MySync </span><span>FROM</span> <span>'</span><span>C:\MySync.dll</span><span>'</span> <span>WITH</span> PERMISSION_SET <span>=</span><span> EXTERNAL_ACCESS; </span><span>GO</span>
然后创建一个函数用于调用这个DLL:
<span>CREATE</span> <span>FUNCTION</span><span> dbo.fun_sync ( </span><span>@strSql</span> <span>nvarchar</span>(<span>max</span><span>) ) </span><span>RETURNS</span> <span>nvarchar</span>(<span>max</span><span>) </span><span>AS</span> EXTERNAL NAME <span>[</span><span>MySync</span><span>]</span>.<span>[</span><span>MySync.SyncDataBase</span><span>]</span>.<span>[</span><span>Sync</span><span>]</span>
先来测试一下,在SyncA中执行查询:
<span>SELECT</span> dbo.fun_sync(<span>'</span><span>insert into Target(Id,Name,SyncTime) values (null,null,getdate())</span><span>'</span>)
SyncB中添加了一条数据:
下面使用触发器自动的从SyncA中将数据同步到SyncB中,其中的tt表是我临时创建的,用于保存触发器调用返回的结果:
<span>create</span> <span>Trigger</span><span> tr_source </span><span>on</span> <span>[</span><span>Source</span><span>]</span> <span>for</span> <span>INSERT</span> <span>AS</span> <span>begin</span> <span>declare</span> <span>@strSql</span> <span>nvarchar</span>(<span>max</span><span>) </span><span>select</span> <span>@strSql</span><span>=</span><span>'</span><span>insert into Target(Id,Name,SyncTime) values (</span><span>'''</span><span>+</span><span>cast</span>(Id <span>as</span> <span>nvarchar</span>)<span>+</span><span>'''</span><span>,</span><span>'''</span><span>+</span>Title<span>+</span><span>'''</span><span>,getdate())</span><span>'</span> <span>from</span><span> inserted </span><span>--</span><span>执行</span> <span>declare</span> <span>@result</span> <span>nvarchar</span>(<span>max</span><span>) </span><span>select</span> <span>@result</span><span>=</span>dbo.fun_sync(<span>@strSql</span><span>) </span><span>insert</span> <span>into</span> tt(tt) <span>values</span> (<span>@result</span><span>) </span><span>end</span>
直接执行函数没有问题,但是触发器去调用函数执行却出现异常:
<span>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)</span>
这个错误中包含了一个false值,说明触发器调用时已经可以走到DLL这一步了。考虑到在查询中直接执行函数,走到DLL这一步是没有错误的。那么错误就发生在触发器和DLL调用产生的冲突,冲突在访问数据库上面,再深入的原因,我也没有找到。
下面使用另外一种方式实现同步,因为错误是触发器和DLL的数据库访问冲突,那么我就绕过数据库的访问。将触发器产生的SQL脚本保存到某个目录下面,然后通过其他程序监听这个目录,执行脚本文件,实现同步。
类库代码
<span>using</span><span> System; </span><span>using</span><span> System.Data; </span><span>using</span><span> System.Data.Sql; </span><span>using</span><span> Microsoft.SqlServer.Server; </span><span>using</span><span> System.Data.SqlClient; </span><span>using</span><span> System.Data.SqlTypes; </span><span>using</span><span> System.IO; </span><span>namespace</span><span> MySync { </span><span>public</span> <span>class</span><span> SyncDataBase { [SqlFunction(SystemDataAccess </span>= SystemDataAccessKind.Read, DataAccess =<span> DataAccessKind.Read)] </span><span>public</span> <span>static</span> <span>string</span> Sync(<span>string</span><span> strSql) { </span><span>string</span> result = <span>"</span><span>true</span><span>"</span><span>; </span><span>try</span><span> { </span><span>if</span> (!Directory.Exists(<span>"</span><span>c:\\SyncLog</span><span>"</span><span>)) { Directory.CreateDirectory(</span><span>"</span><span>c:\\SyncLog</span><span>"</span><span>); } </span><span>string</span> fileName = <span>@"</span><span>c:\\SyncLog\\</span><span>"</span> + DateTime.Now.ToString(<span>"</span><span>yyyyMMddHHmmss</span><span>"</span>) + <span>"</span><span>.txt</span><span>"</span><span>; </span><span>if</span> (<span>File.Exists(fileName)) File.Delete(fileName); </span><span>using</span> (StreamWriter sw =<span> File.CreateText(fileName)) { sw.WriteLine(strSql); } } </span><span>catch</span><span> (Exception ex) { result </span>= <span>"</span><span>false:</span><span>"</span> +<span> ex.ToString(); } </span><span>return</span><span> result; } } }</span>
另外创建一个监听程序:MyListen
<span>using</span><span> System; </span><span>using</span><span> System.Data; </span><span>using</span><span> System.Data.Sql; </span><span>using</span><span> System.Data.SqlClient; </span><span>using</span><span> System.Data.SqlTypes; </span><span>using</span><span> System.Configuration; </span><span>using</span><span> System.Threading; </span><span>using</span><span> System.IO; </span><span>namespace</span><span> MyListen { </span><span>class</span><span> Program { </span><span>static</span> <span>void</span> Main(<span>string</span><span>[] args) { </span><span>string</span> connSync = ConfigurationManager.ConnectionStrings[<span>"</span><span>connSync</span><span>"</span><span>].ToString(); </span><span>string</span> filePath = ConfigurationManager.AppSettings[<span>"</span><span>filePath</span><span>"</span><span>]; </span><span>while</span> (<span>true</span><span>) { </span><span>//</span><span>所有txt文件</span> <span>string</span>[] fileList = DirFile.GetFileNames(filePath, <span>"</span><span>*.txt</span><span>"</span>, <span>true</span><span>); </span><span>foreach</span> (<span>var</span> f <span>in</span><span> fileList) { </span><span>string</span> strSql = <span>""</span><span>; </span><span>using</span> (StreamReader sr = <span>new</span><span> StreamReader(f)) { </span><span>string</span><span> line; </span><span>while</span> ((line = sr.ReadLine()) != <span>null</span><span>) { strSql </span>+= line + <span>"</span> <span>"</span><span>; } sr.Close(); } </span><span>try</span><span> { </span><span>using</span> (SqlConnection connection = <span>new</span><span> SqlConnection(connSync)) { connection.Open(); SqlCommand command </span>= <span>new</span><span> SqlCommand(strSql, connection); command.CommandType </span>=<span> CommandType.Text; command.ExecuteNonQuery(); connection.Close(); } } </span><span>catch</span><span> (Exception ex) { Console.WriteLine(ex.ToString()); } File.Delete(f); } </span><span>//</span><span>每10秒扫描一次</span> Thread.Sleep(<span>5</span> * <span>1000</span><span>); } } } }</span>
只要将监听程序打开,就可以实现对数据的同步。项目和数据库下载。
参考:
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

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

iPhone上的默认地图是Apple专有的地理位置提供商“地图”。尽管地图越来越好,但它在美国以外的地区运行不佳。与谷歌地图相比,它没有什么可提供的。在本文中,我们讨论了使用Google地图成为iPhone上的默认地图的可行性步骤。如何在iPhone中使Google地图成为默认地图将Google地图设置为手机上的默认地图应用程序比您想象的要容易。请按照以下步骤操作–先决条件步骤–您必须在手机上安装Gmail。步骤1–打开AppStore。步骤2–搜索“Gmail”。步骤3–点击Gmail应用旁

导入步骤如下:将 MDF 文件复制到 SQL Server 的数据目录(通常为 C:\Program Files\Microsoft SQL Server\MSSQL\DATA)。在 SQL Server Management Studio(SSMS)中,打开数据库并选择“附加”。单击“添加”按钮,选择 MDF 文件。确认数据库名称,点击确定按钮即可。

对于 SQL Server 数据库中已存在同名对象,需要采取以下步骤:确认对象类型(表、视图、存储过程)。如果对象为空,可使用 IF NOT EXISTS 跳过创建。如果对象有数据,使用不同名称或修改结构。使用 DROP 删除现有对象(谨慎操作,建议备份)。检查架构更改,确保没有引用删除或重命名的对象。

您的手机中缺少时钟应用程序吗?日期和时间仍将显示在iPhone的状态栏上。但是,如果没有时钟应用程序,您将无法使用世界时钟、秒表、闹钟等多项功能。因此,修复时钟应用程序的缺失应该是您的待办事项列表的首位。这些解决方案可以帮助您解决此问题。修复1–放置时钟应用程序如果您错误地从主屏幕中删除了时钟应用程序,您可以将时钟应用程序放回原位。步骤1–解锁iPhone并开始向左侧滑动,直到到达“应用程序库”页面。步骤2–接下来,在搜索框中搜索“时钟”。步骤3–当您在搜索结果中看到下方的“时钟”时,请按住它并

若误删 SQL Server 数据库,可采取以下步骤恢复:停止数据库活动;备份日志文件;检查数据库日志;恢复选项:从备份恢复;从事务日志恢复;使用 DBCC CHECKDB;使用第三方工具。请定期备份数据库并启用事务日志以防止数据丢失。

要查看 SQL Server 端口号:打开 SSMS,连接到服务器。在对象资源管理器中找到服务器名称,右键单击它,然后选择“属性”。在“连接”选项卡中,查看“TCP 端口”字段。

当 SQL Server 服务无法启动时,可采取以下步骤解决:检查错误日志以确定根本原因。确保服务帐户具有启动服务的权限。检查依赖项服务是否正在运行。禁用防病毒软件。修复 SQL Server 安装。如果修复不起作用,重新安装 SQL Server。

在iPhone上面临滞后,缓慢的移动数据连接?通常,手机上蜂窝互联网的强度取决于几个因素,例如区域、蜂窝网络类型、漫游类型等。您可以采取一些措施来获得更快、更可靠的蜂窝互联网连接。修复1–强制重启iPhone有时,强制重启设备只会重置许多内容,包括蜂窝网络连接。步骤1–只需按一次音量调高键并松开即可。接下来,按降低音量键并再次释放它。步骤2–该过程的下一部分是按住右侧的按钮。让iPhone完成重启。启用蜂窝数据并检查网络速度。再次检查修复2–更改数据模式虽然5G提供了更好的网络速度,但在信号较弱
