C# - Adatbázis lekérdezés eredményének és tetszőleges egyéb adatok tárolása a Cache-ben

Web Cache 2. rész

forráskód letöltése
ASP.NET alkalmazásaink készítésekor lehetőségünk van arra, hogy egy átmeneti tárolóban ne csak egy teljes web oldal tartalmát helyezzük el későbbi felhasználás céljából, hanem az is megvalósítható, hogy például egy lekérdezés eredményhalmazát tároljuk, vagy egy TXT állomány tartalmát, vagy tulajdonképpen bármilyen adatot, amire csak szükségünk lehet a web oldal létrehozásánál. Ennek előnye egyértelmű: hiszen ha egy (vagy több) web oldalra egy TXT állomány tartalmát kell megjeleníteni, akkor nem kell állandóan a háttértárhoz fordulni és beolvasni azt. Ugyanígy az adatbázis szerverünk is pihenhet, feltéve, hogy lekérdezésünk olyan jellegű, hogy mindig ugyanazt az eredményt produkálná, ilyenkor felesleges is lenne állandó lekérdezésekkel terhelni a szervert.
Mellékelt példánkban két web lapot tartalmazó programot készítünk. Az elsőt a WebForm1.aspx szolgáltatja és egy MS SQL adatbázisban futtatott lekérdezés eredményét fogja a cache-be helyezni és szükség esetén onnan felhasználni. A második oldalon, a WebForm2.aspx-nél egy TXT állomány tartalmát helyezzük a cache-re, méghozzá úgy, hogy ha annak tartalma változna, akkor a cache-ben tárolt adatok automatikusan érvényüket veszítsék.
Menjünk sorban, és nézzük az első oldal létrehozását. A Page_Load eseménynél gondoskodunk a DataGrid-ben megjelenítendő adatok létrehozásáról. Ennek két módja lehet: vagy a cache-ből vesszük az adatokat, vagy ha ott nem állnak rendelkezésre, akkor futtatunk egy lekérdezést a Northwind példaadatbázisra. Nyilvánvaló, hogy a web oldal első megjelenítésekor a cache-ben még nem lesz adat, így ekkor csak a lekérdezés marad megoldásként.
  private void Page_Load(object sender, System.EventArgs e)
  {
Első lépésként tehát azt kell ellenőriznünk, hogy a cache-ben található-e adat. A cache műveletekhez a Cache osztályt kell használnunk. Ennek Item property-jén keresztül érhetjük el a cache-ben tárolt adatokat, melyeknek mi adhatunk egyedi nevet. A most tárolandó lekérdezésünk eredményhalmazának a ProductData nevet választottuk. A tárolásra kerülő adat nem más, mint egy DataView osztály. Így az alábbi sorral megpróbáljuk ezt az eltárolt adatot beolvasni egy DataView osztályba.
      DataView dv = (DataView)Cache["ProductData"];
Ha a cache-ben nem található ProductData nevű objektum, akkor a visszatérési érték null.
      if (dv == null) 
      {
Ebben az esetben tudhatjuk, hogy a keresett adat a cache-ben nem található meg, így kénytelenek vagyunk egy lekérdezést futtatni. Az MS SQL szerverrel való kapcsolatfelvételre az alábbi sornál szükség esetén meg kell változtatnia a server, User ID és Password paraméterek értékét.
        SqlConnection connection = new SqlConnection("server=;User ID=sa;Password=;database=Northwind;Trusted_Connection=yes");
A lekérdezéshez egy SqlDataAdapter osztályt használunk és a Product tábla összes sorából a ProductID és ProductName mezőket kérdezzük le.
        SqlDataAdapter da = new SqlDataAdapter("select ProductID, ProductName from Products", connection);
Létrehozunk és feltöltünk egy DataSet osztályt a lekérdezés eredményével.
        DataSet ds = new DataSet();
        da.Fill(ds, "Products");
Majd kreálunk egy új DataView osztályt az adatok megjelenítése érdekében, valamint majd ezt az objektumot helyezzük el a cache-ben is.
        dv = new DataView(ds.Tables["Products"]);
A cache-ben történő elhelyezésre ismét a Cache osztályt használjuk.
        Cache["ProductData"] = dv;
        Label1.Text = "Az adatok lekérdezés útján jöttek létre.";
        Button1.Enabled = false;
      }
      else 
      {
Abban az esetben, ha az első sorban lévő cache lekérdezés nem null értéket adott vissza, vagyis a ProductData nevű objektum már megtalálható a cache-ben, akkor nincs más teendőnk, mint ezt jelezni, hiszen ekkor a dv nevű DataView osztály már tartalmazza a lekérdezés eredményét.
        Label1.Text = "Az adatok a cache-ből származnak.";
        Button1.Enabled = true;
      }
Így a megjelenítéshez már csak arra van szükségünk, hogy a DataGrid-hez kapcsoljuk a DataView osztály adatait.
      DataGrid1.DataSource=dv;
      DataGrid1.DataBind();        
    }
A programot futtatva, ha böngészőben felváltva kattintunk a WebForm1 és WebForm2 linkre, akkor látható, hogy a Label1 szövege az első kéréskor még azt jelzi, hogy „az adatok lekérdezés útján jöttek létre”, majd az ezt követő esetekben már csak „az adatok a cache-ből származnak” jelzés látható. Ezzel elértük a kívánt célt: az adat lekérdezés csak egyszer történik meg, majd ezután már a memóriából történik az adatok előkeresése.
Lehetőségünk van arra is természetesen, hogy a cache-ből eltávolítsunk egy-egy objektumot. Ehhez a Cache osztály Remove függvényét kell meghívnunk, paraméterként a törlendő objektum nevét átadni.
    private void Button1_Click(object sender, System.EventArgs e)
    {
      Cache.Remove("ProductData");
      Response.Redirect("WebForm1.aspx");
    }
Ezt kipróbálva látható, hogy a törlés után megjelenő oldalon ismét az adatbázisból történt meg a lekérdezés.
Nézzük most a második oldal elkészítését. Itt az a feladat, hogy egy Data.txt nevű állomány tartalma jelenjen meg egy web lapon úgy, hogy a Data.txt a cache-en legyen tárolva a további felhasználáshoz. További cél, hogy ha a Data.txt tartalma változik, akkor a cache-en tárolt adat érvénytelenítve legyen.
Ennek az oldalnak a teszteléséhez tegye a következőket:
  • Nyissa meg ezt az oldalt.
  • Kattintson többször a Frissítés (Refresh) gombra. Első alkalommal az állomány beolvasásra kerül, a további alkalmakkor már a cache-ből jön az adat.
  • Változtassa meg a Data.txt tartalmát, miközben a böngészőt hagyja a WebForm2.aspx oldalon.
  • Ismét frissítse az oldalt a böngészőben. Mivel a Data.txt tartalma változott, most ismét beolvasásra kerül és újbóli tárolásra a cache-re.
A megvalósítás hasonló az előző oldaléhoz. Először itt is ellenőrizzük, hogy a szükséges adat már megtalálható-e a cache-en. Ennek most StringData nevet adtunk. Az objektum pedig egy egyszerű string objektum, mely tartalmazza a Data.txt állomány teljes szövegét sztringként.
Lekérdezzük tehát az objektumot a cache-ből, majd ismét ellenőrizzük, hogy létezett-e már ez az objektum, vagyis a visszaadott érték null-e vagy sem.
  private void Page_Load(object sender, System.EventArgs e)
  {
      string s = (string)Cache["StringData"];
      if (s == null) 
      {
Ha még nem volt a cache-en tárolva, akkor kénytelenek leszünk beolvasni a tartalmat a háttértárról. Ehhez a StreamReader osztályt használjuk.
        StreamReader sr = new StreamReader(Server.MapPath("data.txt"));
Ennek ReadToEnd függvénye egy lépésben beolvassa és sztringként visszaadja a txt tartalmát.
        s = sr.ReadToEnd();
Zárjuk az állományt a Close-al.
        sr.Close();
Majd elhelyezzük a kapott sztringet a Cache-ben. Itt most a Cache osztály Insert függvényét használjuk. Ennek első paraméterében megadjuk az objektumunk nevét, másodikban pedig a tárolandó objektumot. A harmadik paraméterben rendelkezünk arról, hogy milyen függőségi viszony áll fenn a tárolt adattal kapcsolatban. Itt egy CacheDependency osztály példányát kell átadnunk, melyet most úgy hozunk létre, hogy paraméterként megadjuk annak az állománynak az elérési útvonalát és nevét, melytől függ a cache-ben tárolt adat. Így ettől kezdve nincs gondunk a tárolt adatra, hiszen ha az itt megadott állomány tartalma megváltozik, akkor a cache-ből automatikusan törölve lesz a StringData objektumunk, így a következő web kérésnél ismét be kell olvasnunk annak tartalmát.
        Cache.Insert("StringData", s, new CacheDependency(Server.MapPath("data.txt")));
        Label1.Text = "Az adatok a Data.txt-ből lettek beolvasva.";
      }      
Ha az adat már megtalálható volt a cache-ben, akkor nincs különösebb dolgunk, mint jelezni ezt.
      else 
      {
        Label1.Text = "Az adatok a cache-ből származnak.";
      }      
Végezetül megjelenítjük az adatot egy Label kontrol segítségével.
      Label3.Text = s;
    }
Amint a fentiekből látható is a Cache-re bármilyen típusú objektumot helyezhetünk, nem csak egy lekérdezés eredményét, vagy egy sztringet. Ezt kihasználva nagymértékben gyorsíthatjuk a feldolgozást és csökkenthetjük rendszerünk terhelését.

Web Cache cikksorozat

ASP.NET Web oldalak átmeneti tárolása - Web Cache 1. rész

Adatbázis lekérdezés eredményének és tetszőleges egyéb adatok tárolása a Cache-ben - Web Cache 2. rész

Cache-ben tárolt adatok élettartamának meghatározása - Web Cache 3. rész