none
sugerencia con la cache RRS feed

  • Pregunta

  • hola...

    este es mi caso:
    tengo una aplicacion web desarrollada con .net mvc3 y se utiliza un monton de jquery y
    un monton de peticiones ajax a mi base de datos, estas peticiones lo que hacen
    es llenar combos cajas de texto y cosas asi como cualquier otra aplicacion,
    pero mi duda es como podria utilizar la cache para no estar aciendo tantas peticiones
    a mi base de datos si estas ya estan cargadas en la cache. alguien tendra alguna sugerencia con el tema
    ¿es posible utilizar la cache?


    jose arreola

    lunes, 23 de julio de 2012 20:44

Respuestas

  • En programación multicapas usted tendría una colección que se llena una vez y se reutiliza constantemente.  Suele estar en una clase estática y la colección sería también estática.  Como las páginas web son multiusuario, la colección debe sincronizarse.

    //Clase no estática en la capa de datos con colección estática.
    //Ejemplo que carga objetos Region que rara vez cambian.
    public class Region
    {
        #region Miembros estáticos
        private static List<Region> m_regiones;
        private object _sync = new object();
        public static List<Region> Regiones
        {
            get
            {
                lock (_sync)
                {
                    if (m_regiones == null)
                    {
                        //Solicitarle a la capa de datos (base de datos)
                        //la lista de regiones aquí.
                        //Luego llenar la colección m_regiones.
                    }
                    //Devolver una copia:
                    return new List<Region>(m_regiones);
                }
            }
        }
        #endregion
    
        #region Propiedades
        public int ID { get; protected set; }
        public string Nombre { get; protected set; }
        #endregion
    
        #region Constructores
        public Region(int id, string nombre)
        {
            ID = id;
            Nombre = nombre;
        }
        #endregion
    }

    En el ejemplo se asume que hay una lista de regiones que cambia muy poco, así que la cargamos una única vez (la primera vez que se necesita) y luego nada más devolvemos copias sin tener que consultar la base de datos nuevamente.


    Jose R. MCP
    Code Samples

    • Marcado como respuesta ch-B miércoles, 25 de julio de 2012 15:11
    lunes, 23 de julio de 2012 23:07
    Moderador
  • Concuerdo con WebJose en que la solución consiste en que las peticiones enviadas en modo AJAX desde el cliente atraviesen una clase que se encargue de guardar los resultados en caché, y devolverlos en cada petición sucesiva sin realizar una nueva consulta a la base de datos.

    Pero opino que en lugar de usar una variable estática, es preferible usar el objeto Cache. La ventaja es que en caso de que aumente la presión de memoria sobre el servidor, el Cache descarta automáticamente los datos cacheados menos necesarios, y libera esa memoria para otros usos más importantes. También se le puede configurar una expiración automática para que los datos se actualicen desde la base de datos a la memoria con determinada periodicidad. En suma, en lugar de usar la variable estática el código quedaría así:

        public static List<Region> Regiones
        {
            get
            {
                List<Region> r = Cache["Regiones"] as List<Region>;
                if (r==null)
                {
                    r=(sacar datos de la BD)
                    Cache.Insert("Regiones", r, ...opciones...);
                }
                return r;
            }
        }

    Nótese que he omitido el lock. En caso de que dos hilos entrasen a la rutina simultáneamente, y los dos encontrasen el Cache vacío, se recuperarían los datos dos veces desde la base de datos. La probabilidad de que esto ocurra es lo suficientemente pequeña para que esta recuperación adicional sea en promedio menos costosa que la ejecución del lock a cada llamada para obtener datos. La lectura e inserción en el Cache no necesitan bloqueo en el código que las llama porque internamente son seguras en cuanto al acceso en multihilo.

    • Marcado como respuesta ch-B miércoles, 25 de julio de 2012 15:11
    miércoles, 25 de julio de 2012 6:17

Todas las respuestas

  • En programación multicapas usted tendría una colección que se llena una vez y se reutiliza constantemente.  Suele estar en una clase estática y la colección sería también estática.  Como las páginas web son multiusuario, la colección debe sincronizarse.

    //Clase no estática en la capa de datos con colección estática.
    //Ejemplo que carga objetos Region que rara vez cambian.
    public class Region
    {
        #region Miembros estáticos
        private static List<Region> m_regiones;
        private object _sync = new object();
        public static List<Region> Regiones
        {
            get
            {
                lock (_sync)
                {
                    if (m_regiones == null)
                    {
                        //Solicitarle a la capa de datos (base de datos)
                        //la lista de regiones aquí.
                        //Luego llenar la colección m_regiones.
                    }
                    //Devolver una copia:
                    return new List<Region>(m_regiones);
                }
            }
        }
        #endregion
    
        #region Propiedades
        public int ID { get; protected set; }
        public string Nombre { get; protected set; }
        #endregion
    
        #region Constructores
        public Region(int id, string nombre)
        {
            ID = id;
            Nombre = nombre;
        }
        #endregion
    }

    En el ejemplo se asume que hay una lista de regiones que cambia muy poco, así que la cargamos una única vez (la primera vez que se necesita) y luego nada más devolvemos copias sin tener que consultar la base de datos nuevamente.


    Jose R. MCP
    Code Samples

    • Marcado como respuesta ch-B miércoles, 25 de julio de 2012 15:11
    lunes, 23 de julio de 2012 23:07
    Moderador
  • Concuerdo con WebJose en que la solución consiste en que las peticiones enviadas en modo AJAX desde el cliente atraviesen una clase que se encargue de guardar los resultados en caché, y devolverlos en cada petición sucesiva sin realizar una nueva consulta a la base de datos.

    Pero opino que en lugar de usar una variable estática, es preferible usar el objeto Cache. La ventaja es que en caso de que aumente la presión de memoria sobre el servidor, el Cache descarta automáticamente los datos cacheados menos necesarios, y libera esa memoria para otros usos más importantes. También se le puede configurar una expiración automática para que los datos se actualicen desde la base de datos a la memoria con determinada periodicidad. En suma, en lugar de usar la variable estática el código quedaría así:

        public static List<Region> Regiones
        {
            get
            {
                List<Region> r = Cache["Regiones"] as List<Region>;
                if (r==null)
                {
                    r=(sacar datos de la BD)
                    Cache.Insert("Regiones", r, ...opciones...);
                }
                return r;
            }
        }

    Nótese que he omitido el lock. En caso de que dos hilos entrasen a la rutina simultáneamente, y los dos encontrasen el Cache vacío, se recuperarían los datos dos veces desde la base de datos. La probabilidad de que esto ocurra es lo suficientemente pequeña para que esta recuperación adicional sea en promedio menos costosa que la ejecución del lock a cada llamada para obtener datos. La lectura e inserción en el Cache no necesitan bloqueo en el código que las llama porque internamente son seguras en cuanto al acceso en multihilo.

    • Marcado como respuesta ch-B miércoles, 25 de julio de 2012 15:11
    miércoles, 25 de julio de 2012 6:17
  • Sí, la clase System.Web.Caching.Cache es bien interesante y útil.  El detalle es que está ligada a System.Web entonces no suelo ni acordarme que existe ya que yo suelo proveer el cache en la capa de negocio o datos según lo necesite.  Esta clase está muy ligada a la capa gráfica y es lo que no me gusta.

    Pero en fin, sí es cierto que tiene todas las ventajas que Alberto menciona, y si no tiene usted inconveniente en mantener el cache en la capa gráfica, pues adelante que le trabajará muy bien según lo menciona Alberto.

    Sí debo mencionar que me parece muy interesante su último párrafo acerca de la sincronización de hilos.  Sería genial si hubiera alguna experimentación documentada al respecto, pues suelo ser bastante estricto en cuanto a sincronizar siempre que deba hacerse.

    ACTUALIZACIÓN:  MSDN dice que la clase es thread-safe.  Así que podemos obviar el comentario último de mi parte, pues el uso del lock es casi irrelevante.  Sí, sería igual bonito ver si hay tiempos documentados, pero por lo menos me queda claro que la sincronización ya se da internamente.


    Jose R. MCP
    Code Samples


    miércoles, 25 de julio de 2012 6:46
    Moderador
  • El truco para usar la Cache desde la capa de negocio o de datos es añadir una referencia a System.Web.dll, y llamar al cache como HttpContext.Current.Cache. Esto sólo funciona si dicha capa de negocios o de datos se va a usar exclusivamente desde aplicaciones web; si se llamara a la misma DLL desde una aplicación de escritorio, HttpContext.Current devolvería null.

    miércoles, 25 de julio de 2012 7:27