zoukankan      html  css  js  c++  java
  • simple spring memcached(ssm) 和spring的整合教程 附代码

    Memcached 是一个高性能的分布式内存对象缓存系统,在web应用中有很强大的应用场景。而spring作为一个流行的开源框架,在针对数据缓存中,也有着不少的需求。在众多的第三方实现中,google的simple-spring-memcached是一种非常好的方式。下面就用一个简单的订单系统,描述了在spring-mvc中使用memcached的集成方法。 

    场景描述:a、用户在购买某件商品时,先进行商品的选择,系统生成商品的订单。订单内容包括:商品名称,商品id,订单id,商品原金额。

           b、用户进行订单确定,可能会有一定的折扣(例如使用京东的优惠券等),此时需要更新订单内容,订单内容需要更新商品的金额。

           c、用户需要选择支付方式,此时需要更新订单的支付渠道,同时还可能进行金额更新。(例如通过某宝搞活动等,呵呵)

         d、用户完成支付。

    一旦做完了d,订单数据将进入交易数据库表中。

    如果未做完d,每一步在30分钟之后,该笔订单就失效,并在memcached中删除订单。

     基于这个特性,abc状态的交易信息其实是交易信息的缓存,后面的增删改查如果每次都需要去进行数据库操作,是比较浪费的,因此考虑使用memcached进行订单状态的管理。

    好了,需求大致落实好了,开干!

    首先是在pom.xml完成与memcached相关的配置。(spring本身的pom配置就不在这里说了) 

            <!-- simple spring memcached -->
            <dependency>
                <groupId>com.google.code.simple-spring-memcached</groupId>
                <artifactId>spring-cache</artifactId>
                <version>3.6.0</version>
            </dependency>
            <dependency>
                <groupId>com.google.code.simple-spring-memcached</groupId>
                <artifactId>xmemcached-provider</artifactId>
                <version>3.6.0</version>
            </dependency>

    然后我们需要进行simple-spring-memcached的配置。

    首先我们需要创建一个spring-memcached的基础配置文件,主要用于声明与spring相关的memcached配置。(例如命名空间等) 

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-3.0.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
        <import resource="simplesm-context.xml" />
    
        <aop:aspectj-autoproxy />
        <context:annotation-config />
        <import resource="xmemcached.xml"/>
    </beans>

    这里我们可以看到,我们使用了一个xmemcached.xml的配置文件对memcached具体的内容进行配置。xmemcached.xml内容如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <bean name="defaultMemcachedClient" class="com.google.code.ssm.CacheFactory">
            <!-- xmemcached配置方法 -->
            <property name="cacheClientFactory">
                <bean
                    class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl" />
            </property>
            <!-- 定义了缓存节点的IP地址和端口号 -->
            <property name="addressProvider">
                <bean class="com.google.code.ssm.config.DefaultAddressProvider">
                    <property name="address" value="localhost:11211" />
                </bean>
            </property>  
            
            <!-- 定义了缓存节点的查找方法 -->
            <property name="configuration">
                <bean class="com.google.code.ssm.providers.CacheConfiguration">
                    <property name="consistentHashing" value="true" />
                </bean>
            </property>
        </bean>
    
    </beans>

    到此步为止,我们的与memcached配置相关的xml已经完了,接下来开始编写我们的代码了。

    首先创建一个类,用于缓存我们的订单信息,由于在memcached中是按照key-value形式进行数据存储的,因此我们需要指定一个key,这个key可以用注解来实现。

    public class OrderInfo implements Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = -608764679068384346L;
        
        private String orderId;
        private String productId;
        private String productName;
        private int productPrice;
        private int orderPrice;
        private String orderTime;
        private int paymentMethod;
        private int orderStatus;
        private String payTime;
        @CacheKeyMethod 
        public String getOrderId() {
            return orderId;
        }
        ...//get set method
    }

     这里有两个注意点,首先,我们这个作为缓存信息的类,需要实现Serializable接口,否在在memcached中是无法缓存对象的。其次我要要指定一个索引key,我们这里使用了orderId作为可以的索引。

    然后是我们的dao层。

    public interface OrderInfoDao {
        public OrderInfo getOrderInfo(String orderId); 
        public void orderInit(OrderInfo orderInfo);
        public void orderChecks(OrderInfo orderInfo);
        public void orderPayChecks(OrderInfo orderInfo);
        public void orderSuccess(String orderId);
    }

    dao层相对来说比较简单,就不展开了。

    最后是我们的关键了,dao层的实现,代码如下:

    @Repository("orderInfoDao")
    @ImportResource("classpath:spring_memcached.xml")
    public class OrderInfoDaoImpl implements OrderInfoDao{
    
        private static final String ORDER_INFO_SSM = "orderInfoSSM";
        
        @ReadThroughSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
        public OrderInfo getOrderInfo(@ParameterValueKeyProvider String orderId) {
            System.out.println("no cached hitd from ssm");
            return null;
        }
        @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
        public void orderInit(
                @ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
            System.out.println("orderInit cached to ssm");
            System.out.println(orderInfo.toString());
        }
        @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
        public void orderChecks(@ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
            System.out.println("orderChecks cached to ssm");
            System.out.println(orderInfo.toString());
            
        }
        @UpdateSingleCache(namespace = ORDER_INFO_SSM, expiration = 1800)
        public void orderPayChecks(@ParameterValueKeyProvider @ParameterDataUpdateContent OrderInfo orderInfo) {
            System.out.println("orderPayChecks cached to ssm");
            System.out.println(orderInfo.toString());
        }
        
        @InvalidateSingleCache(namespace = ORDER_INFO_SSM)  
        public void orderSuccess(@ParameterValueKeyProvider String orderId) {
            System.out.println("orderSuccess delet cached from ssm");
            System.out.println(orderId);
            //TODO 进行数据持久化处理
        }
    }

    首先我们要进行memcached命名空间的指定,通常来说,每个dao的实现都应在memcached中拥有自己的命名空间。

    接下来简单描述下相关的注解:

    @ReadThroughSingleCache 

    1)、检查缓存中是否存在,如果存在,返回缓存数据并退出。

    2)、如果在缓存中没有找到,将会继续访问下面的方法。

    3)、如果方法返回了期望的对象,则memcached将会以注解ParameterValueKeyProvider修饰的对象作为key并把返回的对象记入缓存。

    4)、如果方法没有发挥期望的对象,则memcached将不会写入该对象。

    5)、expiration指定了失效时间,是以秒记的。

    @UpdateSingleCache 

    1)、用于更新缓存,包括两个概念,一是写入新的缓存,二是更新现有缓存。

    2)、该注解中@ParameterDataUpdateContent代表更新之后进行对象刷新。

    3)、由于我们之前在对象中使用了@CacheKeyMethod 的注解,因此我们这里可以直接使用该类进行写入,key就是对象中写的orderId。

    @InvalidateSingleCache

    这个注解就比较简单了,就是使缓存失效。

    好了,大功告成,我们编写测试案例来试一下

    @Test
        public void testSSM() throws InterruptedException {
            OrderInfo orderInfo = new OrderInfo();
            // step1 下订单,使用当前时间作为orderId
            String orderId = String.valueOf(System.currentTimeMillis());
            orderInfo.setOrderId(orderId);
            orderInfo.setOrderTime("20151125115900");
            orderInfo.setProductId("10000000");
            orderInfo.setProductName("apple phone 6s");
            orderInfo.setProductPrice(528800);
            orderInfoDao.orderInit(orderInfo);
    
            // step2 进行确定金额
            // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
            orderInfo = null;
            orderInfo = orderInfoDao.getOrderInfo(orderId);
            System.out.println("get cached afterstep 1 orderInfo:" + orderInfo);
            orderInfo.setOrderStatus(2);
            // 更新金额,现在进行活动东,因此优惠288元
            orderInfo.setOrderPrice(500000);
            // 更新缓存
            orderInfoDao.orderChecks(orderInfo);
    
            // step3 进行支付方式选择
            // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
            orderInfo = null;
            orderInfo = orderInfoDao.getOrderInfo(orderId);
            System.out.println("get cached afterstep 2 orderInfo:" + orderInfo);
            orderInfo.setOrderStatus(3);
            // 确定支付方式
            orderInfo.setPaymentMethod(1);
            // 支付方式继续进行优惠
            orderInfo.setPayPrice(480000);
            orderInfo.setPayTime("20151125120000");
            // 更新缓存
            orderInfoDao.orderPayChecks(orderInfo);
    
            // step4 进行支付
            // 先从缓存中获取之前的数据,为了证明是从缓存中取出的,我们先初始化一下之前的对象
            orderInfo = null;
            orderInfo = orderInfoDao.getOrderInfo(orderId);
            System.out.println("get cached afterstep 3 orderInfo:" + orderInfo);
            // TODO PAY action
            orderInfoDao.orderSuccess(orderInfo.getOrderId());
    
            // 确认缓存对象已经删除
            orderInfo = null;
            orderInfo = orderInfoDao.getOrderInfo(orderId);
            System.out.println("get cached afterstep 4 orderInfo:" + orderInfo);
        }

    然后我们用maven-test观察下输出

    orderInit cached to ssm
    OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=0, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=0, payTime=null]
    get cached afterstep 1 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=0, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=0, payTime=null]
    orderChecks cached to ssm
    OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=2, payTime=null]
    get cached afterstep 2 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=0, payPrice=0, orderStatus=2, payTime=null]
    orderPayChecks cached to ssm
    OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=1, payPrice=480000, orderStatus=3, payTime=20151125120000]
    get cached afterstep 3 orderInfo:OrderInfo [orderId=1448455664090, productId=10000000, productName=apple phone 6s, productPrice=528800, orderPrice=500000, orderTime=20151125115900, paymentMethod=1, payPrice=480000, orderStatus=3, payTime=20151125120000]
    orderSuccess delet cached from ssm
    1448455664090
    no cached hitd from ssm
    get cached afterstep 4 orderInfo:null
    是不是很easy。
    当然,实际上memcached通常回合数据库联合起来使用,例如在@ReadThroughSingleCache中使用访问数据库生成缓存,这里咱们的目的是memcached,就不再展开了,嘿嘿。
    示例代码下载:
    http://download.csdn.net/detail/highkgao1988/9300325




  • 相关阅读:
    Android读书笔记三
    Android读书笔记二
    Android读书笔记一
    cpp plugin system
    houdini已放弃2
    ssh-keygen
    linux library
    software with plugin
    houdini已放弃
    C++ template
  • 原文地址:https://www.cnblogs.com/highkgao/p/4989784.html
Copyright © 2011-2022 走看看