MemCached cache operation
When a Web project is running, it usually needs to read and write from the database. With the increase of the amount of operation data and the concentration of visits, the load of the database increases, the database response slows down and the website access speed slows down. Memcached is used to solve these problems.
Memcached is an open source high-performance distributed caching system. It is mainly used to reduce database load and accelerate Web application access. It is a memory based key Value storage system, which mainly stores data with small Value. The size of Value cannot exceed 1M. In general, the data structures supported by memcached are key Value pairs, and the supported data structures are simpler than Redis.
The usage scenarios of Memcached include:
Businesses with high access frequency, such as social networks, e-commerce, games, advertising, etc., can store frequently accessed data in Memcached, so as to reduce access to the database.
Promotional business and second kill business. These businesses have great access pressure, and the general database can't carry such a large amount of business at all.
Counter, such as the number of likes, the number of article readers, etc.
Store small pictures to reduce the access pressure of hard disk storage system.
So why should we store based on memory? Let's first look at a picture comparing the data processing rates of various storage media in the computer:
Memory, disk and CPU run differently. The disk is on the millisecond scale, the memory is on the subtle scale, and the CPU is on the nanosecond scale. It can be said that comparing the speed difference between memory and disk, memory is 100000 ~ 1 million times faster than disk. The transmission speed is different from that of the bus. Although there is SSD (Solid State Drives), its speed cannot be compared with that of memory.
In operation, if it cannot be calculated in memory, you must search the data on the disk, but the disk I/O input and output is very time-consuming. Generally, the response time of a request of a website should be controlled within 1 second.
Let's look at the physical architecture of MemCached:
When using Memcached, the data reading process is: first get the data from Memcached, if not, then get the data from the database, and then save the data to Memcached.
When using Memcached, the data update process is to update the database first, then update the Memcached cache, or delete the data cache.
Next, let's look at the application of Memcached:
First, install the Memcached server. Take the win10 system as an example, switch to the Memcached path, and execute the installation and startup commands in the command line of the DOS window: (you need to download the Memcached client on the official website, and then execute the installation command)
#Install Memcached server memcached -d install #Start Memcached service net strat "memcached server"
After installing and starting the Memcached service, we next create a maven project in the idea development tool, where we can view the basic operations of Memcached through code:
memcached service example
Example code:
package com.itszt.DemoMC.domain; /** * Order entity class, id, name, order placing time */ public class OrderRequest { private int orderId; private String orderName,orderTime; public OrderRequest() { } public OrderRequest(int orderId, String orderName, String orderTime) { this.orderId = orderId; this.orderName = orderName; this.orderTime = orderTime; } public int getOrderId() { return orderId; } @Override public String toString() { return "OrderRequest{" + "orderId=" + orderId + ", orderName='" + orderName + '\'' + ", orderTime='" + orderTime + '\'' + '}'; } public void setOrderId(int orderId) { this.orderId = orderId; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public String getOrderTime() { return orderTime; } public void setOrderTime(String orderTime) { this.orderTime = orderTime; } } ******************************************** package com.itszt.DemoMC; import com.alibaba.fastjson.JSON; import com.itszt.DemoMC.domain.OrderRequest; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; /** * MemCached Basic operation of */ public class App { public static void main(String[] args) { //Create a client that operates MemCached XMemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.1.160:11211")); MemcachedClient memcachedClient =null; try { memcachedClient = memcachedClientBuilder.build(); System.out.println("memcachedClient = " + memcachedClient); boolean booDel = memcachedClient.delete("data1"); if(booDel){ System.out.println("Delete succeeded"); }else{ System.out.println("No such data"); } //Insert string data into MemCached /*memcachedClient.add("data1",0,"Test data (1 "); memcachedClient.add("data2",0,"Test data (2 ");*/ /*memcachedClient.set("data1",0,"Test data (1 "); memcachedClient.set("data2",0,"Test data (2 ");*/ } catch (IOException e) { e.printStackTrace(); } /*catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); }*/ catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } //Fetch single data from MemCached /*try { Object data1 = memcachedClient.get("data1"); System.out.println("data1 = " + data1); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); }*/ //Take out a batch of data List<String> keys=new ArrayList<>(); keys.add("data1"); keys.add("data2"); try { //Read string from memcached Map<String, Object> objectMap = memcachedClient.get(keys); System.out.println("objectMap = " + objectMap); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } //Storage object OrderRequest orderRequest = new OrderRequest(1, "chinese rhubarb", new Date().toString()); System.out.println(JSON.toJSON(orderRequest).toString()); try { memcachedClient.set("order_"+orderRequest.getOrderId(),0, JSON.toJSON(orderRequest).toString()); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } try { String obj = memcachedClient.get("order_" + orderRequest.getOrderId()); OrderRequest orderFromJson = JSON.parseObject(obj, OrderRequest.class); System.out.println("orderFromJson = " + orderFromJson); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } } }
The above code is the basic operation of MemCached. We will use it in combination with the database in our work. Therefore, we configure the mybatis environment in maven and create a test table user (int uid, varchar username, varchar userpwd) in the database. The configuration in the pom.xml file of maven project is as follows:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itszt.DemoMC</groupId> <artifactId>DemoMC</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>DemoMC</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.googlecode.xmemcached</groupId> <artifactId>xmemcached</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.44</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> <build> <finalName>DemoMC</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>
Next, let's look at the mybatis-config.xml configuration file:
<?xml version="1.0" encoding="UTF-8" ?> <!--DTD Constraint introduction--> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--Global configuration start--> <configuration> <!-- Operating environment setting 1.Connection 2.affair--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/a0314?useUnicode=true&CharsetEncodig=UTF-8"/> <property name="username" value="root"/> <property name="password" value="2018"/> </dataSource> </environment> </environments> <!-- Import profile 2--> <mappers> <package name="com.itszt.DemoMC.demo"></package> </mappers> </configuration>
After completing the above configuration files, let's write a small case, and its file system is shown in the following figure:
Let's look at the code:
package com.itszt.DemoMC.util; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * memcached Tool class */ public class MCUtil { private static MemcachedClient memcachedClient =null; static { XMemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.1.160:11211")); try { memcachedClient = memcachedClientBuilder.build(); } catch (IOException e) { e.printStackTrace(); } } public static boolean setData(String key,int expire,Object obj){ try { memcachedClient.set(key,expire,obj); return true; } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } return false; } public static <T> T getData(String key){ try { return memcachedClient.get(key); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } return null; } } ********************************************* package com.itszt.DemoMC.demo; import java.io.Serializable; /** * Entity class, mapping user table in database a0314 */ public class User implements Serializable{ private int uid; private String username,userpwd; public User() { } @Override public String toString() { return "User{" + "uid=" + uid + ", username='" + username + '\'' + ", userpwd='" + userpwd + '\'' + '}'; } public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserpwd() { return userpwd; } public void setUserpwd(String userpwd) { this.userpwd = userpwd; } } ************************************************ package com.itszt.DemoMC.demo; /** * Interface, operating database */ public interface UserDao { //Query users according to user name and password public User findUserByNameAndPwd(String username,String userpwd); //Modify user name according to uid public boolean resetUsername(int uid,String username); } ************************************************* package com.itszt.DemoMC.demo; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; /** * For operating database */ public interface UserDaoDB extends UserDao{ @Override @Select("select * from user where username=#{username} and userpwd=#{userpwd}") User findUserByNameAndPwd(@Param("username") String username,@Param("userpwd") String userpwd); @Override @Update("update user set username=#{username} where uid=#{uid}") boolean resetUsername(@Param("uid") int uid,@Param("username") String username); } ************************************************ UserDaoDB.xml Configuration content: <?xml version="1.0" encoding="UTF-8" ?> <!--introduce DTD constraint--> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itszt.DemoMC.demo.UserDaoDB"> </mapper> ************************************************ package com.itszt.DemoMC.demo; import com.itszt.DemoMC.util.MCUtil; /** * Operation MemCached cache */ public class UserDaoCached implements UserDao{ @Override public User findUserByNameAndPwd(String username, String userpwd) { return MCUtil.getData("user_"+username+"_"+userpwd); } @Override public boolean resetUsername(int uid, String username) { boolean boo = MCUtil.setData("user_" + uid, 0, username); return boo; } } ************************************************ package com.itszt.DemoMC.demo; import com.itszt.DemoMC.util.MCUtil; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * UserDao Implementation class of */ public class UserDaoImpl implements UserDao{ private UserDaoCached userDaoCached; private UserDaoDB userDaoDB; SqlSession sqlSession; public UserDaoImpl(){ userDaoCached=new UserDaoCached(); String resource="mybatis-config.xml"; InputStream inputStream=null; try { inputStream=Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSession = sqlSessionFactory.openSession(); userDaoDB= sqlSession.getMapper(UserDaoDB.class); } @Override public User findUserByNameAndPwd(String username, String userpwd) { User userByNameAndPwd=null; //Search from the cache first. If there is no cache, then search from the database userByNameAndPwd=userDaoCached.findUserByNameAndPwd(username,userpwd); if(userByNameAndPwd==null){ System.out.println("Not in the cache,Find from database"); userByNameAndPwd=userDaoDB.findUserByNameAndPwd(username,userpwd); if(userByNameAndPwd==null){ System.out.println("No matches in database"); return null; } //After it is found in the database, add it to the cache MCUtil.setData("user_"+username+"_"+userpwd,0,userByNameAndPwd); System.out.println("Successfully saved to cache"); } System.out.println("Get from cache"); return userByNameAndPwd; } @Override public boolean resetUsername(int uid, String username) { //Update the database before updating the cache try { boolean boo = userDaoDB.resetUsername(uid, username); if(boo){ sqlSession.commit(); userDaoCached.resetUsername(uid,username); return true; }else{ System.out.println("Data update failed"); } } catch (Exception e) { e.printStackTrace(); } return false; } } *********************************************** package com.itszt.DemoMC.demo; /** * Test class */ public class Test { public static void main(String[] args) { //Operation UserDaoImpl implementation class UserDaoImpl userDao=new UserDaoImpl(); User userByNameAndPwd = userDao.findUserByNameAndPwd("admin", "123456"); System.out.println("userByNameAndPwd = " + userByNameAndPwd); //Update the data in the database and update it to the cache boolean boo = userDao.resetUsername(userByNameAndPwd.getUid(), "admin123"); if(boo){ System.out.println("Data update completed"); User user = userDao.findUserByNameAndPwd("admin123", "123456"); System.out.println("user = " + user); }else{ System.out.println("Data update failed"); } } }
After running the Test class Test in the above code, the display results are as follows:
Get from cache userByNameAndPwd = User{uid=1, username='admin', userpwd='123456'} Data update completed Not in the cache,Find from database Successfully saved to cache Get from cache user = User{uid=1, username='admin123', userpwd='123456'}
At this point, the operation of MemCached cache and database has been successfully implemented.