memcached enyim client
要点
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)
viewplaincopy
[*]<!--配置memcached服务器及log4net日志-->
[*]<configuration>
[*]<configSections>
[*] <!--... 其它配置 -->
[*]
[*] <!--log4net日志配置-->
[*] <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
[*] <!--缓存客户端配置-->
[*] <sectionGroup name="enyim.com">
[*] <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
[*] <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching"/>
[*] </sectionGroup>
[*] <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
[*]</configSections>
[*]<!--缓存客户端配置-->
[*]<enyim.com>
[*] <log factory="Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter"/>
[*] <memcached>
[*] <servers>
[*] <add address="192.168.0.45" port="11211"/>
[*] </servers>
[*] <socketPool minPoolSize="1000" maxPoolSize="2000" connectionTimeout="00:00:10" deadTimeout="00:05:00"/>
[*] </memcached>
[*]</enyim.com>
[*]<memcached>
[*] <servers>
[*] <add address="192.168.0.45" port="11211"/>
[*] </servers>
[*] <socketPool minPoolSize="1000" maxPoolSize="2000" connectionTimeout="00:00:10" deadTimeout="00:05:00"/>
[*]</memcached>
[*]<!--log4net日志配置-->
[*]<!--Basic log4net config. Don't forget to call log4net.Config.XmlConfigurator.Configure(); at the start of your app.-->
[*]<log4net>
[*] <root>
[*] <level value="ALL"/>
[*] <appender-ref ref="RollingLogFileAppender"/>
[*] <appender-ref ref="ConsoleAppender"/>
[*] <appender-ref ref="TraceAppender"/>
[*] </root>
[*] <logger name="Enyim.Caching.Memcached.DefaultNodeLocator">
[*] <level value="Debug"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.PooledSocket">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.Protocol">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Membase.VBucketAwareOperationFactory">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.MemcachedNode">
[*] <level value="Info"/>
[*] </logger>
[*] <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
[*] <param name="File" value="LogFiles/"/>
[*] <param name="AppendToFile" value="true"/>
[*] <param name="MaxSizeRollBackups" value="10"/>
[*] <param name="StaticLogFileName" value="false"/>
[*] <param name="DatePattern" value="yyyy-MM-dd".txt""/>
[*] <param name="RollingStyle" value="Date"/>
[*] <layout type="log4net.Layout.PatternLayout">
[*] <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%thread] %-5level %c %L %F - %message%newline"/>
[*] </layout>
[*] <footer value="by anyx"/>
[*] </appender>
[*] <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
[*] <layout type="log4net.Layout.PatternLayout,log4net">
[*] <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
[*] </layout>
[*] </appender>
[*] <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
[*] <layout type="log4net.Layout.PatternLayout,log4net">
[*] <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
[*] </layout>
[*] </appender>
[*]</log4net>
[*]<!-- 缓存期限 -->
[*]<appSettings>
[*] <add key="cachingTime" value="120"/>
[*]</appSettings>
[*]<!-- 数据库连接 -->
[*]<connectionStrings>
[*] <add name="dbConnStr" connectionString="Data Source=APPCtl;User ID=appuser;Password=appuser123;Integrated Security = false" providerName="System.Data.OracleClient"/>
[*]</connectionStrings>
[*]<system.web>
[*] <!-- 用于跨域调用 -->
[*] <webServices>
[*] <protocols>
[*] <add name="HttpGet"/>
[*] <add name="HttpPost"/>
[*] </protocols>
[*] </webServices>
[*] <!--... 其它配置 -->
[*]</system.web>
[*]<!--... 其它配置 -->
[*]</configuration>
viewplaincopy
[*]<span style="font-size:14px;"><!--配置memcached服务器及log4net日志-->
[*]<configuration>
[*]<configSections>
[*] <!--... 其它配置 -->
[*]
[*] <!--log4net日志配置-->
[*] <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
[*] <!--缓存客户端配置-->
[*] <sectionGroup name="enyim.com">
[*] <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
[*] <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching"/>
[*] </sectionGroup>
[*] <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
[*]</configSections>
[*]<!--缓存客户端配置-->
[*]<enyim.com>
[*] <log factory="Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter"/>
[*] <memcached>
[*] <servers>
[*] <add address="192.168.0.45" port="11211"/>
[*] </servers>
[*] <socketPool minPoolSize="1000" maxPoolSize="2000" connectionTimeout="00:00:10" deadTimeout="00:05:00"/>
[*] </memcached>
[*]</enyim.com>
[*]<memcached>
[*] <servers>
[*] <add address="192.168.0.45" port="11211"/>
[*] </servers>
[*] <socketPool minPoolSize="1000" maxPoolSize="2000" connectionTimeout="00:00:10" deadTimeout="00:05:00"/>
[*]</memcached>
[*]<!--log4net日志配置-->
[*]<!--Basic log4net config. Don't forget to call log4net.Config.XmlConfigurator.Configure(); at the start of your app.-->
[*]<log4net>
[*] <root>
[*] <level value="ALL"/>
[*] <appender-ref ref="RollingLogFileAppender"/>
[*] <appender-ref ref="ConsoleAppender"/>
[*] <appender-ref ref="TraceAppender"/>
[*] </root>
[*] <logger name="Enyim.Caching.Memcached.DefaultNodeLocator">
[*] <level value="Debug"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.PooledSocket">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.Protocol">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Membase.VBucketAwareOperationFactory">
[*] <level value="Info"/>
[*] </logger>
[*] <logger name="Enyim.Caching.Memcached.MemcachedNode">
[*] <level value="Info"/>
[*] </logger>
[*] <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
[*] <param name="File" value="LogFiles/"/>
[*] <param name="AppendToFile" value="true"/>
[*] <param name="MaxSizeRollBackups" value="10"/>
[*] <param name="StaticLogFileName" value="false"/>
[*] <param name="DatePattern" value="yyyy-MM-dd".txt""/>
[*] <param name="RollingStyle" value="Date"/>
[*] <layout type="log4net.Layout.PatternLayout">
[*] <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%thread] %-5level %c %L %F - %message%newline"/>
[*] </layout>
[*] <footer value="by anyx"/>
[*] </appender>
[*] <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
[*] <layout type="log4net.Layout.PatternLayout,log4net">
[*] <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
[*] </layout>
[*] </appender>
[*] <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
[*] <layout type="log4net.Layout.PatternLayout,log4net">
[*] <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
[*] </layout>
[*] </appender>
[*]</log4net>
[*]<!-- 缓存期限 -->
[*]<appSettings>
[*] <add key="cachingTime" value="120"/>
[*]</appSettings>
[*]<!-- 数据库连接 -->
[*]<connectionStrings>
[*] <add name="dbConnStr" connectionString="Data Source=APPCtl;User ID=appuser;Password=appuser123;Integrated Security = false" providerName="System.Data.OracleClient"/>
[*]</connectionStrings>
[*]<system.web>
[*] <!-- 用于跨域调用 -->
[*] <webServices>
[*] <protocols>
[*] <add name="HttpGet"/>
[*] <add name="HttpPost"/>
[*] </protocols>
[*] </webServices>
[*] <!--... 其它配置 -->
[*]</system.web>
[*]<!--... 其它配置 -->
[*]</configuration></span>
四 log4net初始化
初始化Web.config中配置的log4net
在Global.asax下:
viewplaincopy
[*]protected void Application_Start(object sender, EventArgs e)
[*]{
[*] //log4net初始化
[*] //程序启动加入,在Web.config log4net:RollingLogFileAppender:file对应的日志目录或日志文件
[*] log4net.Config.XmlConfigurator.Configure();
[*]}
viewplaincopy
[*]<span style="font-size:14px;">protected void Application_Start(object sender, EventArgs e)
[*]{
[*] //log4net初始化
[*] //程序启动加入,在Web.config log4net:RollingLogFileAppender:file对应的日志目录或日志文件
[*] log4net.Config.XmlConfigurator.Configure();
[*]}</span>
五 读取写入缓存的类
注意,以下读取写入Memcached是基于memcached v1.4以后的版本
建一个类,用于读取和写入Memcached.
viewplaincopy
[*]public class CachedService
[*] {
[*] private static MemcachedClient mc = new MemcachedClient();
[*] /// <summary>
[*] /// 从缓存服务器取出数据
[*] /// </summary>
[*] /// <param name="key"></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="key"></param>
[*] /// <returns></returns>
[*] public static bool setObjectToCached(string key, object obj)
[*] {
[*] //读取Web.config配置中的缓存时间
[*] double cachintTime = 0;
[*] string ct = System.Configuration.ConfigurationManager.AppSettings["cachingTime"];
[*] 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;
[*] }
[*] }
[*] }
viewplaincopy
[*]<span style="font-size:14px;">public class CachedService
[*] {
[*] private static MemcachedClient mc = new MemcachedClient();
[*] /// <summary>
[*] /// 从缓存服务器取出数据
[*] /// </summary>
[*] /// <param name="key"></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="key"></param>
[*] /// <returns></returns>
[*] public static bool setObjectToCached(string key, object obj)
[*] {
[*] //读取Web.config配置中的缓存时间
[*] double cachintTime = 0;
[*] string ct = System.Configuration.ConfigurationManager.AppSettings["cachingTime"];
[*] 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;
[*] }
[*] }
[*] }</span>
六 缓存与数据库
取数据首先查看Memcached缓存服务器是否有对应键的数据对象,如果有,就直接取出,如果没有,就从数据库取出,再按相应键存入Memcached.
viewplaincopy
[*] /// <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 "{\"total\":0,\"rows\":[]}"; ;
[*] }
[*]
[*] string json = "";
[*]
[*] //缓存服务器唯一标识,命名很重要
[*] //在这里我采用的是查询条件作为缓存标识
[*] string key = "edaylhb:" + start + ":" + limit + ":" + sf + ":" + sr;
[*]
[*] //从缓存服务器中取对应key的数据
[*] Object obj = CachedService.getObjectFromCached(key);
[*]
[*] if (obj != null)
[*] {
[*] //缓存服务器中有数据
[*] json = (string)obj;
[*] }
[*] else
[*] {
[*] //缓存服务器中无数据,去数据库取,再保存到缓存服务器
[*]
[*] //查询数据库,返回dataset ds
[*]
[*] //...各种sql查询
[*]
[*] try{
[*] string ds2Str = "";
[*]
[*] //如果ds不为空,转换为Json格式
[*] ds2Str = DbUtil.dataSet2Json(ds);
[*] ds.Dispose();
[*]
[*]
[*] //拼接成Json格式
[*] if (ds.Tables.Rows.Count == 0)
[*] {
[*] json = "{\"total\":0,\"rows\":[]}";
[*] }
[*] else
[*] {
[*] json = "{\"total\":" + ds.Tables.Rows.Count + ",\"rows\":" + ds2Str + "}";
[*] }
[*] //保存数据到缓存服务器
[*] CachedService.setObjectToCached(key, json);
[*] }
[*] catch (Exception ex)
[*] {
[*] //异常记录到日志
[*] Log4netService.log4netFatal(MethodBase.GetCurrentMethod().DeclaringType, ex);
[*] throw ex;
[*] }
[*] }
[*] return json;
[*] }
[*]}
viewplaincopy
[*]<span style="font-size:14px;"> /// <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 "{\"total\":0,\"rows\":[]}"; ;
[*] }
[*]
[*] string json = "";
[*]
[*] //缓存服务器唯一标识,命名很重要
[*] //在这里我采用的是查询条件作为缓存标识
[*] string key = "edaylhb:" + start + ":" + limit + ":" + sf + ":" + sr;
[*]
[*] //从缓存服务器中取对应key的数据
[*] Object obj = CachedService.getObjectFromCached(key);
[*]
[*] if (obj != null)
[*] {
[*] //缓存服务器中有数据
[*] json = (string)obj;
[*] }
[*] else
[*] {
[*] //缓存服务器中无数据,去数据库取,再保存到缓存服务器
[*]
[*] //查询数据库,返回dataset ds
[*]
[*] //...各种sql查询
[*]
[*] try{
[*] string ds2Str = "";
[*]
[*] //如果ds不为空,转换为Json格式
[*] ds2Str = DbUtil.dataSet2Json(ds);
[*] ds.Dispose();
[*]
[*]
[*] //拼接成Json格式
[*] if (ds.Tables.Rows.Count == 0)
[*] {
[*] json = "{\"total\":0,\"rows\":[]}";
[*] }
[*] else
[*] {
[*] json = "{\"total\":" + ds.Tables.Rows.Count + ",\"rows\":" + ds2Str + "}";
[*] }
[*] //保存数据到缓存服务器
[*] CachedService.setObjectToCached(key, json);
[*] }
[*] catch (Exception ex)
[*] {
[*] //异常记录到日志
[*] Log4netService.log4netFatal(MethodBase.GetCurrentMethod().DeclaringType, ex);
[*] throw ex;
[*] }
[*] }
[*] return json;
[*] }
[*] }</span>
七 dataSet转json
viewplaincopy
[*]public static string dataSet2Json(DataSet ds)
[*] {
[*] string jsonStr = null;
[*]
[*] //Newtonsoft.Json在转换日期的时候,会出现格式和时区(差8小时)差别Trade_Status_Name
[*] //如果不作如下格式转换,会出现形如Date(1335247957000+0800)/的日期
[*] IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
[*] //这里使用自定义日期格式,如果不使用的话,默认是ISO8601格式
[*] timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss";
[*] jsonStr = JsonConvert.SerializeObject(ds.Tables, Formatting.Indented, timeConverter);
[*] //jsonStr = "[{Stk_Code:'601398',Stk_name:'工商银行'},{Stk_Code:'500999',Stk_name:'农业银行'}]";
[*]
[*] return jsonStr;
[*] }
viewplaincopy
[*]<span style="font-size:14px;">public static string dataSet2Json(DataSet ds)
[*] {
[*] string jsonStr = null;
[*]
[*] //Newtonsoft.Json在转换日期的时候,会出现格式和时区(差8小时)差别Trade_Status_Name
[*] //如果不作如下格式转换,会出现形如Date(1335247957000+0800)/的日期
[*] IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
[*] //这里使用自定义日期格式,如果不使用的话,默认是ISO8601格式
[*] timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss";
[*] jsonStr = JsonConvert.SerializeObject(ds.Tables, Formatting.Indented, timeConverter);
[*] //jsonStr = "[{Stk_Code:'601398',Stk_name:'工商银行'},{Stk_Code:'500999',Stk_name:'农业银行'}]";
[*]
[*] return jsonStr;
[*] }</span>
八WebService调用及返回Json数据
viewplaincopy
[*]
[*] public class TestWebService : System.Web.Services.WebService
[*] {
[*] /// <summary>
[*] /// </summary>
[*]
[*] public void getTestData()
[*] {
[*] string cb = Context.Request["callback"]; //跨域服务器发送jsonp的参数key
[*] int start = Convert.ToInt32(string.IsNullOrEmpty(Context.Request["start"]) ? "1" : Context.Request["start"]);//从第几页开始:默认第一次从1开始,next_start=start+limit
[*] int limit = Convert.ToInt32(string.IsNullOrEmpty(Context.Request["limit"]) ? "20" : Context.Request["limit"]);//每次取的条数(步进):默认每页20条
[*] string sf = string.IsNullOrEmpty(Context.Request["sf"]) ? "se_code" : Context.Request["sf"]; //sortField 排序字段,默认:se_code
[*] string sr = string.IsNullOrEmpty(Context.Request["sr"]) ? "asc" : Context.Request["sr"];//sortRule 排序规则,默认:asc
[*]
[*] SomeClass svr = new SomeClass();
[*] string json = svr.getSomeData(start, limit, sf, sr);
[*]
[*] Context.Response.ContentType = "text/plain; charset=utf-8";
[*] //Context.Response.Write(cb + "({\"total\":30,\"rows\":[{\"ID\":1,\"NAME\":\"John\"},{\"ID\":2,\"NAME\":\"Mike\"}]})");
[*] Context.Response.Write(cb + "(" + json + ")");
[*] }
[*] }
http://blog.iyunv.com/meeweed/article/details/8665900
页:
[1]