sql server主動推送客戶端更新數據

小談需求:

最近工做上接到一個需求,作一個web展現數據的報表,最好能實時更新,不限制所用技術。 java

第一個問題:web服務器推送給瀏覽器新數據,一開始我想到的最快的最簡單的方法就是 在web頁面上js輪詢了。由於咱們的數據更新頻率並不快。 後來以爲這種辦法有點太土了。 或許長輪詢更有效。  固然長輪詢的技術不少了。 java 的dwr,c#的 signalr。c#還能夠同過異步請求來本身寫長輪詢。 web

遇到的第二個問題,就是數據庫如何通知web服務器更新數據,下面即是sql server2008的推送了,經過sql server的觸發器,當數據表有變化時(增,刪,改)就經過tcp請求服務器,服務器會在啓動後開啓端口一直監聽,隨時等待通訊請求。當收到請求後,就從數據庫讀取新數據,推送給瀏覽器。總體大概就這樣。 sql

下面是數據庫通知服務器。這是一個 winform的demo ,winfom就至關於咱們展現數據的服務器了。 數據庫

最後demo圖: 編程

如今我插入一條數據:

而後再看那個客戶端:

剛插入的數據已經出現了哦。

客戶端代碼:

winform: c#

程序啓動後,開啓端口監聽,若是有收到通訊,則通知 dataview更新數據。 瀏覽器

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace sql_dependency
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        System.Data.SqlClient.SqlConnection conn = null;
        string _connstr = "Data Source = 10.6.154.251; database=Temp;user id=sa;pwd=MOcyou0543_";
        System.Data.SqlClient.SqlCommand command = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            conn = new System.Data.SqlClient.SqlConnection(_connstr);
            command = conn.CreateCommand();
            command.CommandText = "select [A],[B],[C] From [Temp].[dbo].[Simple]";
            SqlDependency.Start(_connstr);//啓動
            Thread t = new Thread(new ThreadStart(GetData));
            t.Start();
        }


        private void GetData()
        {

            SetData();
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");
            TcpListener tcplistener = new TcpListener(localAddr, 10010);
            tcplistener.Start();
            byte[] btServerReceive = new byte[2048];
            string strServerReceive = string.Empty;
            while (true)
            {
                TcpClient tcp = tcplistener.AcceptTcpClient();
                Console.WriteLine("Connected!");
                NetworkStream ns = tcp.GetStream();
                int intReceiveLength = ns.Read(btServerReceive, 0, btServerReceive.Length);
                strServerReceive = Encoding.ASCII.GetString(btServerReceive, 0, intReceiveLength);

                SetData();
                tcp.Close();
            }

        }
        private delegate void ChangeDataView();
        private void SetData()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ChangeDataView(SetData));
            }
            else
            {
                using (SqlDataAdapter adapter = new SqlDataAdapter(command)) //查詢數據
                {
                    System.Data.DataSet ds = new DataSet();
                    adapter.Fill(ds, 0, 100, "Simple");
                    dataGridView1.DataSource = ds.Tables["Simple"];
                }

            }
        }



        private void Form1_Closed(object sender, FormClosedEventArgs e)
        {
            //清理現場
            SqlDependency.Stop(_connstr);
            conn.Close();
            conn.Dispose();
        }


    }
}

數據庫與clr集成,編寫寫dll:SqlDependency.dll,sql server將在可編程性中加載此dll,

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using Microsoft.SqlServer.Server;

using System.Net.Sockets;
namespace SqlDependency
{
    public class Program
    {

        [SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.Read)]
        public static String WriteStringToFile(String FileFullPath, String Contend)
        {

            FileInfo Fi = new FileInfo(FileFullPath);
            if (!Fi.Directory.Exists)
            {
                Fi.Directory.Create();
            }

            using (StreamWriter rw = File.CreateText(FileFullPath))
            {

                rw.WriteLine(Contend);
                TcpClient tcpClient = new TcpClient();

                try
                {
                    if (tcpClient == null)
                    {
                        tcpClient = new TcpClient();
                        tcpClient.ReceiveTimeout = 20000;
                    }
                    if (tcpClient.Connected == false)
                    {
                        System.Net.IPAddress address = System.Net.IPAddress.Parse(Contend);
                        System.Net.IPHostEntry ipInfor = System.Net.Dns.GetHostByAddress(address);
                        string hostName = ipInfor.HostName;
                        IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10010);
                        tcpClient.Connect(serverEndPoint);
                        rw.Write(hostName);
                    }
                    rw.Write("鏈接成功,先發送指令");
                    // Translate the passed message into ASCII and store it as a Byte array.
                    Byte[] data = System.Text.Encoding.ASCII.GetBytes("new data!");

                    NetworkStream stream = tcpClient.GetStream();

                    // Send the message to the connected TcpServer. 
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                
                }
                catch (Exception e)
                {
                    rw.Write(e.Message);
                }
                tcpClient.Close();  
                rw.Flush();
                rw.Close();
                return "";
            }
        }
    }
}

接下來,便開始配置sql server啦: 服務器

首先開啓sql server的clr支持: 異步

開啓數據庫CLR 支持
--exec sp_configure 'clr enabled', 1;
--開始數據的驗證
alter database dbname set TRUSTWORTHY on;
RECONFIGURE
接着在sql server 2008中,新建查詢窗口。加載剛纔編寫的dll SqlDependency.dll,並註冊方法,而後寫觸發器,當表數據有變化時,觸發函數。:

use Temp;--數據庫名
create assembly SqlDependency FROM 'D:\SqlDependency.dll'--程序集名稱和地址
WITH PERMISSION_SET = UNSAFE
GO

--方法名寫正確,爲程序集中的方法名,注意參數個數
create function WriteStringToFile(@FileFullName as nvarchar(max),  @FileContend AS  nvarchar(max))
returns nvarchar(max)
with returns null on null input
external name [SqlDependency].[SqlDependency.Program].[WriteStringToFile]
GO

--編寫觸發器,傳遞參數以及
CREATE TRIGGER [dbo].[UserTableChangedEvent] on [dbo].[Simple]  
    FOR INSERT, DELETE, UPDATE  
      
AS  
    BEGIN  
    DECLARE @Contend AS VARCHAR(100)  
    DECLARE @FileName AS VARCHAR(MAX)  
        SET @FileName ='D:\\MSG\\'+CONVERT(varchar(12) , getdate(), 112 )+'\\'+ convert(nvarchar(50), NEWID())+'.TXT'  
         
       SET @Contend = '127.0.0.1';  
       Select dbo.WriteStringToFile(@FileName, @Contend)  
                  
    END  
  GO
注意,個人應用程序和 數據庫在一臺服務器上,因此地址都是127.0.0.1.可跟據實際填寫正確地址。

再次在sql server中新建一個查詢窗口,插入語句,進行測試吧。 tcp

若是過程當中有問題,須要更新程序,方便地刪除之上所建立的幾個東東:

drop TRIGGER [dbo].[UserTableChangedEvent] 
drop function WriteStringToFile
drop assembly SqlDependency
以後將嘗試在web 結合 signal實現實時推送數據給web頁面。等待下篇。
相關文章
相關標籤/搜索