舒畅 发表于 2015-11-18 13:25:56

memcached缓存服务器.net开发应用

要点
  memcached, Enyim, log4net, Newtonsoft.Json
   一 环境

   注意Enyim,log4net,memcached的版本,如果与下面不一至,调试运行中有可能出现问题



1.memcached客户端

   Enyim.Caching.dllv2.12.0.0

   Enyim.Caching.Log4NetAdapter.dllv2.12.0.0

   log4net.dll   v1.2.10.0

2.memcached服务端

   memcached-win32v1.4.4-14

3.数据输出及提供

   数据输出格式:json

   数据提供:WebService

4.dataSet转json

   组件:Newtonsoft.Json.dllv4.0.8.14612

5.开发工具

   visual studio 2010

6.dotNet

   开发版本:.netv3.5

   运行版本:.netv2.0.50727


  二 memcached安装启动

1.安装

memcached.exe -d install

服务启动后, memcached 默认使用 64M 内存和 11211 端口作为服务器参数。

如果你希望调整参数,请参考: memcached.exe -h



2.启动

memcached.exe -m 512 -p 33000 -d start

-d为守护进程启动

-m为指定内存大小

-p指定端口,默认端口11211



3.测试memcached

d:\>telnet localhost 11211

add firstKey 0 0 15

Hello Memcached

STORED

get firstKey

VALUE firstKey 0 15

Hello Memcached

END

quit


  


  三 memcached及log4net配置(Web.config)


  

<!--配置memcached服务器及log4net日志-->
<configuration>
<configSections>
<!--... 其它配置 -->
<!--log4net日志配置-->
<section name=&quot;log4net&quot; type=&quot;log4net.Config.Log4NetConfigurationSectionHandler,log4net&quot;/>
<!--缓存客户端配置-->
<sectionGroup name=&quot;enyim.com&quot;>
<section name=&quot;memcached&quot; type=&quot;Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching&quot;/>
<section name=&quot;log&quot; type=&quot;Enyim.Caching.Configuration.LoggerSection, Enyim.Caching&quot;/>
</sectionGroup>
<section name=&quot;memcached&quot; type=&quot;Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching&quot;/>
</configSections>
<!--缓存客户端配置-->
<enyim.com>
<log factory=&quot;Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter&quot;/>
<memcached>
<servers>
<add address=&quot;192.168.0.45&quot; port=&quot;11211&quot;/>
</servers>
<socketPool minPoolSize=&quot;1000&quot; maxPoolSize=&quot;2000&quot; connectionTimeout=&quot;00:00:10&quot; deadTimeout=&quot;00:05:00&quot;/>
</memcached>
</enyim.com>
<memcached>
<servers>
<add address=&quot;192.168.0.45&quot; port=&quot;11211&quot;/>
</servers>
<socketPool minPoolSize=&quot;1000&quot; maxPoolSize=&quot;2000&quot; connectionTimeout=&quot;00:00:10&quot; deadTimeout=&quot;00:05:00&quot;/>
</memcached>
<!--log4net日志配置-->
<!--Basic log4net config. Don't forget to call log4net.Config.XmlConfigurator.Configure(); at the start of your app.-->
<log4net>
<root>
<level value=&quot;ALL&quot;/>
<appender-ref ref=&quot;RollingLogFileAppender&quot;/>
<appender-ref ref=&quot;ConsoleAppender&quot;/>
<appender-ref ref=&quot;TraceAppender&quot;/>
</root>
<logger name=&quot;Enyim.Caching.Memcached.DefaultNodeLocator&quot;>
<level value=&quot;Debug&quot;/>
</logger>
<logger name=&quot;Enyim.Caching.Memcached.PooledSocket&quot;>
<level value=&quot;Info&quot;/>
</logger>
<logger name=&quot;Enyim.Caching.Memcached.Protocol&quot;>
<level value=&quot;Info&quot;/>
</logger>
<logger name=&quot;Membase.VBucketAwareOperationFactory&quot;>
<level value=&quot;Info&quot;/>
</logger>
<logger name=&quot;Enyim.Caching.Memcached.MemcachedNode&quot;>
<level value=&quot;Info&quot;/>
</logger>
<appender name=&quot;RollingLogFileAppender&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;>
<param name=&quot;File&quot; value=&quot;LogFiles/&quot;/>
<param name=&quot;AppendToFile&quot; value=&quot;true&quot;/>
<param name=&quot;MaxSizeRollBackups&quot; value=&quot;10&quot;/>
<param name=&quot;StaticLogFileName&quot; value=&quot;false&quot;/>
<param name=&quot;DatePattern&quot; value=&quot;yyyy-MM-dd&quot;.txt&quot;&quot;/>
<param name=&quot;RollingStyle&quot; value=&quot;Date&quot;/>
<layout type=&quot;log4net.Layout.PatternLayout&quot;>
<param name=&quot;ConversionPattern&quot; value=&quot;%d{yyyy-MM-dd HH:mm:ss}[%thread] %-5level %c %L %F - %message%newline&quot;/>
</layout>
<footer value=&quot;by anyx&quot;/>
</appender>
<appender name=&quot;ConsoleAppender&quot; type=&quot;log4net.Appender.ConsoleAppender&quot;>
<layout type=&quot;log4net.Layout.PatternLayout,log4net&quot;>
<param name=&quot;ConversionPattern&quot; value=&quot;%d [%t] %-5p %c %m%n&quot;/>
</layout>
</appender>
<appender name=&quot;TraceAppender&quot; type=&quot;log4net.Appender.TraceAppender&quot;>
<layout type=&quot;log4net.Layout.PatternLayout,log4net&quot;>
<param name=&quot;ConversionPattern&quot; value=&quot;%d [%t] %-5p %c %m%n&quot;/>
</layout>
</appender>
</log4net>
<!-- 缓存期限 -->
<appSettings>
<add key=&quot;cachingTime&quot; value=&quot;120&quot;/>
</appSettings>
<!-- 数据库连接 -->
<connectionStrings>
<add name=&quot;dbConnStr&quot; connectionString=&quot;Data Source=APPCtl;User ID=appuser;Password=appuser123;Integrated Security = false&quot; providerName=&quot;System.Data.OracleClient&quot;/>
</connectionStrings>
<system.web>
<!-- 用于跨域调用 -->
<webServices>
<protocols>
<add name=&quot;HttpGet&quot;/>
<add name=&quot;HttpPost&quot;/>
</protocols>
</webServices>
<!--... 其它配置 -->
</system.web>
<!--... 其它配置 -->
</configuration>

四 log4net初始化

初始化Web.config中配置的log4net

在Global.asax下:protected void Application_Start(object sender, EventArgs e)
{
//log4net初始化
//程序启动加入,在Web.config log4net:RollingLogFileAppender:file对应的日志目录或日志文件
log4net.Config.XmlConfigurator.Configure();
}五 读取写入缓存的类

    注意,以下读取写入Memcached是基于memcached v1.4以后的版本

    建一个类,用于读取和写入Memcached.public class CachedService
{
private static MemcachedClient mc = new MemcachedClient();
/// <summary>
/// 从缓存服务器取出数据
/// </summary>
/// <param name=&quot;key&quot;></param>
/// <returns></returns>
public static object getObjectFromCached(string key)
{
//...
Object obj = null;
IGetOperationResult result = mc.ExecuteGet(key);
if (result.HasValue)
{
obj = result.Value;
}
return obj;
//...
}
/// <summary>
/// 存入数据到缓存服务器
/// </summary>
/// <param name=&quot;key&quot;></param>
/// <returns></returns>
public static bool setObjectToCached(string key, object obj)
{
//读取Web.config配置中的缓存时间
double cachintTime = 0;
string ct = System.Configuration.ConfigurationManager.AppSettings[&quot;cachingTime&quot;];
if (!string.IsNullOrEmpty(ct))
{
cachintTime = Convert.ToDouble(ct);
}
//缓存数据
IStoreOperationResult result = mc.ExecuteStore(StoreMode.Set, key, obj, DateTime.Now.AddMinutes(cachintTime));
if (result.Success)
{
return true;
}
else
{
string me = result.Message;
int code = Convert.ToInt32(result.StatusCode);
return false;
}
}
}六 缓存与数据库

取数据首先查看Memcached缓存服务器是否有对应键的数据对象,如果有,就直接取出,如果没有,就从数据库取出,再按相应键存入Memcached.

         /// <summary>
/// 每日龙虎榜:最近交易日:缺省数据:分页(缓存服务器)
/// </summary>
/// <returns>返回Json格式字符串</returns>
public class SomeClass
{   
public string getSomeData(int start,int limit,string sf,string sr)
{
if (string.IsNullOrEmpty(sf) || string.IsNullOrEmpty(sr))
{
//某些参数为空,返回
return &quot;{\&quot;total\&quot;:0,\&quot;rows\&quot;:[]}&quot;; ;
}
string json = &quot;&quot;;
//缓存服务器唯一标识,命名很重要
//在这里我采用的是查询条件作为缓存标识
string key = &quot;edaylhb:&quot; + start + &quot;:&quot; + limit + &quot;:&quot; + sf + &quot;:&quot; + sr;
//从缓存服务器中取对应key的数据
Object obj = CachedService.getObjectFromCached(key);
if (obj != null)
{
//缓存服务器中有数据
json = (string)obj;
}
else
{
//缓存服务器中无数据,去数据库取,再保存到缓存服务器
//查询数据库,返回dataset ds
//...各种sql查询
try{
string ds2Str = &quot;&quot;;
//如果ds不为空,转换为Json格式
ds2Str = DbUtil.dataSet2Json(ds);
ds.Dispose();
//拼接成Json格式
if (ds.Tables.Rows.Count == 0)
{
json = &quot;{\&quot;total\&quot;:0,\&quot;rows\&quot;:[]}&quot;;
}
else
{
json = &quot;{\&quot;total\&quot;:&quot; + ds.Tables.Rows.Count + &quot;,\&quot;rows\&quot;:&quot; + ds2Str + &quot;}&quot;;
}
//保存数据到缓存服务器
CachedService.setObjectToCached(key, json);
}
catch (Exception ex)
{
//异常记录到日志
Log4netService.log4netFatal(MethodBase.GetCurrentMethod().DeclaringType, ex);
throw ex;
}
}
return json;
}
}七 dataSet转jsonpublic static string dataSet2Json(DataSet ds)
{
string jsonStr = null;
//Newtonsoft.Json在转换日期的时候,会出现格式和时区(差8小时)差别Trade_Status_Name
//如果不作如下格式转换,会出现形如Date(1335247957000+0800)/的日期
IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
//这里使用自定义日期格式,如果不使用的话,默认是ISO8601格式
timeConverter.DateTimeFormat = &quot;yyyy'-'MM'-'dd' 'HH':'mm':'ss&quot;;
jsonStr = JsonConvert.SerializeObject(ds.Tables, Formatting.Indented, timeConverter);
//jsonStr = &quot;[{Stk_Code:'601398',Stk_name:'工商银行'},{Stk_Code:'500999',Stk_name:'农业银行'}]&quot;;
return jsonStr;
}八WebService调用及返回Json数据
public class TestWebService : System.Web.Services.WebService
{
/// <summary>
/// </summary>

public void getTestData()
{
string cb = Context.Request[&quot;callback&quot;];   //跨域服务器发送jsonp的参数key
int start = Convert.ToInt32(string.IsNullOrEmpty(Context.Request[&quot;start&quot;]) ? &quot;1&quot; : Context.Request[&quot;start&quot;]);//从第几页开始:默认第一次从1开始,next_start=start+limit
int limit = Convert.ToInt32(string.IsNullOrEmpty(Context.Request[&quot;limit&quot;]) ? &quot;20&quot; : Context.Request[&quot;limit&quot;]);//每次取的条数(步进):默认每页20条
string sf = string.IsNullOrEmpty(Context.Request[&quot;sf&quot;]) ? &quot;se_code&quot; : Context.Request[&quot;sf&quot;]; //sortField 排序字段,默认:se_code
string sr = string.IsNullOrEmpty(Context.Request[&quot;sr&quot;]) ? &quot;asc&quot; : Context.Request[&quot;sr&quot;];//sortRule 排序规则,默认:asc
SomeClass svr = new SomeClass();
string json = svr.getSomeData(start, limit, sf, sr);
Context.Response.ContentType = &quot;text/plain; charset=utf-8&quot;;
//Context.Response.Write(cb + &quot;({\&quot;total\&quot;:30,\&quot;rows\&quot;:[{\&quot;ID\&quot;:1,\&quot;NAME\&quot;:\&quot;John\&quot;},{\&quot;ID\&quot;:2,\&quot;NAME\&quot;:\&quot;Mike\&quot;}]})&quot;);
Context.Response.Write(cb + &quot;(&quot; + json + &quot;)&quot;);
}
}








  

版权声明:本文为博主原创文章,未经博主允许不得转载。
页: [1]
查看完整版本: memcached缓存服务器.net开发应用