為了保證車載動(dòng)力電池的安全運(yùn)行,全面掌握其運(yùn)行狀態(tài),電動(dòng)汽車遠(yuǎn)程監(jiān)控系統(tǒng)已被各個(gè)廠家越來越重視,如何對(duì)監(jiān)控產(chǎn)生的海量數(shù)據(jù)進(jìn)行安全快速的查詢是遠(yuǎn)程監(jiān)控中的重要研究課題。本文著重介紹了一種基于Hibernate框架針對(duì)監(jiān)控車輛的海量數(shù)據(jù)進(jìn)行并行查詢的設(shè)計(jì)思路、關(guān)鍵技術(shù)分析以及具體實(shí)現(xiàn)手段。通過將海量數(shù)據(jù)在ORACLE數(shù)據(jù)庫中分區(qū)存儲(chǔ),查詢終端經(jīng)Hibernate服務(wù)器并行查詢數(shù)據(jù),保證了數(shù)據(jù)庫安全的同時(shí)縮短了查詢所需時(shí)間,達(dá)到了預(yù)期效果。
【關(guān)鍵詞】遠(yuǎn)程監(jiān)控 Hibernate 數(shù)據(jù)庫 并行查詢
電動(dòng)汽車遠(yuǎn)程監(jiān)控系統(tǒng)已被各個(gè)廠家越來越重視,而對(duì)監(jiān)控產(chǎn)生的海量數(shù)據(jù)進(jìn)行安全快速查詢是遠(yuǎn)程監(jiān)控中的重要研究課題。
基于Hibernate的遠(yuǎn)程監(jiān)控?cái)?shù)據(jù)并行查詢目的在于:
(1)確保數(shù)據(jù)庫安全;
(2)確保海量數(shù)據(jù)存儲(chǔ)合理;
(3)提高海量數(shù)據(jù)查詢效率。
本課題實(shí)現(xiàn)了通過中間Hibernate服務(wù)器將查詢終端和數(shù)據(jù)庫服務(wù)器間安全連接,通過按時(shí)間分區(qū),保證了數(shù)據(jù)存儲(chǔ)合理及在此基礎(chǔ)上的并行查詢算法的實(shí)現(xiàn)。
1 基于Hibernate的遠(yuǎn)程監(jiān)控系統(tǒng)設(shè)計(jì)
架構(gòu)圖如圖1,下面詳細(xì)介紹模塊。
1.1 遠(yuǎn)程監(jiān)控終端采集模塊
用于采集動(dòng)力電池運(yùn)營數(shù)據(jù)并將數(shù)據(jù)上傳。
1.2 數(shù)據(jù)庫集群
數(shù)據(jù)處理中心,負(fù)責(zé)存儲(chǔ)查詢數(shù)據(jù),采用的是ORACLE11gR2 RAC版本。
1.3 遠(yuǎn)程監(jiān)控系統(tǒng)應(yīng)用服務(wù)器集群
數(shù)據(jù)接入服務(wù)器,負(fù)責(zé)接收遠(yuǎn)程終端采集來的數(shù)據(jù)。
1.4 Hibernate中間服務(wù)器模塊
響應(yīng)客戶端的數(shù)據(jù)操作,保證數(shù)據(jù)安全。
1.5 客戶端模塊
包括pc,手機(jī)端等,通過中間服務(wù)器和數(shù)據(jù)庫進(jìn)行數(shù)據(jù)交換。
基于Hibernate的并行查詢主要研究的是數(shù)據(jù)庫安全和快速查詢響應(yīng),因此遠(yuǎn)程監(jiān)控終端采集模塊和應(yīng)用服務(wù)器集群不在此文的研究之中。
2 關(guān)鍵技術(shù)的研究
本項(xiàng)目中通過將數(shù)據(jù)庫按時(shí)間進(jìn)行分區(qū),使海量數(shù)據(jù)合理存儲(chǔ);在查詢端和數(shù)據(jù)庫服務(wù)器集群間添加Hibernate框架中間服務(wù)器,保證數(shù)據(jù)安全;在客戶端用并行查詢的算法提高查詢效率。
2.1 數(shù)據(jù)庫分區(qū)
在存有海量數(shù)據(jù)的表格中,查詢效率非常的低,進(jìn)行按天分區(qū)后,查詢時(shí)間大為縮短但還是未達(dá)到預(yù)期要求,因此我們提出了在分區(qū)基礎(chǔ)上的并行查詢。
2.2 Hibernate中間服務(wù)器
傳統(tǒng)三層編程將客戶端直連數(shù)據(jù)庫,造成了安全隱患。而使用Hibernate架構(gòu),采用中間服務(wù)器處理客戶端請求,避免了將數(shù)據(jù)服務(wù)器直接暴露在公網(wǎng)上,確保了數(shù)據(jù)安全。
2.3 并行查詢算法
本項(xiàng)目并行查詢基于數(shù)據(jù)庫分區(qū)和Hibernate架構(gòu)進(jìn)行。在數(shù)據(jù)庫中,我們將記錄按天進(jìn)行分區(qū),為并行查詢算法提供了可行基礎(chǔ)。
數(shù)據(jù)庫中的記錄雖不斷增加,但每天的記錄是有限的,分區(qū)數(shù)據(jù)具備可操作性。如查詢某輛車某月的數(shù)據(jù),可以將數(shù)據(jù)查詢拆分成30個(gè)并發(fā)線程,每個(gè)線程只查詢一天的記錄,將查詢時(shí)間壓縮至1天。
圖2是兩種查詢方式的流程對(duì)比。
但長時(shí)距數(shù)據(jù),不可能去開啟無限線程,本項(xiàng)目采用了給定線程數(shù)上限按需循環(huán)去解決這個(gè)矛盾。在單個(gè)分區(qū)內(nèi)進(jìn)行查詢效率最高,并行查詢就是將所有的查詢從跨分區(qū)的需求拆分為針對(duì)各個(gè)單獨(dú)數(shù)據(jù)分區(qū)的查詢,使查詢效率大為提高。
本項(xiàng)目客戶端采用C#開發(fā),以單體信息查詢?yōu)槔?,部分代碼示例如下:
2.3.1 首先設(shè)置線程上限。
private long totalCount = 0; //存放計(jì)算結(jié)果
private readonlyintthreadCounts = 30; //處理的線程數(shù)
private static object locker = new object(); //線程鎖
staticTCellInfoDao()
{
intminWorker, minIOC;
ThreadPool.GetMinThreads(out minWorker, out minIOC);
}
2.3.2 計(jì)算并發(fā)線程實(shí)際需要的數(shù)量,開啟線程,在同步完成后給出結(jié)果統(tǒng)計(jì)
/// 并發(fā)計(jì)算count(*)
///
DateTimenextEndTime = DateTime.Parse(endTime.ToString("yyyy-MM-dd ")); //結(jié)束日期前零點(diǎn)時(shí)間 00:00:00
TimeSpants = endTime - nextbeginTime;
double seconds = ts.TotalSeconds;
if (seconds <= 0) //查詢時(shí)間同一天
{
ManualResetEventmre = new ManualResetEvent(false);
manualEvents.Add(mre);
CellParams par = new CellParams();
par.BeginDate = beginTime;
par.EndDate = endTime;
par.BwtId = bwtid;
par.UserID = userID;
par.mrEvent = mre;
ThreadPool.QueueUserWorkItem(CalcCounts, par);
WaitHandle.WaitAll(manualEvents.ToArray()); //等待所有線程執(zhí)行完畢,返回總數(shù)據(jù)
}
else //查詢時(shí)間跨天
{
//計(jì)算開頭和結(jié)尾時(shí)間段中數(shù)據(jù)
DateTime b = beginTime;
DateTime e = nextbeginTime;
for (inti = 0; i< 2; i++)
{
ManualResetEventmre = new ManualResetEvent(false);
manualEvents.Add(mre);
CellParams par = new CellParams();
par.BeginDate = b;
par.EndDate = e;
par.BwtId = bwtid;
par.mrEvent = mre;
par.UserID = userID;
ThreadPool.QueueUserWorkItem(CalcCounts, par);
b = nextEndTime;
e = endTime;
}
if (manualEvents.Count !=0)
WaitHandle.WaitAll(manualEvents.ToArray()); //等待所有線程執(zhí)行完畢,返回總數(shù)據(jù)
if (manualEvents.Count != 0)
{
manualEvents.Clear();
}
//計(jì)算整數(shù)天的數(shù)據(jù)總數(shù)
inttotalDays = (nextEndTime - nextbeginTime).Days;
intprocessCounts = totalDays / threadCounts; //總處理次數(shù),每次處理64條查詢
intlastCounts = totalDays % threadCounts; //剩余天數(shù)
b = nextbeginTime; //開始時(shí)間下一天零點(diǎn)開始
for (inti = 0; i { for (int j = 0; j { ManualResetEventmre = new ManualResetEvent(false); manualEvents.Add(mre); CellParams par = new CellParams(); par.BeginDate = b; par.EndDate = b.AddDays(1); //計(jì)算一天的分區(qū)的數(shù)據(jù)量 par.BwtId = bwtid; par.UserID = userID; par.mrEvent = mre; ThreadPool.QueueUserWorkItem(CalcCounts, par); b = b.AddDays(1); } if (manualEvents.Count != 0) WaitHandle.WaitAll(manualEvents.ToArray()); //等待所有線程執(zhí)行完畢,返回總數(shù)據(jù) if (manualEvents.Count != 0) { manualEvents.Clear(); } } //計(jì)算剩余天數(shù) for (inti = 0; i { ManualResetEventmre = new ManualResetEvent(false); manualEvents.Add(mre);
CellParams par = new CellParams();
par.BeginDate = b;
par.EndDate = b.AddDays(1);
par.BwtId = bwtid;
par.UserID = userID;
par.mrEvent = mre;
ThreadPool.QueueUserWorkItem(CalcCounts, par);
b = b.AddDays(1);
}
if (manualEvents.Count != 0)
WaitHandle.WaitAll(manualEvents.ToArray()); //等待所有線程執(zhí)行完畢,返回總數(shù)據(jù)
if (manualEvents.Count != 0)
{
manualEvents.Clear();
}
}
returntotalCount;
}
3 運(yùn)行情況
采用了基于Hibernate架構(gòu)的并行查詢算法后,按時(shí)間段查詢車輛數(shù)據(jù)的效率提高明顯,單輛車每月數(shù)據(jù)查詢的響應(yīng)時(shí)間提高至0.3秒,每年數(shù)據(jù)查詢的響應(yīng)時(shí)間提高至2秒,用戶使用體驗(yàn)良好,達(dá)到了項(xiàng)目預(yù)期。
4 結(jié)束語
基于Hibernate架構(gòu)的并行查詢算法克服了海量數(shù)據(jù)查詢的難題,數(shù)據(jù)查詢不再受限于數(shù)據(jù)表格中的記錄總數(shù),也減少了對(duì)于查詢的時(shí)間段長短的依賴,在實(shí)際應(yīng)用中很好的滿足了用戶的需求。
參考文獻(xiàn)
[1]孫衛(wèi)琴.精通Hibernate[M].北京:電子工業(yè)出版社,2005.
[2]周亮.Oracle DBA實(shí)戰(zhàn)攻略:運(yùn)維管理、診斷優(yōu)化、高可用與最佳實(shí)踐[M].北京:機(jī)械工業(yè)出版社,2013.
作者簡介
卞林 (1976-),男,大學(xué)本科學(xué)歷。現(xiàn)為合肥國軒高科動(dòng)力能源有限公司工程師。主要研究方向?yàn)殡妱?dòng)汽車遠(yuǎn)程監(jiān)控系統(tǒng)。
鄭中華(1988-),男,碩士學(xué)位?,F(xiàn)為合肥國軒高科動(dòng)力能源有限公司工程師。主要研究方向?yàn)殡妱?dòng)汽車遠(yuǎn)程監(jiān)控系統(tǒng)。
唐曉新(1989-),女,碩士學(xué)位。現(xiàn)為合肥國軒高科動(dòng)力能源有限公司工程師。主要研究方向?yàn)殡妱?dòng)汽車電池管理系統(tǒng)。
作者單位
合肥國軒高科動(dòng)力能源有限公司 安徽省合肥市 230012