请使用Redis 做数据库应用 (Redis做为Driver) 平配合Servlet /JSP/JSTL 做一个学生数据管理功能.

在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
欢迎关注我的博客
Lumen的确是一款适合做API,速度很快的框架。但是在项目中使用Redis时发现Lumen默认使用的 predis/predis 会拖慢整体速度,特别是在高并发的情况下,所以寻思着使用 PhpRedis 代替,毕竟 PhpRedis 是C语言写的模块,性能上肯定优于 predis
文中例子已经整理成一个 composer 包,文末有简单介绍。
[TargetLiu/PHPRedis]
:v1.1.0发布,新增队列驱动,缓存驱动移动至 TargetLiu\PHPRedis\Cache ,使用老版本的需要修改 bootstrap/app.php 中缓存驱动加载位置。
编译安装PhpRedis
由于 PhpRedis 是C语言写的模块,需要编译安装。安装方法网上一搜一大把,请根据自己的环境选择相应的方法安装即可。
两个可能用得上的链接:
Lumen中使用PhpRedis
很简单,只需要在 bootstrap/app.php 中添加下列代码将PhpRedis注入容器即可:
$app-&singleton('phpredis', function(){
$redis = new R
$redis-&pconnect('127.0.0.1'); //建立连接
$redis-&select(1); //选择库
$redis-&auth('xxxx'); //认证
unset($app-&availableBindings['redis']);
绑定后即可通过 app('phpredis') 直接使用 PhpRedis 了,具体使用方法可以看相应的官方文档。
Lumen中为PhpRedis增加Cache驱动
由于实际使用中更多的将Redis用于缓存,Lumen自带的Redis缓存驱动是基于 predis/predis 实现,我们现在新建一个驱动以支持 Phpredis
新增Cache驱动详细方法可以查看 ,这里指罗列一些关键的点。更多的内容也可以查看
我们首先创建一个 ServiceProvider :
namespace App\P
use Illuminate\Support\Facades\C
use Illuminate\Support\ServiceP
use TargetLiu\PHPRedis\PHPRedisS
class CacheServiceProvider extends ServiceProvider
* Perform post-registration booting of services.
* @return void
public function boot()
Cache::extend('phpredis', function ($app) {
return Cache::repository(new PHPRedisStore($app-&make('phpredis'), $app-&config['cache.prefix']));
* Register bindings in the container.
* @return void
public function register()
这样就建立一个名为 phpreids 的驱动。再创建一个基于 Illuminate\Contracts\Cache\Store 契约的缓存操作类用以操作 PhpRedis
namespace TargetLiu\PHPR
use Illuminate\Contracts\Cache\S
class PHPRedisStore implements Store
* The Redis database connection.
* @var \Illuminate\Redis\Database
protected $
* A string that should be prepended to keys.
* @var string
protected $
* Create a new Redis store.
\Illuminate\Redis\Database
* @return void
public function __construct($redis, $prefix = '')
$this-&redis = $
$this-&setPrefix($prefix);
* Retrieve an item from the cache by key.
string|array
* @return mixed
public function get($key)
if (!is_null($value = $this-&connection()-&get($this-&prefix . $key))) {
return is_numeric($value) ? $value : unserialize($value);
* Retrieve multiple items from the cache by key.
* Items not found in the cache will have a null value.
* @return array
public function many(array $keys)
$return = [];
$prefixedKeys = array_map(function ($key) {
return $this-&prefix . $
}, $keys);
$values = $this-&connection()-&mGet($prefixedKeys);
foreach ($values as $index =& $value) {
$return[$keys[$index]] = is_numeric($value) ? $value : unserialize($value);
* Store an item in the cache for a given number of minutes.
* @return void
public function put($key, $value, $minutes)
$value = is_numeric($value) ? $value : serialize($value);
$this-&connection()-&set($this-&prefix . $key, $value, (int) max(1, $minutes * 60));
* Store multiple items in the cache for a given number of minutes.
* @return void
public function putMany(array $values, $minutes)
foreach ($values as $key =& $value) {
$this-&put($key, $value, $minutes);
* Increment the value of an item in the cache.
* @return int|bool
public function increment($key, $value = 1)
return $this-&connection()-&incrBy($this-&prefix . $key, $value);
* Decrement the value of an item in the cache.
* @return int|bool
public function decrement($key, $value = 1)
return $this-&connection()-&decrBy($this-&prefix . $key, $value);
* Store an item in the cache indefinitely.
* @return void
public function forever($key, $value)
$value = is_numeric($value) ? $value : serialize($value);
$this-&connection()-&set($this-&prefix . $key, $value);
* Remove an item from the cache.
* @return bool
public function forget($key)
return (bool) $this-&connection()-&delete($this-&prefix . $key);
* Remove all items from the cache.
* @return void
public function flush()
$this-&connection()-&flushDb();
* Get the Redis connection instance.
* @return \Predis\ClientInterface
public function connection()
return $this-&
* Get the Redis database instance.
* @return \Illuminate\Redis\Database
public function getRedis()
return $this-&
* Get the cache key prefix.
* @return string
public function getPrefix()
return $this-&
* Set the cache key prefix.
* @return void
public function setPrefix($prefix)
$this-&prefix = !empty($prefix) ? $prefix . ':' : '';
通过以上两个步骤基本上就完成了Cache驱动的创建,现在只需要在 bootstrap/app.php 中注入新建的Cache驱动然后配置 .env 中 CACHE_DRIVER = phpredis ,最后再在 config/cache.php 中加入相应的驱动代码即可
'phpredis' =& [
'driver' =& 'phpredis'
Cache的使用请查看Lumen
一个基于PhpRedis的Lumen扩展包
[TargetLiu/PHPRedis]
安装:composer require targetliu/phpredis
安装及使用方法请看
这个包只是我做的一个简单示例,引入了 PhpRedis 并做了最简单的缓存驱动。目前支持根据 .env 获取Redis配置、Cache的基本读写等。
Session和Queue可以继续使用Lumen自带的Redis驱动,两者互不影响。下一步如有需要可以继续完善这两部分的驱动。
这个包将根据自己工作需求以及大家的已经进一步完善。
欢迎大家提出意见共同完善。
3 收藏&&|&&15
你可能感兴趣的文章
8 收藏,1.9k
50 收藏,19.9k
5 收藏,383
本作品采用 署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
如果有使用 phpredis 之前和之后的性能对比,那就完美了
如果有使用 phpredis 之前和之后的性能对比,那就完美了
空了做个详细对比哈。反正在公司的项目上,ab测下来是有很大提升的。
空了做个详细对比哈。反正在公司的项目上,ab测下来是有很大提升的。
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。在平时的开发中我们都需要处理重复提交的问题,避免业务出错或者产生脏数据,虽然可以通过前端控制但这并不是可以完全避免,最好的方式还是前后端均进行控制,这样的话就可以更有效,尽可能全面的去减少错误的发生。
一、比如我们注册的时候需要发送验证码
如果用户频繁点击或者恶意攻击的话就会造成不断的请求对服务器产生很大的压力,为了避免这种情况我们需要做处理,传统的模式中是在数据库中记录手机号、验证码已经发送时间,再次请求的时候呢去数据库查询是否有该手机号记录,并校验是否超过间隔时间,如果超过则重新发送并更新时间,否组不予发送,这样有一个缺点就是如果同时又很多人在做相同的业务同时查询就会对数据库造成很大的压力。
根据此种情况我们可以使用Redis incrde&原子性递增,来解决这种高并发的秒杀或者分布式序列号生成等场景。鉴于本场景我们只用他来做计数实现间隔时间内只接收一次请求。
实现逻辑:在发送短信之后使用Redis的incr设置一个递增的KEY(根据自己的需要设定但是要保证每一个人的唯一),来判断该KEY的数值,如果等于1说明这是第一次请求,发送短信记录日志,并设置有效期,如果不等于的话说明是间隔时间内多次请求,就提示请求频繁,稍后重试。
1 String redisKey = "SMS_SEND_" + smsP
2 long count = redisTemplate.opsForValue().increment(redisKey, 1);
3 if (count == 1) {
4 //设置有效期一分钟
redisTemplate.expire(redisKey, 60, TimeUnit.SECONDS);
7 if (count & 1) {
resultMap.put("retCode", "-1");
resultMap.put("retMsg", "每分钟只能发送一次短信");
<span style="color: #
outPrintJson(resultMap);
<span style="color: #
<span style="color: # }
<span style="color: # /** 发送短信 */
<span style="color: # ......
<span style="color: # /** 记录发送日志 */
<span style="color: # ......
二、上述方式可以解决特定的问题,当需要处理的情况多的话我们可以考虑使用切面来解决
代码如下:
1 package com.cul.culsite.
3 public class RedisLockBean {
private int timeInS
private String codeN
private String msgN
<span style="color: #
private boolean isAtC
<span style="color: #
private boolean isAtS
<span style="color: #
private boolean isAtP
<span style="color: #
private String returnT
<span style="color: #
public String getKey() {
<span style="color: #
<span style="color: #
<span style="color: #
public void setKey(String key) {
<span style="color: #
this.key =
<span style="color: #
<span style="color: #
public int getTimeInSecond() {
<span style="color: #
return timeInS
<span style="color: #
<span style="color: #
public void setTimeInSecond(int timeInSecond) {
<span style="color: #
this.timeInSecond = timeInS
<span style="color: #
<span style="color: #
public String getCodeName() {
<span style="color: #
return codeN
<span style="color: #
<span style="color: #
public void setCodeName(String codeName) {
<span style="color: #
this.codeName = codeN
<span style="color: #
<span style="color: #
public String getMsgName() {
<span style="color: #
return msgN
<span style="color: #
<span style="color: #
public void setMsgName(String msgName) {
<span style="color: #
this.msgName = msgN
<span style="color: #
<span style="color: #
public String getCode() {
<span style="color: #
<span style="color: #
<span style="color: #
public void setCode(String code) {
<span style="color: #
this.code =
<span style="color: #
<span style="color: #
public String getMsg() {
<span style="color: #
<span style="color: #
<span style="color: #
public void setMsg(String msg) {
<span style="color: #
this.msg =
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
public boolean isAtController() {
<span style="color: #
return isAtC
<span style="color: #
<span style="color: #
public void setAtController(boolean isAtController) {
<span style="color: #
this.isAtController = isAtC
<span style="color: #
<span style="color: #
public boolean isAtService() {
<span style="color: #
return isAtS
<span style="color: #
<span style="color: #
public void setAtService(boolean isAtService) {
<span style="color: #
this.isAtService = isAtS
<span style="color: #
<span style="color: #
public boolean isAtParameter() {
<span style="color: #
return isAtP
<span style="color: #
<span style="color: #
public void setAtParameter(boolean isAtParameter) {
<span style="color: #
this.isAtParameter = isAtP
<span style="color: #
<span style="color: #
public String getReturnType() {
<span style="color: #
return returnT
<span style="color: #
<span style="color: #
public void setReturnType(String returnType) {
<span style="color: #
this.returnType = returnT
<span style="color: #
<span style="color: #
<span style="color: #
public String toString() {
<span style="color: #
return "RedisLockBean [key=" + key + ", timeInSecond=" + timeInSecond
<span style="color: #
+ ", codeName=" + codeName + ", msgName=" + msgName + ", code="
<span style="color: #
+ code + ", msg=" + msg + ", isAtController=" + isAtController
<span style="color: #
+ ", isAtService=" + isAtService + ", isAtParameter="
<span style="color: #
+ isAtParameter + ", returnType=" + returnType + "]";
<span style="color: #
<span style="color: # }
1 package com.cul.culsite.
3 import java.lang.annotation.ElementT
4 import java.lang.annotation.R
5 import java.lang.annotation.RetentionP
6 import java.lang.annotation.T
* 解决的问题:&br&
1.数据库加锁性能较差&br&
<span style="color: #
2.数据库加锁,若相应线程异常,所无法释放&br&
<span style="color: #
* 注意事项:&br&
<span style="color: #
方法的返回值对象必须包含错误码,错误信息属性及其的get方法
<span style="color: #
<span style="color: #
<span style="color: # @Target({ElementType.PARAMETER,ElementType.METHOD})
<span style="color: # @Retention(RetentionPolicy.RUNTIME)
<span style="color: # public @interface RedisLock {
<span style="color: #
<span style="color: #
* 若加注解的入参时基本数据类型(int,long)或String时,fieldName无效&br&
<span style="color: #
* 若注解的参数是自定义对象时,请注意一下几点:&br&
<span style="color: #
1.确保定义有相应属性public修饰的get方法&br&
<span style="color: #
2.get方法的返回参数是基本的数据类型或String&br&
<span style="color: #
3.get方法的返回值不为空&br&
<span style="color: #
* 否则,加锁失败.
<span style="color: #
<span style="color: #
<span style="color: #
String[] fieldName() default {};
<span style="color: #
<span style="color: #
* 锁的有效时间,单位为秒,默认值为1
<span style="color: #
<span style="color: #
<span style="color: #
int timeInSecond() default 1;
<span style="color: #
<span style="color: #
* 加锁,锁已被其它请求获取时,直接返回重复提交,codeName指定返回对象的返回码对应的属性,默认值'code'
<span style="color: #
<span style="color: #
<span style="color: #
String codeName() default "code";
<span style="color: #
<span style="color: #
* 加锁,锁已被其它请求获取时,直接返回重复提交,msgName指定返回对象的返回信息对应的属性,默认值'msg'
<span style="color: #
<span style="color: #
<span style="color: #
String msgName() default "msg";
<span style="color: #
<span style="color: #
* 加锁,锁已被其它请求获取时,直接返回重复提交,code指定返回对象的返回码对应的值,默认值'09'
<span style="color: #
<span style="color: #
<span style="color: #
String code() default "09";
<span style="color: #
<span style="color: #
* 加锁,锁已被其它请求获取时,直接返回重复提交,msg指定返回对象的返回码对应的值,默认值'重复提交'
<span style="color: #
<span style="color: #
<span style="color: #
String msg()
default "重复提交";
<span style="color: #
<span style="color: #
* 注解作用与方法时,指定参数在参数列表中的索引
<span style="color: #
<span style="color: #
int paramIndex() default 0;
<span style="color: # }
1 package com.cul.culsite.
3 import java.lang.annotation.A
4 import java.lang.reflect.InvocationTargetE
5 import java.lang.reflect.M
6 import java.util.ArrayL
7 import java.util.A
8 import java.util.C
9 import java.util.HashM
10 import java.util.L
11 import java.util.M
13 import javax.servlet.http.HttpServletR
15 import org.apache.commons.lang.StringU
16 import org.aspectj.lang.ProceedingJoinP
17 import org.aspectj.lang.S
18 import org.aspectj.lang.reflect.MethodS
19 import org.slf4j.L
20 import org.slf4j.LoggerF
21 import org.springframework.beans.factory.annotation.A
22 import org.springframework.stereotype.C
23 import org.springframework.stereotype.C
24 import org.springframework.web.bind.annotation.RequestM
26 import com.alibaba.fastjson.JSONO
27 import com.cul.culsite.common.RedisKeyC
28 import com.cul.culsite.service.RedisS
29 import com.cul.culsite.util.DateU
30 import com.cul.culsite.util.OxmH
32 @Component
33 public class RedisLockAspect {
private final static Logger logger = LoggerFactory.getLogger(RedisLockAspect.class);
protected static final String XML_TYPE = "xml";
protected static final String JSON_TYPE = "json";
protected static final String ILLEGAL_TYPE = "illegal type";
@Autowired
private RedisService redisS
public Object redisLockParse(ProceedingJoinPoint p) throws Throwable{
Signature signature = p.getSignature();
boolean isRepetition = false;
RedisLockBean redisLockBean = null;
String value = System.nanoTime()+"";
if(signature instanceof MethodSignature){
//获得接口中定义的方法的Method,但注解时加载实现类中方法的参数上
MethodSignature methodSignature = (MethodSignature)
Method serviceMethod = methodSignature.getMethod();
Method serviceImpMethod = p.getTarget().getClass().getMethod(serviceMethod.getName(), serviceMethod.getParameterTypes());
//获取key值
redisLockBean = getRedisLockKey(p.getTarget(),serviceImpMethod,p.getArgs());
//成功获取key值,在redis中加锁
if(redisLockBean!=null){
logger.info("redis lock value is :{}",value);
boolean isPutSuccess =redisService.setIfAbsent(redisLockBean.getKey(), value, redisLockBean.getTimeInSecond());
//加锁失败,直接返回
if(!isPutSuccess){
logger.info("get redis lock fail for {}",redisLockBean.getKey());
if(redisLockBean.isAtParameter()||redisLockBean.isAtService()){
Class&?& returnType = serviceImpMethod.getReturnType();
//加锁方法有返回值
if(!returnType.getName().equals(java.lang.Void.class.getName())){
//实例化返回值对象
Object result = returnType.newInstance();
//设置返回码
returnType.getMethod(getSetMethodNameByFieldName(redisLockBean.getCodeName()), java.lang.String.class).invoke(result, redisLockBean.getCode());
//设置返回信息
returnType.getMethod(getSetMethodNameByFieldName(redisLockBean.getMsgName()), java.lang.String.class).invoke(result, redisLockBean.getMsg());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
throw new RuntimeException("@RedisLock作用的方法没有返回参数");
}else if(redisLockBean.isAtController()){
Map&String,String& result = new HashMap&String,String&();
result.put(redisLockBean.getCodeName(), redisLockBean.getCode());
result.put(redisLockBean.getMsgName(), redisLockBean.getMsg());
return response(redisLockBean.getReturnType()==null?"json":redisLockBean.getReturnType(), result);
logger.info("get redis lock success for {}",redisLockBean.getKey());
isRepetition = true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
<span style="color: #0
} catch (SecurityException e) {
<span style="color: #1
e.printStackTrace();
<span style="color: #2
<span style="color: #3
<span style="color: #4
Object result = null;
<span style="color: #5
<span style="color: #6
result = p.proceed();
<span style="color: #7
} catch (Throwable e) {
<span style="color: #8
<span style="color: #9
<span style="color: #0
if(redisLockBean!=null){
<span style="color: #1
if(isRepetition&&value.equals(redisService.get(redisLockBean.getKey()))){
<span style="color: #2
logger.info("lock has released :{}",redisLockBean.getKey());
<span style="color: #3
redisService.delete(redisLockBean.getKey());
<span style="color: #4
<span style="color: #5
<span style="color: #6
<span style="color: #7
<span style="color: #8
<span style="color: #9
<span style="color: #0
<span style="color: #1
private RedisLockBean getRedisLockKey(Object target,Method method,Object... object){
<span style="color: #2
if(target == null){
<span style="color: #3
throw new RuntimeException("get redis lock key error,target is null");
<span style="color: #4
<span style="color: #5
if(method==null){
<span style="color: #6
throw new RuntimeException("get redis lock key error,method is null");
<span style="color: #7
<span style="color: #8
List&String& fieldValueList = new ArrayList&String&();
<span style="color: #9
RedisLockBean redisLockBean = new RedisLockBean();
<span style="color: #0
RedisLock redisLock = null;
<span style="color: #1
//类上有@Controller说明@RedisLock是放在请求方法上,使用HttpServletRequest获取请求参数
<span style="color: #2
if(method.isAnnotationPresent(RedisLock.class)&&target.getClass().isAnnotationPresent(Controller.class)){
<span style="color: #3
//controller层方法时对外开放的接口
<span style="color: #4
if(method.isAnnotationPresent(RequestMapping.class)){
<span style="color: #5
redisLock = method.getAnnotation(RedisLock.class);
<span style="color: #6
//获取方法中的HttpServletRequest类型的参数
<span style="color: #7
HttpServletRequest request = null;
<span style="color: #8
for(Object para:object){
<span style="color: #9
if(para instanceof HttpServletRequest){
<span style="color: #0
request = (HttpServletRequest)
<span style="color: #1
<span style="color: #2
<span style="color: #3
<span style="color: #4
if(request==null){
<span style="color: #5
throw new RuntimeException("@RedisLock作用于controller层方法时,方法需要包含HttpServletRequest类型的参数");
<span style="color: #6
<span style="color: #7
//未定义加锁参数时,默认使用mac
<span style="color: #8
String[] paraName = redisLock.fieldName();
<span style="color: #9
if(paraName==null||paraName.length==0){
<span style="color: #0
paraName=new String[]{"mac"};
<span style="color: #1
<span style="color: #2
for(String para:paraName){
<span style="color: #3
fieldValueList.add(request.getParameter(para));
<span style="color: #4
<span style="color: #5
if(fieldValueList.isEmpty()){
<span style="color: #6
throw new RuntimeException("@RedisLock作用于controller层方法时,生成key失败,请求中没有mac签名");
<span style="color: #7
<span style="color: #8
//标示注解作用在controller成方法上
<span style="color: #9
redisLockBean.setAtController(true);
<span style="color: #0
<span style="color: #1
throw new RuntimeException("@RedisLock作用于controller层的方法时,该方法上需要使用@RequestMapping注解");
<span style="color: #2
<span style="color: #3
//注解作用于非controller层方法上
<span style="color: #4
}else if(method.isAnnotationPresent(RedisLock.class)){
<span style="color: #5
redisLock = method.getAnnotation(RedisLock.class);
<span style="color: #6
//参数的索引位置
<span style="color: #7
int index = redisLock.paramIndex();
<span style="color: #8
String[] fieldName = redisLock.fieldName();
<span style="color: #9
String[] values = getFieldValue(object[index],fieldName);
<span style="color: #0
//注解的参数时基本的数据类型或String,不需要传入属性名称,否则设置的属性,都必须获得该属性值
<span style="color: #1
if(values==null || values.length!=fieldName.length && fieldName.length&0){
<span style="color: #2
return null;
<span style="color: #3
<span style="color: #4
fieldValueList.addAll(Arrays.asList(values));
<span style="color: #5
redisLockBean.setAtService(true);
<span style="color: #6
<span style="color: #7
Annotation[][]
<span style="color: #8
annotations = method.getParameterAnnotations();
<span style="color: #9
for(int i=0;i&annotations.i++){
<span style="color: #0
for(Annotation annotation:annotations[i]){
<span style="color: #1
if(annotation instanceof RedisLock){
<span style="color: #2
RedisLock redisLockTmp = (RedisLock)
<span style="color: #3
if(redisLock==null){
<span style="color: #4
redisLock = redisLockT
<span style="color: #5
<span style="color: #6
String[] fieldName = redisLockTmp.fieldName();
<span style="color: #7
String[] values = getFieldValue(object[i],fieldName);
<span style="color: #8
//注解的参数时基本的数据类型或String,不需要传入属性名称,否则设置的属性,都必须获得该属性值
<span style="color: #9
if(values==null || values.length!=fieldName.length && fieldName.length&0){
<span style="color: #0
return null;
<span style="color: #1
<span style="color: #2
fieldValueList.addAll(Arrays.asList(values));
<span style="color: #3
redisLockBean.setAtParameter(true);
<span style="color: #4
<span style="color: #5
<span style="color: #6
<span style="color: #7
<span style="color: #8
//未使用注解
<span style="color: #9
if(fieldValueList.isEmpty()){
<span style="color: #0
return null;
<span style="color: #1
<span style="color: #2
<span style="color: #3
//设置其它参数值
<span style="color: #4
if(redisLockBean.getTimeInSecond()==0){
<span style="color: #5
redisLockBean.setTimeInSecond(redisLock.timeInSecond());
<span style="color: #6
<span style="color: #7
if(StringUtils.isEmpty(redisLockBean.getCodeName())){
<span style="color: #8
redisLockBean.setCodeName(redisLock.codeName());
<span style="color: #9
<span style="color: #0
if(StringUtils.isEmpty(redisLockBean.getCode())){
<span style="color: #1
redisLockBean.setCode(redisLock.code());
<span style="color: #2
<span style="color: #3
if(StringUtils.isEmpty(redisLockBean.getMsgName())){
<span style="color: #4
redisLockBean.setMsgName(redisLock.msgName());
<span style="color: #5
<span style="color: #6
if(StringUtils.isEmpty(redisLockBean.getMsg())){
<span style="color: #7
redisLockBean.setMsg(redisLock.msg());
<span style="color: #8
<span style="color: #9
<span style="color: #0
Collections.sort(fieldValueList);
<span style="color: #1
logger.info("all value of fieldName is {}",fieldValueList);
<span style="color: #2
//生成key值
<span style="color: #3
StringBuilder builder = new StringBuilder();
<span style="color: #4
builder.append(target.getClass().getName())
<span style="color: #5
.append("-")
<span style="color: #6
.append(method.getName())
<span style="color: #7
.append("-")
<span style="color: #8
.append(Arrays.asList(method.getParameterTypes()))
<span style="color: #9
.append("-")
<span style="color: #0
.append(fieldValueList);
<span style="color: #1
String lockKey = RedisKeyConstants.REDIS_LOCK + builder.toString();
<span style="color: #2
logger.info("redis lock key is :{}",builder.toString());
<span style="color: #3
redisLockBean.setKey(lockKey);
<span style="color: #4
logger.info("redisLockBean :{}",redisLockBean.toString());
<span style="color: #5
return redisLockB
<span style="color: #6
<span style="color: #7
private String[] getFieldValue(Object argObj,String...fieldName){
<span style="color: #8
if(fieldName ==null || fieldName.length == 0){
<span style="color: #9
return new String[]{getBaseClassValue(argObj)};
<span style="color: #0
<span style="color: #1
List&String& fieldsValue = new ArrayList&String&();
<span style="color: #2
for(String field:fieldName){
<span style="color: #3
String value = getFieldValue(argObj,field);
<span style="color: #4
logger.info("value of fieldName '{}' is :{}",fieldName,value);
<span style="color: #5
if(value!=null){
<span style="color: #6
fieldsValue.add(value);
<span style="color: #7
<span style="color: #8
<span style="color: #9
return fieldsValue.toArray(new String[0]);
<span style="color: #0
<span style="color: #1
private String getFieldValue(Object argObj,String fieldName){
<span style="color: #2
if(argObj==null){
<span style="color: #3
throw new RuntimeException("argObj is null,cannot get field value of fieldName");
<span style="color: #4
<span style="color: #5
String value = getBaseClassValue(argObj);
<span style="color: #6
if(!StringUtils.isEmpty(value)){
<span style="color: #7
<span style="color: #8
<span style="color: #9
String methodName = getGetMethodValueByFieldName(fieldName);
<span style="color: #0
Object result = null;
<span style="color: #1
<span style="color: #2
Method method = argObj.getClass().getMethod(methodName);
<span style="color: #3
result = method.invoke(argObj);
<span style="color: #4
} catch (NoSuchMethodException e) {
<span style="color: #5
logger.error("method {} without parameter is not exists!",methodName);
<span style="color: #6
e.printStackTrace();
<span style="color: #7
} catch (SecurityException e) {
<span style="color: #8
e.printStackTrace();
<span style="color: #9
} catch (IllegalAccessException e) {
<span style="color: #0
logger.error("method {} without parameter is not public!",methodName);
<span style="color: #1
e.printStackTrace();
<span style="color: #2
} catch (IllegalArgumentException e) {
<span style="color: #3
logger.error("method {} has parameter!",methodName);
<span style="color: #4
e.printStackTrace();
<span style="color: #5
} catch (InvocationTargetException e) {
<span style="color: #6
e.printStackTrace();
<span style="color: #7
<span style="color: #8
if(result==null){
<span style="color: #9
logger.warn("method {} does not have returnValue",methodName);
<span style="color: #0
return null;
<span style="color: #1
<span style="color: #2
return getBaseClassValue(result);
<span style="color: #3
<span style="color: #4
private String getBaseClassValue(Object object){
<span style="color: #5
if(object==null){
<span style="color: #6
throw new RuntimeException("argObj is null,cannot get field value ");
<span style="color: #7
<span style="color: #8
if(object instanceof String){
<span style="color: #9
return object.toString();
<span style="color: #0
<span style="color: #1
if(object instanceof Integer){
<span style="color: #2
int i = (Integer)
<span style="color: #3
//剔除成员变量的默认值
<span style="color: #4
<span style="color: #5
return i+"";
<span style="color: #6
<span style="color: #7
<span style="color: #8
if(object instanceof Long){
<span style="color: #9
long i = (Long)
<span style="color: #0
<span style="color: #1
return i+"";
<span style="color: #2
<span style="color: #3
<span style="color: #4
return null;
<span style="color: #5
<span style="color: #6
<span style="color: #7
private String getGetMethodValueByFieldName(String fieldName){
<span style="color: #8
return getMethodNameByFieldNameAndPrefix("get",fieldName);
<span style="color: #9
<span style="color: #0
private String getSetMethodNameByFieldName(String fieldName){
<span style="color: #1
return getMethodNameByFieldNameAndPrefix("set",fieldName);
<span style="color: #2
<span style="color: #3
private String getMethodNameByFieldNameAndPrefix(String prefix,String fieldName){
<span style="color: #4
if(StringUtils.isEmpty(fieldName)){
<span style="color: #5
throw new RuntimeException("cannot get Get method by null or length is 0");
<span style="color: #6
<span style="color: #7
if(StringUtils.isEmpty(prefix)){
<span style="color: #8
throw new RuntimeException("cannot get Get method by null without prefix");
<span style="color: #9
<span style="color: #0
String getMethodName = prefix+fieldName.substring(0, 1).toUpperCase();
<span style="color: #1
//fieldName 的长度大于一时,索引大于一的字符不改变大小写
<span style="color: #2
if(fieldName.length()&1){
<span style="color: #3
getMethodName = getMethodName + fieldName.substring(1);
<span style="color: #4
<span style="color: #5
return getMethodN
<span style="color: #6
<span style="color: #7
<span style="color: #8
private String response(String type, Object obj) {
<span style="color: #9
if (XML_TYPE.equalsIgnoreCase(type)) {
<span style="color: #0
String ret = OxmHelper.marshal(obj);
<span style="color: #1
logger.info("response:{}",ret);
<span style="color: #2
<span style="color: #3
<span style="color: #4
if (JSON_TYPE.equalsIgnoreCase(type)) {
<span style="color: #5
String ret = JSONObject.toJSONString(obj);
<span style="color: #6
logger.info("response:{}",ret);
<span style="color: #7
<span style="color: #8
<span style="color: #9
return ILLEGAL_TYPE + ":" +
<span style="color: #0
<span style="color: #1 }
1 package com.cul.culsite.service.
3 import java.util.ArrayL
4 import java.util.L
5 import java.util.S
6 import java.util.concurrent.TimeU
8 import org.slf4j.L
9 import org.slf4j.LoggerF
10 import org.springframework.beans.factory.annotation.A
11 import org.springframework.dao.DataAccessE
12 import org.springframework.data.redis.core.RedisO
13 import org.springframework.data.redis.core.RedisT
14 import org.springframework.data.redis.core.SessionC
15 import org.springframework.data.redis.core.ValueO
16 import org.springframework.stereotype.S
17 import org.springframework.util.A
19 import com.cul.culsite.service.RedisS
21 @Service
22 public class RedisServiceImpl implements RedisService {
private static final Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
@Autowired
private RedisTemplate&String, String& redisT
* 获取redis值
* @param key
* @return 值
public String get(String key) {
Assert.hasText(key, "redis get key cannot null");
return redisTemplate.opsForValue().get(key);
* 删除redis键
* @param key
void delete(String key) {
Assert.hasText(key, "redis delete key cannot null");
redisTemplate.delete(key);
* 设置redis值
* @param key
* @param value
* @param time
时间(分钟)
如果小于0 默认为1分钟
boolean setIfAbsent(final String key,final String value,int time) {
Assert.hasText(key, "redis set key cannot null");
Assert.hasText(value, "redis set value cannot null");
if(time&=0){
final int timeInSecond =
@SuppressWarnings("unchecked")
Object isSetSuccess = redisTemplate.execute(new SessionCallback() {
public Object execute(RedisOperations arg0)
throws DataAccessException {
//开始事务
List&Object& result=new ArrayList&Object&();
arg0.multi();
arg0.opsForValue().setIfAbsent(key, value);
arg0.expireAt(key,DateUtils.addSeconds(new Date(),timeInSecond));
arg0.expire(key, timeInSecond, TimeUnit.SECONDS);
//提交事务
result= arg0.exec();
logger.info("redis mutil for get lock result is :{}",result);
//执行了两次redis操作,应该有两个返回值,否则防止key永久有效,执行删除操作
if(result == null||result.size()!=2){
redisTemplate.delete(key);
return false;
//获取加锁操作的返回结果
boolean setIfAbsentResult = false;
if(result.get(0) instanceof Boolean){
<span style="color: #0
setIfAbsentResult =(Boolean)result.get(0);
<span style="color: #1
<span style="color: #2
//获取设置key有效时间返回结果
<span style="color: #3
boolean expireAtResult = false;
<span style="color: #4
if(result.get(1) instanceof Boolean){
<span style="color: #5
expireAtResult = (Boolean)result.get(1);
<span style="color: #6
<span style="color: #7
if(setIfAbsentResult&&expireAtResult){
<span style="color: #8
logger.info("加锁成功.......");
<span style="color: #9
return true;
<span style="color: #0
<span style="color: #1
}catch(Exception e){
<span style="color: #2
e.printStackTrace();
<span style="color: #3
<span style="color: #4
return false;
<span style="color: #5
<span style="color: #6
<span style="color: #7
<span style="color: #8
if(isSetSuccess instanceof Boolean){
<span style="color: #9
return (Boolean) isSetS
<span style="color: #0
<span style="color: #1
return false;
<span style="color: #2
}catch(Exception e){
<span style="color: #3
e.printStackTrace();
<span style="color: #4
return false;
<span style="color: #5
<span style="color: #6
<span style="color: #7
<span style="color: #8
<span style="color: #9
public Set&String& keys(String keyPattern) {
<span style="color: #0
Assert.hasText(keyPattern, "keys pattern is null");
<span style="color: #1
<span style="color: #2
return redisTemplate.keys(keyPattern);
<span style="color: #3
<span style="color: #4
<span style="color: #5
<span style="color: #6
public long incr(String key) {
<span style="color: #7
Assert.hasText(key, "key is null");
<span style="color: #8
<span style="color: #9
return redisTemplate.opsForValue().increment(key, 1L);
<span style="color: #0
<span style="color: #1
<span style="color: #2
public long decr(String key) {
<span style="color: #3
Assert.hasText(key, "key is null");
<span style="color: #4
<span style="color: #5
return redisTemplate.opsForValue().increment(key, -1L);
<span style="color: #6
<span style="color: #7
<span style="color: #8
<span style="color: #9
public void set(String key, String value) {
<span style="color: #0
Assert.hasText(key, "key is null");
<span style="color: #1
Assert.hasText(value, "value is null");
<span style="color: #2
redisTemplate.opsForValue().set(key, value);
<span style="color: #3
<span style="color: #4
<span style="color: #5
<span style="color: #6
public boolean set(final String key, final long value, final int timeInSecond) {
<span style="color: #7
Assert.hasText(key, "key is null");
<span style="color: #8
Assert.hasText(value + "", "value is null");
<span style="color: #9
Assert.hasText(timeInSecond + "", "timeInSecond is null");
<span style="color: #0
<span style="color: #1
<span style="color: #2
<span style="color: #3
@SuppressWarnings("unchecked")
<span style="color: #4
Object isSetSuccess = redisTemplate.execute(new SessionCallback() {
<span style="color: #5
<span style="color: #6
<span style="color: #7
public Object execute(RedisOperations arg0)
<span style="color: #8
throws DataAccessException {
<span style="color: #9
<span style="color: #0
//开始事务
<span style="color: #1
List&Object& result=new ArrayList&Object&();
<span style="color: #2
arg0.multi();
<span style="color: #3
arg0.opsForValue().increment(key, value);
<span style="color: #4
arg0.expire(key, timeInSecond, TimeUnit.SECONDS);
<span style="color: #5
//提交事务
<span style="color: #6
result= arg0.exec();
<span style="color: #7
<span style="color: #8
logger.info("result of redis set long value is :{}",result);
<span style="color: #9
//执行了两次redis操作,应该有两个返回值,否则防止key永久有效,执行删除操作
<span style="color: #0
if(result == null || result.size() != 2){
<span style="color: #1
redisTemplate.opsForValue().increment(key, (0 - value));
<span style="color: #2
return false;
<span style="color: #3
<span style="color: #4
//获取加锁操作的返回结果
<span style="color: #5
long incrementResult = 0;
<span style="color: #6
if(result.get(0) instanceof Long){
<span style="color: #7
incrementResult =(Long)result.get(0);
<span style="color: #8
<span style="color: #9
//获取设置key有效时间返回结果
<span style="color: #0
boolean expireAtResult = false;
<span style="color: #1
if(result.get(1) instanceof Boolean){
<span style="color: #2
expireAtResult = (Boolean)result.get(1);
<span style="color: #3
<span style="color: #4
if((incrementResult == value) && expireAtResult){
<span style="color: #5
return true;
<span style="color: #6
<span style="color: #7
}catch(Exception e){
<span style="color: #8
e.printStackTrace();
<span style="color: #9
<span style="color: #0
redisTemplate.opsForValue().increment(key, (0 - value));
<span style="color: #1
return false;
<span style="color: #2
<span style="color: #3
<span style="color: #4
<span style="color: #5
if(isSetSuccess instanceof Boolean){
<span style="color: #6
return (Boolean) isSetS
<span style="color: #7
<span style="color: #8
return false;
<span style="color: #9
}catch(Exception e){
<span style="color: #0
e.printStackTrace();
<span style="color: #1
return false;
<span style="color: #2
<span style="color: #3
<span style="color: #4
<span style="color: #5
<span style="color: #6
<span style="color: #7
public Long getLong(String key) {
<span style="color: #8
<span style="color: #9
Set&String& keys = redisTemplate.keys(key);
<span style="color: #0
//key指定的数据不存在
<span style="color: #1
if (keys == null || keys.isEmpty()) {
<span style="color: #2
return null;
<span style="color: #3
<span style="color: #4
return redisTemplate.opsForValue().increment(key, 0);
<span style="color: #5
} catch (DataAccessException e) {
<span style="color: #6
logger.info("error :{}", e);
<span style="color: #7
logger.info("{}指定的数据不是数值类型", key);
<span style="color: #8
throw new RuntimeException(key + "指定的数据不是数值类型");
<span style="color: #9
<span style="color: #0
<span style="color: #1
<span style="color: #2
public Long getLongNoKeys(String key) {
<span style="color: #3
<span style="color: #4
long keys = redisTemplate.opsForValue().increment(key, 0);
<span style="color: #5
<span style="color: #6
} catch (DataAccessException e) {
<span style="color: #7
logger.info("error :{}", e);
<span style="color: #8
logger.info("{}指定的数据不是数值类型", key);
<span style="color: #9
throw new RuntimeException(key + "指定的数据不是数值类型");
<span style="color: #0
<span style="color: #1
<span style="color: #2
<span style="color: #3
<span style="color: #4
<span style="color: #5
<span style="color: #6
<span style="color: #7
* 删除set集合中的对象
<span style="color: #8
* @param key
<span style="color: #9
* @param value
<span style="color: #0
<span style="color: #1
<span style="color: #2
public void srem(String key, String value) {
<span style="color: #3
redisTemplate.boundSetOps(key).remove(value);
<span style="color: #4
<span style="color: #5 }
使用方式:
* @Description:
* @param @param request
* @param @return
* @param @throws Exception
* @return String
* @author liping.sang
@RedisLock(fieldName={"reqNo"},timeInSecond=3)
@RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, value = "/conversionCodeModel2")
@ResponseBody
public String conversionCodeModel2(HttpServletRequest request)
throws Exception {
<span style="color: # &aop:pointcut expression="execution(* com.cul.culsite.controller.ConversionCodeController.conversionCodeModel2(..))" id="conversionCodeModel2Redis"/&
<span style="color: #
<span style="color: #
&aop:around method="redisLockParse" pointcut-ref="conversionCodeModel2Redis"/&
阅读(...) 评论()

我要回帖

更多关于 数据库 的文章

 

随机推荐