上節(jié)我們剩余Compare和Fix按鈕沒有講,本節(jié)我們就來講一下Compare按鈕的功能,年底了,要開年會了,一個個積極的跟邱少云似得,給員工漲工資的時候能不能也積極點。不說了,說多了都是淚。
資中網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、自適應網(wǎng)站建設等網(wǎng)站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯(lián)公司2013年開創(chuàng)至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選成都創(chuàng)新互聯(lián)公司。
還記得我之前寫的大數(shù)據(jù)實戰(zhàn)之環(huán)境搭建,我們今天主要是拿DB的數(shù)據(jù)和solr的數(shù)據(jù)作比較,得出比較結(jié)果。首先,先啟動centOS,啟動tomcat,這樣我們才能利用SolrNet調(diào)用solr公開的API。關(guān)于solr的啟動再次我就不再贅述。
OK,我們將solr實例啟動起來后,用firefox瀏覽管理界面,沒問題。目前solr中并沒有任何數(shù)據(jù)。
接下來我們就要看點擊Compare按鈕了,點擊Compare按鈕,Compare按鈕在哪里呢,在Partial頁。
@using Bruce.GRLC.Model.ViewModel; @model UserInfoViewModel
OK,我們看到了按鈕在這里,我們設置按鈕的樣式為btn btn-info,這都是bootStrap提供的樣式,我們直接拿來用就ok了。這個頁面其實就是循環(huán)相同數(shù)據(jù)的List和不同數(shù)據(jù)的List,加載到一個可多選的下拉列表。大家注意到multiple="multiple",可以多選。另外"form-control"也是bootStrap提供的樣式,用來裝飾表單元素的樣式。上面的代碼沒有什么,我們主要是看控制器一級一級往下是怎么處理的,我們先看Compare按鈕的click事件。
$("#btncompare").click(function () { $("#selsamelist").empty(); $("#seldifflist").empty(); $.ajax({ url: "/Home/GetCompareResult?pam=" + new Date().toTimeString(), type: "POST", datatype: "Html", beforeSend: function () { $("#divcompare").show(); }, complete: function () { $("#divcompare").hide(); }, success: function (data) { $("#divcompareresult").html(data); }, error: function () { alert("比較失敗!"); } });
首先我們先清除兩個多選下拉列表的數(shù)據(jù),因為我們這里并不是返回整個Partial頁面來替換,所以我們必須先把兩個多選下拉數(shù)據(jù)清除掉。OK,我們看一下控制器。
public PartialViewResult GetCompareResult() { GRLCBiz instance = GRLCBiz.GetInstance(); instance.CompareDBAndSolr(); UserInfoViewModel userInfoViewModel = new UserInfoViewModel(); userInfoViewModel.DifferenceWithSolrEntityList = instance.differenceUserEntityList; ListdifferenceUserIDList = userInfoViewModel.DifferenceWithSolrEntityList.Select(d => d.UserNo.Trim()).ToList(); userInfoViewModel.SameWithSolrEntityList = instance.userEntityList.Where(u => !differenceUserIDList.Contains(u.UserID.Trim())) .Select((userDB, userSolr) => { return new UserSolrEntity() { UserNo = userDB.UserID.Trim(), Name = userDB.UserName == null ? string.Empty : userDB.UserName.Trim() }; }).ToList(); return PartialView("~/Views/Partial/DiffAndSameWithSolrPartial.cshtml", userInfoViewModel); }
其實很簡單,首先我們調(diào)用CompareDBAndSolr方法,這個方法是獲取到比較結(jié)果的關(guān)鍵。那么比較的話,我們怎么比較呢,大家有經(jīng)驗的同學一定想到多線程。不錯,就是多線程,可是有人要說了,多線程的話,你怎么知道線程都執(zhí)行完了,因為只有多個線程都執(zhí)行完了,我們才能拿到最終的比較結(jié)果,顯示到頁面上。說到這里,如果你是一個.net4.0以前的用戶,你可能會想到AutoResetEvent。
說到這個AutoResetEvent,它可以有一個初始的狀態(tài),如果是true,則表明是一個終止狀態(tài),反之則是非終止狀態(tài),那么看一下我們的程序。
public void CompareDBAndSolr() { if (userEntityList == null) { userEntityList = this.GetAllDBUserList(); } if (userEntityList == null || userEntityList.Count == 0) return; int threadCount = 0; int totalCount = userEntityList.Count; threadCount = totalCount % ConstValues.CONN_ComparePerThread == 0 ? totalCount / ConstValues.CONN_ComparePerThread : totalCount / ConstValues.CONN_ComparePerThread + 1; if (threadCount > ConstValues.CONN_CompareThreadCount) { threadCount = ConstValues.CONN_CompareThreadCount; } differenceUserEntityList = new List(); autoResetEvents = new AutoResetEvent[threadCount]; for (int i = 0; i < threadCount; i++) { autoResetEvents[i] = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(new WaitCallback(CompareUserInfoByThread), i); Thread.Sleep(ConstValues.CONN_ThreadCreateInterval); } WaitHandle.WaitAll(this.autoResetEvents); }
在這個方法中我們先拿到數(shù)據(jù)庫的所有用戶的數(shù)據(jù)
SELECT A.UseNo, ISNULL(B.Name,'') AS Name, ISNULL(B.Age,0) AS Age, ISNULL(B.Temper,'') AS Married FROM Bonus.dbo.[User] A WITH(NOLOCK) INNER JOIN Bonus.dbo.UerInfo B WITH(NOLOCK) ON A.UseNo = B.UseNo
然后計算應該使用的線程數(shù)。CONN_ComparePerThread配置的是每個線程比較的數(shù)據(jù)量,所以我們先拿總數(shù)據(jù)對其進行求余,得到總線程數(shù),然后再判斷如果總線程數(shù)大于配置的線程數(shù)CONN_CompareThreadCount,則取配置的線程數(shù)。因為機器的資源有限,不可能開啟成百上千個線程,那樣CPU資源占用很大,機器肯能會卡死。所以設置最大線程數(shù)是必須的。當我們拿到線程數(shù)以后,我們實例化一個AutoResetEvent數(shù)組,來管理這些線程之間的通信。接下來循環(huán)創(chuàng)建AutoResetEvent,設置其初始狀態(tài)為非終止。然后將線程要執(zhí)行的方法加入線程池工作隊列,并傳遞線程編號i作為方法參數(shù)。最后這句WaitHandle.WaitAll(this.autoResetEvents);意思是等待所有的線程任務結(jié)束(狀態(tài)標記為終止狀態(tài))。
我們接下來看CompareUserInfoByThread方法。
private void CompareUserInfoByThread(object userState) { int threadIndex = (int)userState; try { UserDBEntity[] copyUserDBEntityList = null; while (this.movePosition < this.userEntityList.Count) { lock (this.userEntityList) { if (this.movePosition >= this.userEntityList.Count) { break; } if (this.movePosition <= this.userEntityList.Count - ConstValues.CONN_ComparePerThread) { copyUserDBEntityList = new UserDBEntity[ConstValues.CONN_ComparePerThread]; userEntityList.CopyTo(this.movePosition, copyUserDBEntityList, 0, ConstValues.CONN_ComparePerThread); } else { //最后幾個,count這個方法其實就是多線程瓜分數(shù)據(jù)了,每個線程Copy出一批(CONN_ComparePerThread)DB的數(shù)據(jù)去和solr作對比,每個線程拿到自己的那批數(shù)據(jù)后,將計數(shù)器movePosition增加CONN_ComparePerThread。直到這些線程將這些數(shù)據(jù)瓜分完,大家注意到在finally語句塊,我們對每個AutoResetEvent對象調(diào)用set方法,意思是告訴WaitHandle,我已經(jīng)執(zhí)行完了,即終止狀態(tài)。這樣當WaitHanlde收到每個線程執(zhí)行完畢的信號后,結(jié)束等待,否則就會一直等待下去,這就是為什么Set方法的調(diào)用一定要放到finally塊的原因。OK,繼續(xù)看下一個方法CompareUserInfoStart
private void CompareUserInfoStart(UserDBEntity[] userDBEntityList, int threadIndex) { ListuserIDList = userDBEntityList.Select(u => u.UserID.Trim()).ToList(); StringBuilder solrFilter = new StringBuilder(); foreach (var userID in userIDList) { solrFilter.Append("UserNo:"); solrFilter.Append(userID); solrFilter.Append(" OR "); } solrFilter.Length = solrFilter.Length - 4; List userSolrEntityList = SolrHelper.GetInstance().QueryByFilter (solrFilter.ToString()); List userDBConvertSolrEntityList = userDBEntityList.Select((userDB, userSolr) => { return new UserSolrEntity() { UserNo = userDB.UserID.Trim(), Age = userDB.Age, Name = userDB.UserName.Trim(), IsMarried = userDB.Married == "1" }; }).ToList(); lock (_lockObj) { differenceUserEntityList.AddRange(userDBConvertSolrEntityList.Except(userSolrEntityList, new UserSolrEntityCompare())); } } } 我們拿到對比的DB數(shù)據(jù)實體List之后,得到userID,然后拼成solr的查詢條件solrFilter,然后調(diào)用SolrHelper中的QueryByFilter
方法去查詢出一個Solr的實體List,然后我們將DB的實體List通過Linq轉(zhuǎn)化為Solr的實體List userDBConvertSolrEntityList。然后通過Except方法找出不同的實體List,放置到differenceUserEntityList。在這里注意IEqualityCompare接口的實現(xiàn)。 public class UserSolrEntityCompare : IEqualityComparer{ public bool Equals(UserSolrEntity original, UserSolrEntity destination) { original.Name = original.Name ?? string.Empty; original.UserNo = original.UserNo ?? string.Empty; destination.Name = destination.Name ?? string.Empty; destination.UserNo = destination.UserNo ?? string.Empty; return original.UserNo.Trim().Equals(destination.UserNo.Trim()) && original.Age == destination.Age && original.Name.Trim().Equals(destination.Name.Trim()) && original.IsMarried == destination.IsMarried; } public int GetHashCode(UserSolrEntity userSolrEntity) { return userSolrEntity.UserNo.GetHashCode(); } } OK,到這里就全部結(jié)束了,我們在action中拿到了比較出的結(jié)果,然后組成viewModel,返回給Partial頁面去綁定??匆幌滦Ч鸆omparing,please wait......
下面是比較出的結(jié)果,因為solr中沒有數(shù)據(jù),所以都是不相同的,因為取DB數(shù)據(jù)是INNER JOIN,所以只有四條數(shù)據(jù)。
OK,本節(jié)到此結(jié)束,下節(jié)我們看一下Fix功能的實現(xiàn)。
新聞標題:ASP.NETMVC4+BootStrap實戰(zhàn)(三)
URL標題:http://weahome.cn/article/gggjjj.html