PowerShell应用之-可更新订阅的事务复制
开始
在上一篇《PowerShell应用之-事务复制》,描述了如何通过PowerShell脚本配置发布&分发服务器、创建事务发布&发布项目、和创建推送&请求订阅。而且上篇订阅是只读的(ReadOnly),在这篇,将会讲述可更新订阅的事务复制,涉及到两种基本的订阅类型:队列更新(QueuedUpdate) & 即时更新(ImmediateUpdate )。本篇使用的例子会沿用上一篇的部分脚本及测试数据库。在这边我们省略了配置发布&分发服务器部分,直接从创建事务发布和发布项目(TransPublication & TransArticle)开始。
创建事务发布和设置发布项目(TransPublication & TransArticle)
在原来的代码中,我们会在开始的输入部分多加两个变量描述可更新订阅的订阅类型,是否队列更新 & 是否即时更新
#------------------------------------------------------------
$AllowQueuedTransactions=$True
##允许即时更新订阅
#------------------------------------------------------------
$AllowSynchronousTransactions=$True
在TransPublication创建之前,需要补上下面的简短代码,描述添加队列更新 & 即时更新到TransPublication可更新订阅选项中。
if($AllowQueuedTransactions -eq $true)
{
$TransPublication.Attributes =$TransPublication.Attributes -bor [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowQueuedTransactions
}
#允许即时更新订阅
if($AllowSynchronousTransactions -eq $true)
{
$TransPublication.Attributes =$TransPublication.Attributes -bor [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowSynchronousTransactions
}
这部分的完整代码,我们可以查看PowerShell脚本:
Replication-5-Create a Publication(AllowQueuedTransactions).ps1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
##配置发布、分发服务器者登录用户名&密码,这里发布与分发使用同一个实例
#------------------------------------------------------------
$serverInstance="WINSERVER01\SQL2008DE01"
$userName="sa"
$password="sql20081"
##设置域账号,应用于同步复制
#------------------------------------------------------------
$RAccount="TN\SQLAccount"
$RPassword="Sql123456"
##发布数据库
#------------------------------------------------------------
$DataBase="ReplicationDB"
##项目名称
#------------------------------------------------------------
$TransPublicationName=$DataBase+“_Tran_”
##项目对应的是表,使用"Select * Form TableName Where ...;"格式
#------------------------------------------------------------
$SQL="
Select * From DataOwner Where ID=2;
Select * From Data1 Where OwnerID=2;
Select * From Data2 Where ParentID In(Select ID From dbo.Data1 Where OwnerID=2);
Select * From DataRelation Where ParentID In(Select dbo.Data2.ID From dbo.Data1 Inner Join dbo.Data2 On dbo.Data1.ID = dbo.Data2.ParentID And dbo.Data1.OwnerID=2);
"
##发行项目选项
#------------------------------------------------------------
$PreCreationMethod="drop" #当名称已被使用时的操作.可以选择“none”,“delete”,“drop”,"truncate"
##允许队列更新订阅
#------------------------------------------------------------
$AllowQueuedTransactions=$True
##允许即时更新订阅
#------------------------------------------------------------
$AllowSynchronousTransactions=$True
<#================================================================#>
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Rmo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
#Step 1: 创建连接
$ServerConnection =New-object "Microsoft.SqlServer.Management.Common.ServerConnection" $serverInstance,$userName, $password
#Step 2:
Try
{
$ServerConnection.Connect()
if ($ServerConnection.IsOpen)
{
$ReplicationDatabase =New-object "Microsoft.SqlServer.Replication.ReplicationDatabase" $DataBase,$ServerConnection
$ReplicationDatabase.EnabledTransPublishing=$true
#创建队列读取器代理
if ($ReplicationDatabase.LogReaderAgentExists -eq $false)
{
$ReplicationDatabase.LogReaderAgentProcessSecurity.Login=$RAccount
$ReplicationDatabase.LogReaderAgentProcessSecurity.Password=$RPassword
$ReplicationDatabase.LogReaderAgentPublisherSecurity.WindowsAuthentication=$true
$ReplicationDatabase.LogReaderAgentPublisherSecurity.SqlStandardLogin=$userName
$ReplicationDatabase.LogReaderAgentPublisherSecurity.SqlStandardPassword=$password
$ReplicationDatabase.LogReaderAgentPublisherSecurity.WindowsAuthentication=$false
$ReplicationDatabase.CreateLogReaderAgent()
}
#创建事务发布
$TransPublication=New-object "Microsoft.SqlServer.Replication.TransPublication" $TransPublicationName,$DataBase,$ServerConnection
$TransPublication.SnapshotGenerationAgentProcessSecurity.Login=$RAccount
$TransPublication.SnapshotGenerationAgentProcessSecurity.Password=$RPassword
$TransPublication.SnapshotGenerationAgentPublisherSecurity.WindowsAuthentication=$true
$TransPublication.SnapshotGenerationAgentPublisherSecurity.SqlStandardLogin=$userName
$TransPublication.SnapshotGenerationAgentPublisherSecurity.SqlStandardPassword=$password
$TransPublication.SnapshotGenerationAgentPublisherSecurity.WindowsAuthentication=$false
#允许队列更新订阅
if($AllowQueuedTransactions -eq $true)
{
$TransPublication.Attributes =$TransPublication.Attributes -bor [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowQueuedTransactions
}
#允许即时更新订阅
if($AllowSynchronousTransactions -eq $true)
{
$TransPublication.Attributes =$TransPublication.Attributes -bor [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowSynchronousTransactions
}
if ($TransPublication.IsExistingObject -eq $false)
{
$TransPublication.Create()
}
#定义发布项目
While($SQL.IndexOf(“`r”) -gt 0) #处理Select列表
{$SQL=$SQL.Replace("`r","")}
While($SQL.IndexOf(“`n”) -gt 0)
{$SQL=$SQL.Replace("`n","")}
While($SQL.IndexOf(“`t”) -gt 0)
{$SQL=$SQL.Replace("`t "," ")}
While($SQL.IndexOf(" ") -gt 0)
{$SQL=$SQL.Replace(" "," ")}
$SQL=$SQL.ToLower()
Foreach ($SqlLine In $SQL.split(";"))
{
if ($SqlLine.IndexOf("from") -gt 0)
{
$Where=""
$TB=$SqlLine.split(" ")[3]
If ($SqlLine.LastIndexOf("where") -gt 0)
{
$Where=$SqlLine.substring([int32]($SqlLine.IndexOf("where")+6))
}
$Article=New-object "Microsoft.SqlServer.Replication.TransArticle" $TB,$TransPublicationName,$DataBase,$ServerConnection
$Article.SourceObjectName=$TB
$article.FilterClause=$Where
$article.PreCreationMethod=$PreCreationMethod
if ($Article.IsExistingObject -eq $false)
{
$Article.Create()
}
}
}
Write-Host "事务发布 '$TransPublicationName' 已创建!"
}
}
Catch
{
Write-Error $_
}
执行上面的完整代码,我们就可以看到在事务发布ReplicationDB_Tran_的属性,查看可更新订阅选项内容:
如何创建推送订阅(Push Subscription)
创建可更新订阅的时候,与上篇创建订阅的有些不同,在这过程,我们代码开头位置多一个变量来描述可更新订阅类型。
#------------------------------------------------------------
$SubscriberType=“ImmediateUpdate”
在创建订阅之前会,根据开头设置的变量$SubscriberType,来描述订阅类型,
$TransSubscription.SubscriberType=[Microsoft.SqlServer.Replication.TransSubscriberType]::$SubscriberType
当要使用即时更新的时候,我们还需要设置在连接到发布服务器时立即更新订阅的同步触发器所使用的配置和安全信息。这里将应用到类"Microsoft.SqlServer.Replication.ReplicationDatabase"中的方法LinkPublicationForUpdateableSubscription。此方法类似T-SQL中的sp_link_publication系统存储过程。
#在订阅端,确保登录账户“repllinkproxy”對订阅数据库具有db_onwer權限
$ReplicationDatabase =New-object "Microsoft.SqlServer.Replication.ReplicationDatabase" $DataBase,$SubServerConnection
If($ReplicationDatabase.LoadProperties())
{
$Publisher=$serverInstance
$PublisherDB =$TransSubscription.SubscriptionDBName
$Publication=$TransPublication.Name
$Distributo=$null
$PublisherConnectionSecurityContext=New-object "Microsoft.SqlServer.Replication.PublisherConnectionSecurityContext"
<#--SqlStandard模式--#>
#<#
$PublisherConnectionSecurityContext.SecurityMode=[Microsoft.SqlServer.Replication.ReplicationSecurityMode]::SqlStandard
$PublisherConnectionSecurityContext.SqlStandardLogin=$userName
$PublisherConnectionSecurityContext.SqlStandardPassword=$password
##>
<#--PredefinedServer模式--#> #需要创建一个固定的链接服务器,名字与$serverInstance相同
#$PublisherConnectionSecurityContext.SecurityMode=[Microsoft.SqlServer.Replication.ReplicationSecurityMode]::PredefinedServer
$ReplicationDatabase.LinkPublicationForUpdateableSubscription($Publisher,$PublisherDB,$Publication,$Distributo,$PublisherConnectionSecurityContext )
}
注,在上面的即时更新脚本中,我们要确保发布服务器与订阅服务器的MSTDC要启动,要是存在防火墙需要开启135端口。
我们要注意”<#--SqlStandard模式—#>” 和“ <#--PredefinedServer模式--#>”两部分。使用”<#--SqlStandard模式—#>” 会指定动态远程过程调用 (RPC)。“ <#--PredefinedServer模式--#>”需要固定的链接服务器。是于这两者具体的差异,可能要另写一篇来详细描述,比较有意思的。
订阅的完整PowerShell脚本,我们可以参考:
Replication-5-Create a Publication(AllowQueuedTransactions).ps1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
##分发代理程序执行账户
#------------------------------------------------------------
$serverInstance="WINSERVER01\SQL2008DE01"
$userName="sa"
$password="sql20081"
##设置域账号,应用于同步复制
#------------------------------------------------------------
$RAccount="TN\SQLAccount"
$RPassword="Sql123456"
##连接到订阅服务器账户
#------------------------------------------------------------
$SubserverInstance="TON-WINXP001\SQL2008DE"
$SubuserName="sa"
$Subpassword="WinXP00120081"
##发布对象
#------------------------------------------------------------
$DataBase="ReplicationDB"
$TransPublicationName=“ReplicationDB_Tran_”
##是否要初始化
#------------------------------------------------------------
$invalidate=$true
##可更新订阅类型
#------------------------------------------------------------
$SubscriberType=“ImmediateUpdate”
<#
ReadOnly : 该订阅是只读的。在订阅服务器上所做的更改不会发送到发布服务器。
QueuedUpdate : 启用排队更新的订阅。可以在订阅服务器上进行数据修改,将其存储在队列中,然后传播到发布服务器。Oracle 发布服务器不支持
ImmediateUpdate : 启用对即时更新订阅的支持。Oracle 发布服务器不支持。
QueuedFailover : 将订阅启用为排队更新订阅,并允许更改为立即更新模式。
在订阅服务器和发布服务器之间建立连接之前,可以在订阅服务器上修改数据,并将数据修改存储在队列中。
建立起持续连接后,即可将更新模式更改为立即更新。Oracle 发布服务器不支持。
Failover : 将排队更新作为故障转移的情况下启用用于即时更新的订阅。可以在订阅服务器上进行数据修改并立即传播到发布服务器。
如果发布服务器与订阅服务器未连接在一起,则可以更改更新模式以便将在订阅服务器上所做的数据修改存储在队列中,
直到订阅服务器与发布服务器重新连接在一起。Oracle 发布服务器不支持。
#>
<#================================================================#>
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Rmo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
#Step 1: 创建连接
$ServerConnection =New-object "Microsoft.SqlServer.Management.Common.ServerConnection" $serverInstance,$userName, $password
$SubServerConnection =New-object "Microsoft.SqlServer.Management.Common.ServerConnection" $SubserverInstance,$SubuserName, $Subpassword
#Step 2:
Try
{
$ServerConnection.Connect()
$SubServerConnection.Connect()
if ($ServerConnection.IsOpen -and $SubServerConnection.IsOpen)
{
$TransPublication=New-object "Microsoft.SqlServer.Replication.TransPublication" $TransPublicationName,$DataBase,$ServerConnection
if ($TransPublication.LoadProperties() -eq $true)
{
##设置推送订阅
if($TransPublication.Attributes -notmatch "AllowPush")
{
##使用到位運算OR(inclusive) "-bor" ,如果要刪除某一特征就使用"-bxor"
$TransPublication.Attributes =$TransPublication.Attributes -bor [Microsoft.SqlServer.Replication.PublicationAttributes]::AllowPush
}
$subscriptionDBName=$TransPublication.DatabaseName
$publicationDBName=$TransPublication.DatabaseName
$publicationName=$TransPublication.Name
$TransSubscription=New-object "Microsoft.SqlServer.Replication.TransSubscription" $publicationName,$publicationDBName,$SubserverInstance,$subscriptionDBName,$ServerConnection
if($TransSubscription.LoadProperties() -eq $false)
{
##设置分发代理程序账号(Windows账号)
$TransSubscription.SynchronizationAgentProcessSecurity.Login=$RAccount
$TransSubscription.SynchronizationAgentProcessSecurity.Password=$RPassword
##设置订阅服务器登录账号(SQL Server账号)
$TransSubscription.SubscriberSecurity.WindowsAuthentication=$false
$TransSubscription.SubscriberSecurity.SqlStandardLogin=$SubuserName
$TransSubscription.SubscriberSecurity.SqlStandardPassword=$Subpassword
$TransSubscription.CreateSyncAgentByDefault=$true
#每天执行
$TransSubscription.AgentSchedule.FrequencyType=[Microsoft.SqlServer.Replication.ScheduleFrequencyType]::Daily
#分钟
$TransSubscription.AgentSchedule.FrequencySubDay=[Microsoft.SqlServer.Replication.ScheduleFrequencySubDay]::Minute
#多少分钟执行一次
$TransSubscription.AgentSchedule.FrequencySubDayInterval=1
##是否初始化
if($invalidate -eq $false)
{
$TransSubscription.SyncType=[Microsoft.SqlServer.Replication.SubscriptionSyncType]::ReplicationSupportOnly
}
#更新类型
$TransSubscription.SubscriberType=[Microsoft.SqlServer.Replication.TransSubscriberType]::$SubscriberType
#在订阅端,设置连接发行服务器验证
#在订阅端,确保登录账户“repllinkproxy”對订阅数据库具有db_onwer權限
$ReplicationDatabase =New-object "Microsoft.SqlServer.Replication.ReplicationDatabase" $DataBase,$SubServerConnection
If($ReplicationDatabase.LoadProperties())
{
$Publisher=$serverInstance
$PublisherDB =$TransSubscription.SubscriptionDBName
$Publication=$TransPublication.Name
$Distributo=$null
$PublisherConnectionSecurityContext=New-object "Microsoft.SqlServer.Replication.PublisherConnectionSecurityContext"
<#--SqlStandard模式--#>
#<#
$PublisherConnectionSecurityContext.SecurityMode=[Microsoft.SqlServer.Replication.ReplicationSecurityMode]::SqlStandard
$PublisherConnectionSecurityContext.SqlStandardLogin=$userName
$PublisherConnectionSecurityContext.SqlStandardPassword=$password
##>
<#--PredefinedServer模式--#> #需要创建一个固定的链接服务器,名字与$serverInstance相同
#$PublisherConnectionSecurityContext.SecurityMode=[Microsoft.SqlServer.Replication.ReplicationSecurityMode]::PredefinedServer
$ReplicationDatabase.LinkPublicationForUpdateableSubscription($Publisher,$PublisherDB,$Publication,$Distributo,$PublisherConnectionSecurityContext )
}
$TransSubscription.Create()
#启动快照代理作业
if ($TransPublication.SnapshotAvailable -eq $false )
{
$TransPublication.StartSnapshotGenerationAgentJob()
}
Write-Host "订阅 "$TransSubscription.Name" 创建完成!"
}
Else
{
Write-Host "订阅 "$TransSubscription.Name" 已创建!"
}
}
Else
{
Write-Host "发布对象 $TransPublicationName 不存在!"
}
}
}
Catch
{
Write-Error $_
}
小结
本篇描述了PowerShell应用之-可更新订阅的事务复制,在我们测试过程中可能会发现一些问题,特别是即时更新类型的订阅,注意上面提到的注意内容。因时间问题,订阅部分只测试了Push订阅.如果你在测试过程还有其他不明白的地方,可以在文章的后面留言或直接发Email到我的邮箱。