Redis应用(1)缓存(1.1)------集成

一、Redis与MySQL数据同步

实现Redis与MySQL数据同步,一般有以下几种方法

1、定时同步:

应用程序可以定期将MySQL中的数据同步到Redis中。这种方法的优点是实现简单,缺点是可能会导致数据不一致,因为数据在同步的过程中可能会被修改。

2、实时同步:

可以使用触发器或者消息队列实现MySQL和Redis之间的实时同步。当MySQL中的数据发生变化时,触发器或者消息队列会立即通知Redis进行更新。这种方法的优点是实时性高,缺点是实现复杂。

3、双写模式:

可以将MySQL和Redis同时写入,确保数据的一致性。这种方法的优点是实现简单,缺点是可能会影响性能。

4、读写分离:

可以将MySQL用于写操作,而将Redis用于读操作。这种方法的优点是实现简单,缺点是可能会导致数据不一致,因为MySQL和Redis之间的同步延迟。

二、demo:

1、pom:

<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.redis</groupId>
	<artifactId>redislock</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.1.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<!-- redis -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-redis</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.33</version>
		</dependency>
	</dependencies>

</project>

2、properties配置文件:


#mysql

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/produce?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=wtyy
#mybatis
mybatis.mapper-locations=classpath*:mapper/*Mapper.xml


spring.redis.host=localhost
spring.redis.port=6379
#spring.redis.password=
spring.redis.database=1
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=500
spring.redis.pool.min-idle=0
spring.redis.timeout=0

3、RedisUtil封装Jedis操作:

package com.product.util;

import javax.xml.ws.BindingType;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
//import org.apache.log4j.chainsaw.Main;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @Description:redis工具类
 * @ClassName:
 * @date 2016年10月31日 上午11:25:06
 */
@SuppressWarnings("unused")
@Component
public class RedisUtil {
	private static final String IP = "127.0.0.1"; // ip
	private static final int PORT = 6379; // 端口
	// private static final String AUTH=""; // 密码(原始默认是没有密码)
	private static int MAX_ACTIVE = 1024; // 最大连接数
	private static int MAX_IDLE = 200; // 设置最大空闲数
	private static int MAX_WAIT = 10000; // 最大连接时间
	private static int TIMEOUT = 10000; // 超时时间
	private static boolean BORROW = true; // 在borrow一个事例时是否提前进行validate操作
	private static JedisPool pool = null;
	private static Logger logger = Logger.getLogger(RedisUtil.class);
	/**
	 * 初始化线程池
	 */
	static {
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(MAX_ACTIVE);
		config.setMaxIdle(MAX_IDLE);
		config.setMaxWaitMillis(MAX_WAIT);
		config.setTestOnBorrow(BORROW);
		pool = new JedisPool(config, IP, PORT, TIMEOUT);
	}

	/**
	 * 获取连接
	 */
	public static synchronized Jedis getJedis() {
		try {
			if (pool != null) {
				return pool.getResource();
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.info("连接池连接异常");
			return null;
		}

	}

//	// 加锁
//	public boolean tryLock(String key){
//		Jedis jedis = null;
//		jedis = getJedis();
//
//	    String result = jedis.setex(key,1000,"1");
//
//
//	    if("OK".equals(result)){
//
//	        return true;
//	    }
//	 
//	    return false;
//	}
//
//	// 释放锁
//	public void  releaseLock(String key){
//		Jedis jedis = null;
//		jedis = getJedis();
//	    jedis.del(key);
//	    
//	}
	
	/**
	 * @Description:设置失效时间
	 * @param @param key
	 * @param @param seconds
	 * @param @return
	 * @return boolean 返回类型
	 */
	public static void disableTime(String key, int seconds) {
		Jedis jedis = null;
		try {
			jedis = getJedis();
			jedis.expire(key, seconds);

		} catch (Exception e) {
			logger.debug("设置失效失败.");
		} finally {
			getColse(jedis);
		}
	}

	public static boolean exists(String key) {
		boolean flag = false;
		Jedis jedis = null;
		try {
			jedis = getJedis();
			flag = jedis.exists(key);
		} catch (Exception e) {
			logger.debug("设置失效失败.");
		} finally {
			getColse(jedis);
		}
		return flag;
	}

	/**
	 * @Description:插入对象
	 * @param @param key
	 * @param @param obj
	 * @param @return
	 * @return boolean 返回类型
	 */
	public static boolean addObject(String key, Object obj) {

		Jedis jedis = null;
		String value = JSONObject.toJSONString(obj);
		try {
			jedis = getJedis();
			jedis.set(key, value);
			return true;
		} catch (Exception e) {
			logger.debug("插入数据有异常.");
			return false;
		} finally {
			getColse(jedis);
		}
	}

	/**
	 * @Description:存储key~value
	 * @param @param key
	 * @param @param value
	 * @return void 返回类型
	 */

	public static Long addValue(String key, String value) {
		Jedis jedis = null;
		try {
			jedis = getJedis();
			//String code = jedis.set(key, value);
			return jedis.setnx(key, value);
		
		} catch (Exception e) {
			logger.debug("插入数据有异常.");
			return null;
		} finally {
			getColse(jedis);
		}
		
	}

	/**
	 * @Description:删除key
	 * @param @param key
	 * @param @return
	 * @return boolean 返回类型
	 */
	public static boolean delKey(String key) {
		Jedis jedis = null;
		try {
			jedis = getJedis();
			Long code = jedis.del(key);
			if (code > 1) {
				return true;
			}
		} catch (Exception e) {
			logger.debug("删除key异常.");
			return false;
		} finally {
			getColse(jedis);
		}
		return false;
	}

	/**
	 * @Description: 关闭连接
	 * @param @param jedis
	 * @return void 返回类型
	 */

	public static void getColse(Jedis jedis) {
		if (jedis != null) {
			jedis.close();
		}
	}

}

4、serviceImpl:

package com.product.serviceImpl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.product.util.RedisUtil;

import com.product.mapper.ProductMapper;
import com.product.mapper.UserOrderMapper;
import com.product.module.Product;
import com.product.module.UserOrder;
import com.product.service.OrderService;
import com.product.service.ProductService;

@Service("orderService")
public class OrderServiceImpl implements OrderService {

	@Autowired
	private ProductService productService;

	@Autowired
	private UserOrderMapper userOrderMapper;

	// 用户下订单,返回订单id
	@Override
	public Integer order(String productId, String userId) {

		// 逻辑操作
		// 先判断productId是否存在
		Product product = productService.getByProductId(productId);

		if (product == null) {
			return null;
		}
		// 是否有库存
		Integer id = product.getId();
		Integer total = product.getTotal();
		System.out.println("下单前库存" + total);
        
		UserOrder order = new UserOrder();
		if (total <= 0) {
			return null;
		}
       
		order.setCreatetime(new Date());
		order.setProductid(productId);
		order.setUserid(userId);
		int add = userOrderMapper.addOrder(order);
		if (add > 0) {
			// 创建订单成功,库存--
			total--;
			System.out.println("下单后库存" + total);
			productService.updateTotal(id, total);
		
			// return order.getId();
		}

		return null;

	}


	@Override
	public Integer getCountByProductId(String productId) {
		return userOrderMapper.getCountByProductId(productId);
	}

}

package com.product.serviceImpl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.product.mapper.ProductMapper;
import com.product.module.Product;
import com.product.service.ProductService;

@Service("productService")
public class ProductServiceImpl implements ProductService{
	@Autowired
	private ProductMapper productMapper;

	
	@Override
	public Product getByProductId(String productId) {
		Product product = productMapper.getByProductId(productId);
		return product;
	}
	
	
	@Override
	public Integer getCountByProductId(String productId) {
		return productMapper.getCountByProductId(productId);
	}

	@Override
	public int updateTotal(Integer id, Integer total) {
		return productMapper.updateTotal(id,total);
	}


	
	@Cacheable(cacheNames="product", key="'product'+#productId")
	@Override
	public Product cacheGetByProductId(String productId) {
		Product product = productMapper.getByProductId(productId);
		System.out.println("输出则没有走缓存");
		return product;
	}
	
	@CacheEvict(cacheNames="product", key="'product'+#productId",condition="#productId!=''")
	@Override
	public void del(String productId) {
		
	}


	@Cacheable(cacheNames="proList")
	@Override
	public List<Product> getList() {
		List<Product> list =productMapper.selectAll();
		System.out.println("查询结合,输出则没有走缓存");
		return list;
	}
	

	@CacheEvict(cacheNames="proList")
	@Override
	public void delList() {
		
	}


}

5、controller:


package com.product.controller;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.product.module.Product;

import com.product.service.OrderService;
import com.product.service.ProductService;

import com.product.util.RedisUtil;

@RequestMapping("/product")
@RestController
public class ProductController {

	@Autowired
	private OrderService orderService;

	@Autowired
	private ProductService productService;

	@Autowired
	private RedisUtil redisUtil;


	private String KEY = "productId";

	@RequestMapping("/order")
	public void order(@RequestParam String userId,
			@RequestParam String productId) {

		
		boolean lock = redisUtil.exists(KEY);
		if (!lock) {
			//
			
			Long result = redisUtil.addValue(KEY, productId);
			redisUtil.disableTime(KEY, 60);
			// redisUtil.disableTime(KEY, 5);
			// redisClient.expire(PRODUCT_LOCK, 60, String.valueOf(productId));
			if (result == 1) {
				System.err.println("不存在key,执行逻辑操作");
				orderService.order(productId, userId);
				redisUtil.delKey(KEY);
			}
		}else{
			System.out.println("存在该key,不允许执行");
		}
		
	}


	@RequestMapping("/getCache")
	public void getByProductId(@RequestParam String productId){
		Product product = productService.cacheGetByProductId(productId);
		System.out.println(product);
		
	}
	
	@RequestMapping("/delCache")
	public void del(@RequestParam String productId){
		System.out.println("删除商品缓存");
		productService.del(productId);
	}
	
	@RequestMapping("/getCacheList")
	public void getList(){
		List<Product> list = productService.getList();
		System.out.println("集合长度"+list.size());
	}
	
	@RequestMapping("/delCacheList")
	public void delList(){
		System.out.println("删除商品集合缓存");
		productService.delList();
	}
}

注:

(1)并发接口也可以这样写,以productId为key,随便写一个value:

@RequestMapping("/order")
	public void order(@RequestParam String userId,@RequestParam String productId){
 
		//是否有缓存
		boolean exists = redisUtil.exists(productId);
		if(!exists){
			//没有,加上
			Long sexNx = redisUtil.addValue(productId, "lock");
			if(sexNx == 1){
				orderService.order(productId,userId);
				redisUtil.delKey(productId);
			}
		}else{
			System.out.println(productId+"正在被抢购");
		}
		
	}

(2)缓存也可以用RedisUtil手动存进来,这种方法是不需要在启动类中开启@EnableCaching的,如:

@RequestMapping("/getProductInfo")
	public void getProductInfo(@RequestParam String productId){
		Product product = productService.getProductInfo(productId);
		System.err.println(product);
	}
@Override
	public Product getProductInfo(String productId) {
		String key = "productInfo"+productId;
		boolean exists = redisUtil.exists(key);
		Product product = null;
		if(exists){
			
			String productStr = redisUtil.getValue(key); 
			System.out.println("存在缓存"+productStr);
			product = JSON.parseObject(productStr,Product.class);
		}else{
			System.out.println("没有走缓存");
			 product = productMapper.getByProductId(productId);
			redisUtil.addObject(key, product);
			redisUtil.disableTime(key, 10);
		}
		return product;
	}

6、启动类:


package com.product;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@MapperScan("com.product.mapper")
@EnableCaching 
public class Start {
	public static void main(String[] args) {
		SpringApplication.run(Start.class, args);
	}

}

二、测试:

1、测缓存:

2、测同步:

另建一个测试工程:


package com.test.test;

import com.test.util.HttpRequestUtil;

public class ProductTest implements Runnable{
	public static void main(String[] args) {
		
		ProductTest productTest = new ProductTest();
      for(int i=0;i<50;i++){
    	 Thread thread = new Thread(productTest);
    	  thread.start();
      }
      
	
	}
	@Override
	public void run() {
		 String url = "http://localhost:8080/product/order";
   	  String productId = "abcd";
   	  String userId = "userid";
   	  String param = "userId="+userId+"&productId="+productId;
   	  HttpRequestUtil.sendPost(url, param);
	}
}

 模拟50个并发量,运行该测试类测试。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值