Spring Data Redis

当我有一个想法,使用Spring Data Redis的时候,我想到了JPA, 想到了Spring Data Mongo,一想Spring Data统一了Dao层的编程模型,我就觉得我可以轻松驾驭Spring Data Redis,果然想法是天真的。当我准备启动项目的时候,就报了一个错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'com.example.demo.repository.VocabularyEntityRepository' that could not be found.

然而我明明看到了

我也是加了@Repository注解,同时也看到了Bean的图标,但是确告诉我没有注入这样的Bean,就很疑惑,同样我也没有办法直接判断为什么没有注入成功。一想到以前没有注入成功的原因大半是因为package的问题导致没有扫描到,现在我再三检查了一下,也没有问题。第二就是我想到是不是命名的问题导致的,几经折磨,发现并不是。

这时时间已经过去了许久。我想这时候就开始看官网了,首先是找到Spring Data Redis 的文档看了一番,然而并没有看到什么问题,一想到Spring Data Redis肯定是开箱即用的,也就是我不需要额外的配置,除非我使用的不是默认的配置,显然我是完全按照默认的配置来的,所以我排除了配置的原因。

接着,我想到了Spring Data Example这个项目,这是一个示例项目,也就是怎么使用的问题。果然,还是这个好使。一会我就找到了答案:

原来我少的一个关键的注解,那便是@RedisHash(“xxx”), 这一下就让我想起了以前用关系型数据库mysql,postgresql,时,我会在实体上标注@Entity,使用mongo或者es的时候,我会用@Document。

当然,我第一次还看到了下面的配置:

一看到@EnableRedisRepositories再结合错误,没有找到Repository,自然一下子就看到了曙光,一顿操作,果然服务起来了。

然后,我理解Spring Data Redis也应该是默认就开启了@EnableRedisRepositories,所以我尝试删除了这个配置类也是可以启动了,验证了我的想法。

最后,我想这次解决没有找到Repository的问题,其实是个人经验总结和摸索出来的,但是我看到了一个更好的解决问题的模型——那便除了文档之外,我们可以直接看别人的示例源码,因为在我们用之前,它肯定提供了示例。

当然,我在看到官方提供的示例源码之前,也看到了一些别人写的代码,但是,就算源码中包含了解决方案,也会被更多的变量所覆盖,比如版本问题,以及版本带来的依赖问题,Api变化问题,等等,所以一下子很难看到是哪个原因导致的。所以在分析原因的时候,我们要控制好变量。不然,很容易就被带歪了,比如,我看到了一个示例代码就有:

但是,我那时并没有关注到这个注解@RedisHash(“xxx”)。

敏锐的目光需要不断地打磨,因为你要知道Repository的原理的话,估计就不会出现这些问题。但是平时大都在应用层,我们更多的关注点都在使用Api,并没有深层次的了解那些看起来不起眼的注解上,比如在Feign API时,就经常出现项目没有办法启动,因为就是少了注解,比如@RequestParam.

记在最后,当使用的示例是最好的学习方式,应该这样能最快地解决应用问题。

原本,文章到此就结束了,但是我想起来今天看文档地一点收获也顺便记一下。

我发现Redis也是可以支持Geo的,这让我联想起了Mongo也是支持同样的操作的,然后就顺便看了一下例子:

@RedisHash("people")
public class Person {

  @Id String id;
  @Indexed String firstname;
  String lastname;
  Address hometown;
}

public class Address {

  @GeoIndexed Point location;
}

再看@GeoIndexed注解就很亲切。

Find using Geo Index:

repository.findByHometownLocationNear(new Point(15, 37), new Distance(200, KILOMETERS));
List findByAddressLocationWithin(Circle circle)

这行代码看上去就很美,此时的心情也很美。

是什么促成了你成为一名“厉害的”开发者?

当看到“厉害的”这个词的时候,我希望你知道我指的是“令人倾佩”,“令人欣赏”的意思。同时我也觉得你一定是见过这样的人。

那么我们到底欣赏他(她)的是什么呢?

肯定是他(她)一定是解决问题能力很强的人。在实际编程问题中,我们都是在解决问题,我曾向我母亲解释我的职业,或者说我的工作——有点像小学的时候解决数学应用题。编程很多的时候都是在解决问题。只不过我们不是用数学的语言,而是用编程语言。

解决一个问题,如果你知道的知识比较多,比如你现在已经是中学毕业了,假设你学业成绩还不错,你再去看小学的数学应用题,我想应该不是很难,你可以比较轻松地解题。高出那个级别,你就很容易,因为你掌握足够的知识。所以不断让自己级别提高就是掌握更多的知识。

解决问题,尤其是相应的知识掌握的比较多,你解决问题的能力自然不会很低。知识一定只是解决问题的一个方面,有时候尽管你掌握了很多的知识,包括解决相应问题方面的,你一定会那是那个令人倾佩,令人欣赏的开发者吗?

我看不一定是。知识只是一个方面。解决问题,除了拥有知识,还需要拥有解决问题的动力。你知道该怎么做,但是不一定说你一定会去及时做。你没有及时做的原因,可能是你懒了,也可能是你没有排好事情的优先级,你可能觉得自己不懒,现在你可能觉得我说“懒”是一个贬义词,其实懒是让你蜕变的一个内在因素,相反如果你一直那么忙碌,一直那么勤劳,有时并不是表面上看到的。懒一定程度上触发了思考,触发了创新。懒是惰性导致的,你有时都没有感觉到自己懒。但不管怎样,我说这么多,就是让你认识到,我说懒,并不是说你怎么不好,请一定要理解。

我们经常没有意识到一个问题,那就是客观的时间和自己的精力都是有限的,至少是今天有限。有时候我们在解决一个问题,在思考一个bug怎么解决,我们就会投入进入,然后时间就在默默流逝,当然你的精力也是在以不易察觉的形式流逝。有点像手机里的电池一样,你每天早上醒来,经过一夜的充电,活力满满,元气十足,那是你休息了一晚,睡了个好觉。然后经过一天的工作,思考一些问题,写一些代码,你的电池就会慢慢放电,直到电量90%,80%,70%,下午的时候甚至就只有40%,接近下班的时候就或许只剩下15%。关于时间和精力的问题,我以前只认为是程序员乐观导致错误地估计,后来有一天我突然认识到,乐观不仅仅程序员的“特权”,很多人都拥有着,并使用着。

我上面提到有时候没有解决问题,可能是你动力不足,也可能是你安排不当。如果我们深刻地意识到时间和精力是有限的,我们一定要懂得合理安排事情,解决工作的问题也是一样,这里可能就是指编程中问题,你一定要认识到那些事情是你可以及时解决的,那些问题需要你及时解决的,不是别人怀疑你的能力,而是工作的方式,需要为自己的工作事项,合理安排时间和顺序,这样你才能提高解决问题的能力,这种能力和知识无关,可以叫做工作方法。如果工作方法也叫知识的话,是的。它也是知识,你现在掌握了,以后应用的时候,你如果没有及时解决问题,不要怪罪于不知道怎么做的知识层面,而应该更多的时候,想想你工作方法有问题。

我们再深入一点,我上面“普及”的知识是你第一次听到吗?如果真的是,你真应该好好庆幸,你get到了这块知识。我们在上学的时候,可能就听说过,“事情要分清楚轻重缓急”。我想上面的工作方法也是由它进化而来的。工作中给各种事情排个号,在什么时间做什么事,重要的事情,需要优先完成。所以说这块知识,你可能已经掌握了。那你为什么没有做呢?因为做这项事情是需要思考的,思考是件需要克服惯性的,如果你的惯性就是不给事情排优先级,按照事情进行的顺序,或者说事情来到的顺序来做,那么你很有可能是没有很好地提高解决问题地能力。

我大学的时候曾经一度认为,我是一个分不清事情轻重缓急的人,我那个时候经常会遇到很多的事情并发地发生,需要我去处理。然后有时候,我没有做好一些事情,比如我当时在学生会中的一些工作,在比如学习上的一些事情。

我今年看了一些书籍,那些书籍竟然是理财方面的,我认识到了,在行动的内部,是由思想控制的,但很多时候行为却是由惯性控制的,它有点跳过思想,它的喜好更多的时候就是不喜欢思考。如果你养成了这个习惯,可能还自己都没有认识到,它伪装的如此完美,就像隐身术一样,你看不到它,但是它却在暗中“左右”着你的行为。

如果你养成了把事情排个优先级的习惯,解决工作中的问题的时候也是如此,那么你解决问题的能力会有较大的提升。这就是习惯的力量。而且你发现这将是一个好的习惯,它会你把有限的时间和精力发挥地淋漓尽致。

习惯的养成,需要我们付出努力,因为你可能经常放弃,或者产生放弃的想法,但是你要知道,你要想提高解决问题的能力,在知识方面你也在积累,但是更多的时候,好的工作方法——这是习惯提供给你的,会让你事半功倍。

我现在分享到的“习惯”还只是知识层面,应该它只有落实到行动上,才会是属于自己的习惯。这个习惯需要时间的洗礼。

我还想起了一段话,这段话是——编程中,不要相信你的眼睛,而要相信你的Ctrl+C和Ctrl+V。这是我们写代码中经常出现的,有时候,我们经常去敲一些单词,可能是变量,但是最后程序的运行结果却不是我们期待的。

这表面上也是编程中的方法问题,其实也是习惯问题。当你养成了相信计算机而不是自己的时候,你犯错的概率也会大大下降,当然现在的IDE很多的时候都在帮你少犯一些“低级”错误。

回到主题上来——是什么促成了你成为一名“厉害的”开发者?

上面主要提到的是知识之外的——解决问题的能力养成,在有限的时间和精力中把事情习惯地排上优先级,然后再一一完成事情。

解决问题,还需要知识。我记得我在《HOW TO DEVELOP QUALITY SOFTWARE WITH A GOOD VELOCITY》中提到过知识是需要积累的,但你可以掌握快速地解决问题的最少知识,快速地获取知识也绝对是一门可以练习的技能。这个话题我想此时不在这篇文章中展开。

虽然文章大篇幅地在讲知识之外的能力——养成好的工作方法,形成习惯。但是我们在用好的工作方式的同时,我们一定也不会忘记知识的力量。

透过现象看本质–编程中的错误解决

我之前在思考怎么快速地开发高质量软件,其中就有“ 快速 ”二字,我们开发中如果顺畅地写代码,时间不会占用太多,但如果写代码的过程中“不顺”,我们可能会陷入进去,这是一个很自然的结果。然后一陷入进去,意味着你可能去“探索”去了,你如果快速地解决了问题,这倒是一个很好的结果。

但我们现在回到问题解决的本身上。

解决问题,尤其是开发中的问题,有一些是,技术问题,比如我在写代码过程中遇到的:

这个错误是在badUser.html页面中使用到了
<h1 class=”alert alert-danger” th:utext=”${param.message[0]}”>error</h1>

这主要是Thymeleaf中的问题,由于我使用的较高版本的Thymeleaf 3.0.11,上面的代码在低版本中是没有问题的,如果在不会退版本的前提下——假定的项目框架环境,我们来解决这个问题。

具体的错误信息还是比较清晰的:

A problem occurred whilst attempting to access the property ‘param’: ‘Access to variable “param” is forbidden in this context. Note some restrictions apply to variable access. For example, direct access to request parameters is forbidden in preprocessing and unescaped expressions, in TEXT template mode, in fragment insertion specifications and in some specific attribute processors.’

根据错误我们看一下源码:

错误信息指出,在受限的访问上下文中,如果访问的是受限变量–>param,就会有TemplateProcessingException。

那么我们可能思考的是怎么去解决这个问题?

错误说它不允许访问param变量中的信息,它不允许是出于安全的角度来限制的,那么它不允许我们访问,我们又需要访问,那框架总要提供一种方式,让我们访问,可能我需要需要做一些调整,或者额外的努力,但是我们的功能性需求就是访问到后台传到页面中的信息。

……

上面很容易陷入到“思考怎么解决问题”这个细节出来,这是我们软件开发中可能会经常出现的技术问题。

但是在这些技术问题的背后,其本质是什么呢?

在遇到技术问题时,如果你还记得—— 当问题是一个问题的时候,那一定是

问题 > 人 

我们太关注问题本身了,所以让它难住了我们。

我们深刻地意识到问题之所以是问题的时候,那么就是开始没有问题的时候。

上面说到的技术问题,其实本质是我们对Thymeleaf框架的内部细节没有掌握,如果我们看到上面出错的源码,只是问题的局部,也就是问题森林中的一棵树。

但如果我们看到的是整个森林,我们就不会陷入到具体的一棵树上。我们如果熟悉Thymeleaf框架,我们会就理解为什么在受限的上下文中访问受限的变量需要抛出一个异常。我们会进一步理解,什么是受限的上下文。什么是受限的变量。如果需要访问受限的变量,怎么做。

所以我们需要去“探索”它产生的原因,于是我们来到了GitHub

而我们代码中真正报错的也是 th:utext=”${param.message[0]}”>error,所以我们可以换一个标签th:text=”${param.message}”,这是直觉,也是一些知识的积累。然后就是这个小小的改动就可以实现错误的解决,也同时完成了功能性需求。

我以前也是经常想,为什么我不能快速把问题解决掉呢?还总是带着一丝丝自责,觉得自己不够好,不够优秀,至少是没有快速地解决问题。其实在开发中我们基本上不可能是一番风顺的,软件的不透明性就决定了软件开发的复杂性的存在,所以积累知识是一方面,另一方面是快速定位问题的发生根本原因。

还有一种很大的可能你没有遇到上面那个问题—— 使用th:text 而不是th:utext, 因为你可能一开始就是接触到了th:text, 问题的解决就发生在了问题发生之前。有时候这是习惯的力量,有时候这是知识的力量。

但上面的问题发生在“遗留的代码”中,也就是说并不是你自己从头开始写的代码,也是维护别人的代码,这也是开发中经常存在的。我们经常会忽略一些细节,因为我们也可能不知道,比如上面的th:utext标签随着版本迭代升级而新出的问题。

如果说知识的积累是一个方面,我们可能在这一块没有什么优势–>由于我们年轻,所以积累是件好事,年轻的我们可以积累。同时在“ 积累”有所欠缺的情况下, 我们要动脑筋,想办法弄清楚问题发生的根本原因,然后可以利用一些工具,比如搜索引擎来收集信息,定位问题,然后再解决问题,当然这是个人的独立解决问题的方式,如果你的环境中有集体帮助,比如头脑风暴,也是会有帮助的。

集体中,不要害怕问题,也不要害怕问问题,只要是你经过思考的问题,提炼问题,你可以在合适的时候尝试与别人交流一下。因为解决问题本身是件快乐的过程,帮助他人也是,问高质量问题也是的。一个好的环境一定是彼此共同学习,共同成长,共同提高的。

如果要总结一下全文,编程中的确会有遇到一些不顺的时候,本文就只提到技术问题,可能还会有其它的问题,在解决技术问题的过程中,我们要透过问题本身看问题本质,比如出现这个问题的根本原因是你不知道某些技术细节导致问题发生,所以你要去发现、学习那些技术细节,然后才能解决问题。同时你也要认识到积累的力量,但更重要的是你要去想想怎么去收集那些未知的细节,这种能力对快速解决问题还是很重要的。