Window环境下Memcache 实战



Memcache理论

关于Memcache的理论知识,网上的资料铺天盖地,这里就不重复罗列,作为一名CodeMonkey,学习任何新知识的最好方式就是DIY.

参考资源:

http://kb.cnblogs.com/page/42731/

http://kb.cnblogs.com/page/42732/

http://kb.cnblogs.com/page/42733/

http://kb.cnblogs.com/page/42734/

http://kb.cnblogs.com/page/42735/ 

http://www.blogjava.net/chhbjh/archive/2012/02/21/370472.html 

http://suhuanzheng7784877.iteye.com/blog/2026914

http://kb.cnblogs.com/page/42775/ 

 

 

安装

下载memcached windows版本并解压到某一目录,如D:\Memcache

Window环境下Memcache 实战_第1张图片

Dos 窗口运行memcached.exe -d install 安装memcached服务

如果是第一次安装出现该错误提示,则需要以管理员的身份运行cmd,再次进行安装

Window环境下Memcache 实战_第2张图片

可以通过memcached.exe -h 查看运行命令参数信息

Window环境下Memcache 实战_第3张图片

启动服务

启动memcache服务并监听3686端口,默认端口是11211

查看window资源管理器,可以看到memcached.exe已经作为服务启动了

Window环境下Memcache 实战_第4张图片

操作示例

连接memcachejava客户端有很多,这里我们使用了java_memcache。下载对应的jar包后引入到java项目中,就可以很方便地连接操作memcache了。

话不多说,直接上代码。

使用Java_Memcache客户端连接Memcache

import com.danga.MemCached.*;

public class MemcacheUtility {
	private static MemCachedClient memCache;
	private static final MemcacheUtility MemcacheInstance = new MemcacheUtility();
	
	private MemcacheUtility(){
		memCache = new MemCachedClient();
		SockIOPool sockpool= SockIOPool.getInstance();
		//设置缓存服务器地址,可以设置多个实现分布式缓存
		sockpool.setServers(new String[]{"127.0.0.1:11211","127.0.0.1:11212"});
		//设置初始连接5
		sockpool.setInitConn(5);
		//设置最小连接5
		sockpool.setMinConn(5);
		//设置最大连接250
		sockpool.setMaxConn(250);
		//设置每个连接最大空闲时间1个小时
		sockpool.setMaxIdle(1000 * 3600);
		sockpool.setMaintSleep(30);
		sockpool.setNagle(false);
		sockpool.setSocketTO(3000);
		sockpool.setSocketConnectTO(0);
		sockpool.initialize();
	}
	
	public static MemcacheUtility getMemcacheClientInstance(){
		return MemcacheInstance;
	}
	
	public Object get(String key){
		Object obj = memCache.get(key);
		return obj;
	}	
	
	public void set(String key, Object value){
		memCache.set(key, value);
	}
//Memcache的操作还有replace/add/delete等,这里只用get/set最简单的操作来演示一下
}

使用MemcacheUtilityMemcache进行get/set操作

public class TestMemcaceAndJDBC {

	public static void main(String[] args) {
		MemcacheUtility mem = MemcacheUtility.getMemcacheClientInstance();
		for(int i=0;i<10; i++){ 
			mem.set("Data" + i, i);
		}

		for(int i=0;i<10;i++){
			Object obj = mem.get("Data" + i);
			if(obj != null){
				System.out.println(((Integer)obj).intValue());
			}
		}
	}
}


如果你打开任务管理器,你会注意到在启动memcached后第一次运行该Java程序时,memcached.exe进程所占用的内存会增大1MB,这是memcache内存分配模型所决定的。

应用举例

Memcache作为一个缓存的实现,最主要的功能就是将磁盘中数据(包括数据库、文件系统以及运算的结果)保存在内存中,减少应用程序读取/计算数据时访问IO的次数,提升应用的响应速度,保证良好的用户体验,进而保证产品的竞争性。

通常来说,适合存放在缓存中的数据具有如下特点:1)频繁读取,2)很少更新,3)对实时性,一致性要求不是特别高

例如:在设计某个网站上的热门新闻或热门话题时,可以将对应的信息缓存在memcache中,根据实际情况设置过期时间,每个外部web请求到达应用服务时,直接从memcache中获取,如果从memcache中获取到了就直接返回给web 应用显示在浏览器中,如果从memcache中没有获取到,则发起IO请求访问数据库,将查询的数据缓存进memcache中,同时返回给web应用显示在浏览器中。

 

下面使用mysql创建一个news表表示新闻信息,作为演示该表仅包含了新闻的titlecontent,其中hits表示新闻点击量,点击量最多的前10条表示为热门新闻。

DB 层设计

create database memcache;

use memcache;

create table `news` (

  `id` int primary key  auto_increment,

  `title` varchar(20) ,

  `content` varchar(800) ,

  `hits` int(11) ,

) ENGINE=InnoDB;

应用层设计

Window环境下Memcache 实战_第5张图片


数据Model

News.java

package Model;

import java.io.Serializable;

public class News implements Serializable {
	private int id;
	private String title;
	private String content;
	private int hits;
	
	//......省略get/set
	
	public String toString(){
		StringBuilder sb= new StringBuilder();
		sb.append("[title: ");
		sb.append(title);
		sb.append(" ],[content:  ");
		sb.append(content);
		sb.append("].");
		return sb.toString();
	}	
}

数据访问DAO

Note:这里使用Mysql,因此该应用程序需要引入mysql对应的jar包。

MysqlHelper.java

package DAO;

import java.sql.*;

public class MysqlHelper {
 
	public static Connection getConnection() {
		Connection cn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			cn = DriverManager
					.getConnection("jdbc:mysql://localhost:3306/memcache?user=root&password=root");
		} catch (ClassNotFoundException clazze) {
			System.out.println("mysql driver class is not found");
		} catch (SQLException sqle) {
			System.out.println("mysql connection get failed!");
		}
		return cn;

	}

	public static Statement getStatement(Connection cn) {
		Statement stmt = null;
		if (cn != null) {
			try {
				stmt = cn.createStatement();
			} catch (SQLException e) {
				System.out
						.println("mysql statement get error at getStatement!");
			}
		}
		return stmt;
	}

	public static ResultSet executeQuery(Statement stmt, String sql) {
		ResultSet rs = null;
		if (stmt != null) {
			try {
				rs = stmt.executeQuery(sql);
			} catch (SQLException e) {
				System.out
						.println("mysql statement execute error at getResultSet!");
			}
		}
		return rs;
	}

	public static boolean executeUpdate(Statement stmt, String sql) {
		int affectrows = 0;
		if (stmt != null) {
			try {
				affectrows = stmt.executeUpdate(sql);
			} catch (SQLException e) {
				System.out
						.println("mysql statement execute error at getResultSet!");
			}
		}
		return affectrows > 0;
	}

	public static void close(ResultSet rs, Statement stmt) {
		//略
	}

	public static void closeConnection(Connection cn) {
		//略
	}
}

MysqlNewsDAO.java

package DAO;
import Model.News;
import java.sql.*;
import java.util.*;

public class MysqlNewsDAO {

	public List getHotNews() {
		List news = new ArrayList();
		Connection cn = MysqlHelper.getConnection();
		Statement stmt = MysqlHelper.getStatement(cn);
		ResultSet rs = MysqlHelper.executeQuery(stmt,
				"select id, title, content,hits from news order by hits desc limit 0,10");
		try {
			if (rs != null) {
				while (rs.next()) {
					News oneNews = new News();
					oneNews.setId(rs.getInt(1));
					oneNews.setTitle(rs.getString(2));
					oneNews.setContent(rs.getString(3));
					oneNews.setHits(rs.getInt(4));
					news.add(oneNews);
				}
			}
		} catch (SQLException e) {
			System.out.println("Result Set Error!");
		} finally {
			MysqlHelper.close(rs, stmt);
			MysqlHelper.closeConnection(cn);
		}
		return news;
	}

	public boolean addNews(News news) {
		Connection cn = MysqlHelper.getConnection();
		Statement stmt = MysqlHelper.getStatement(cn);
		StringBuilder sql = new StringBuilder(
				"insert into News(title,content,hits) values('");
		sql.append(news.getTitle());
		sql.append("','");
		sql.append(news.getContent());
		sql.append("',");
		sql.append(news.getHits());
		sql.append(")");
		boolean ret = MysqlHelper.executeUpdate(stmt, sql.toString());
		MysqlHelper.close(null, stmt);
		MysqlHelper.closeConnection(cn);
		return ret;
	}
}

业务逻辑 BLL

package BLL;

import Model.News;
import Memcache.MemcacheUtility;
import DAO.MysqlNewsDAO;
import java.util.*;

public class NewsBLL {

	@SuppressWarnings("unchecked")
	public List getHotNews() {
		MemcacheUtility mem = MemcacheUtility.getMemcacheClientInstance();
		Object newsInMem = mem.get("HotNews");
		if (newsInMem != null) {
			return (List) newsInMem;
		}

		MysqlNewsDAO newsDAO = new MysqlNewsDAO();
		List news = newsDAO.getHotNews();
		mem.set("HotNews", news);
		return news;

	}
		
	public List getHotNew2(){
		MysqlNewsDAO newsDAO = new MysqlNewsDAO();
		List news = newsDAO.getHotNews();
		return news;
	}
		
	public void addNews(News news){
		MysqlNewsDAO newsDAO = new MysqlNewsDAO();
		newsDAO.addNews(news);
	}
}

Note:这里的MemcacheUtility 就是操作示例中MemcacheUtility.java

 

数据展示UI

import Model.News;
import BLL.NewsBLL;
import java.util.*;
import Memcache.MemcacheUtility;

public class TestMemcaceAndJDBC {

	public static void main(String[] args) {
		NewsBLL newsBll = new NewsBLL();
//首先往数据库中插入100条新闻数据
		System.out.println("Begin to insert 100 news");
		for(int i=0;i<100; i++){
			News news = new News();
			news.setTitle("title---"+i);
			news.setContent("content---"+i);
			news.setHits(i);
			newsBll.addNews(news);
		}
		
//使用memcache,获取热门新闻100次
		System.out.print("Using Memcache to get hot news!");
		
		long start = System.currentTimeMillis();
		for(int i=0;i<100;i++){
			List news = newsBll.getHotNews();
			for(News item : news){
				//System.out.println(item);
			}
		}
		long end = System.currentTimeMillis();
		System.out.println("Using Memcache takes: " +(end-start));
		
		System.out.println("\n----------------------\n");		
		
//不使用memcache,直接访问数据库获取热门新闻100次
		System.out.print("Not Using Memcache to get hot news!");
		start = System.currentTimeMillis();
		for(int i=0;i<100;i++){
			List news= newsBll.getHotNew2();
			for(News item : news){
				//System.out.println(item);
			}
		}
		end = System.currentTimeMillis();
		System.out.println("Not Using Memcache takes: " +(end-start));
	}
}

通过运行程序,我们发现使用memcache能大大提前数据的访问速度。

Window环境下Memcache 实战_第6张图片


你可能感兴趣的:(java,memcache,memcache)