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

Dos 窗口運行memcached.exe -d install 安裝memcached服務

如果是第一次安裝出現該錯誤提示,則需要以管理員的身份運行cmd,再次進行安裝

可以通過memcached.exe -h 查看運行命令參數信息

啓動服務

啓動memcache服務並監聽3686端口,默認端口是11211

查看window資源管理器,可以看到memcached.exe已經作爲服務啓動了

操作示例

連接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;

應用層設計



數據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<News> getHotNews() {
		List<News> news = new ArrayList<News>();
		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<News> getHotNews() {
		MemcacheUtility mem = MemcacheUtility.getMemcacheClientInstance();
		Object newsInMem = mem.get("HotNews");
		if (newsInMem != null) {
			return (List<News>) newsInMem;
		}

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

	}
		
	public List<News> getHotNew2(){
		MysqlNewsDAO newsDAO = new MysqlNewsDAO();
		List<News> 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> 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> news= newsBll.getHotNew2();
			for(News item : news){
				//System.out.println(item);
			}
		}
		end = System.currentTimeMillis();
		System.out.println("Not Using Memcache takes: " +(end-start));
	}
}

通過運行程序,我們發現使用memcache能大大提前數據的訪問速度。




發佈了40 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章