最近工做上接到一個需求,作一個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(); } } }
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頁面。等待下篇。