Amos's Blog

大数据|容器化|♾️

0%

Bug的起源和解法

这个错误来的实在猝不及防,第一次请求可以成功使用JedisPool,而第二次请求便会报错,在翻遍了所有相关博客后一度以为是自己的配置出了错,于是不断修改配置文件中的redis连接池参数。
折腾老半天之后,没有帮助TAT
这时,我想起10年前的某个午后,蝉鸣的空气中传来的几分安定,出神地趴在窗边看麻雀扑腾的我,被一声厉呵带回现实。之后便到了标准环节–”下课到办公室找我”。之后的事情便记不太清了,只是我深深地记得当时的心境,想不出的问题换个角度想,一定会有不同的发现。
那就回归报错吧,“无法将资源返回到池”,再回想到我的jedisPool对象,旷的一声,仿佛天旋地转一般,一切的一切突然都变透彻了。

错误根源及出错原因

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public boolean followUser(Integer localUserId, Integer userId) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.zadd(localUserId + RedisKey.FOLLOW_USER, System.currentTimeMillis(),
String.valueOf(userId));
jedis.zadd(userId + RedisKey.FOLLOWED_USER, System.currentTimeMillis(),
String.valueOf(localUserId));
} catch (JedisException e) {
return false;
}
jedisPool.close();// 问题就出在这里
return true;
}

JedisPool在configuration类中初始化(项目启动时有spring自动扫描)
然而在每个业务类调用完之后就被手动关闭,自然执行完第一次后就不再能取出resource的,也无法return。
解决这个bug只需把每个service实现类中的jedisPool.close()删去即可。

为什么会出现这种写法

说到这个就不得不提起Jedis的wiki
官方po出的demo是这样使用jedis的:

首先引入pom

1
2
3
4
5
6
7
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

然后实例化JedisPool

1
JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

接着实例化jedis有两种方法

  1. try-with-resource法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement.
    try (Jedis jedis = pool.getResource()) {
    /// ... do stuff here ... for example
    jedis.set("foo", "bar");
    String foobar = jedis.get("foo");
    jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
    Set<String> sose = jedis.zrange("sose", 0, -1);
    }
    /// ... when closing your application:
    pool.close();// 这便是原罪
  2. 手动关闭jedis法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Jedis jedis = null;
    try {
    jedis = pool.getResource();
    /// ... do stuff here ... for example
    jedis.set("foo", "bar");
    String foobar = jedis.get("foo");
    jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
    Set<String> sose = jedis.zrange("sose", 0, -1);
    } finally {
    // You have to close jedis object. If you don't close then
    // it doesn't release back to pool and you can't get a new
    // resource from pool.
    if (jedis != null) {
    jedis.close();
    }
    }
    /// ... when closing your application:
    pool.close();
    虽然不在报错了,但是现在不关的话又不知道在哪能关的了它了。。。

双手奉上: Jedis官方指引

开篇

此文仅用于记录vue开发中遇到的各种奇葩事。

错误

项目不报错但是路由不加载

前方预警:这是个低级错误Orz
index.js

1
2
3
4
5
6
7
8
9
10
11
routes: [
{
path: '/',
name: 'Index',
component: {
nav: Navv,
main: Index,
footer: Footter
}
}
]

App.vue

1
2
3
4
5
6
7
<template>
<div id="app">
<router-view name="nav"></router-view>
<router-view name="main"></router-view>
<router-view name="footer"></router-view>
</div>
</template>

如果你和我一样是只小白菜,可能咋一看会发现没什么毛病,仔细一看就会发现路由配置里的components被我写成了·component·。。
vue中到目前为止我知道的两种路由配置方式:

1
2
3
4
5
6
7
8
// 第一种
...
component: navv
...
// 第二种
components: {
navv
}

over, 经验值 +1

Failed to execute ‘setAttribute’ on ‘Element’: ‘method+’ is not a valid attribute name.

由于项目中引入了饿了么开发的组件库·element-ui·,所以一度以为是和我引入的css文件起了冲突??甚至我还去执行了npm uninstall element-ui这条命令。最后实在没办法了,一段一段代码排查问题,找到一个诡异的地方。。

1
2
3
4
<form action="/listTopic" method+="post">
<input name="topicName" type="text" class="search-input" placeholder="搜索你感兴趣的内容...">
<button type="submit" class="search-button"><i class="sprite-search"></i></button>
</form>

噗。。form标签下的method方法多了个+号。。。想拿头去撞豆腐了。
ok,经验值 +1

最近又折腾起了python,于是发现很久以前的自己在各个地方留下了python的足迹,简直就是个更新日志。。
既然习惯了brew这个管家,那就把以前的坑都填好吧!

安装软件的时候很快活,卸载的时候就难受的不行,不熟悉系统目录,你就根本卸不干净。
当然市面上有很多pkg卸载软件,但是强迫症的自己总觉得它卸不干净

搜了一票国内论坛。。还是跑去StackOverFlow,找到了一个靠谱回答。
答主提供了python官网的反馈页面,是一位不知如何完整卸载python的网友提交的反馈。
一个叫Ned Deily的朋友提取了安装目录并将其制成卸载脚本(详情见参考链接)
知道了该删哪就可以动手了…

阅读全文 »

先贴Redis官网:https://redis.io/download

1
2
3
4
$ wget http://download.redis.io/releases/redis-4.0.2.tar.gz
$ tar xzf redis-4.0.2.tar.gz
$ cd redis-4.0.2
$ make

如果没有安装gcc,则会抛出这样的错误:

1
$ yum install gcc

在执行一次make可能会再抛出这样一个错误:

这样的话便在make后加上参数

1
$ make MALLOC=libc

编译完成后

1
$ src/redis-server  redis.conf
阅读全文 »

一直听说item2是个比terminal强大的终端工具,为了提升命令行的体验,从teminal切换到了item2。

下载Item2

https://www.iterm2.com/downloads.html

设置开启快捷键

前提是item2在后台运行
-> 进入preference(command ,)
-> keys
-> Hotkeys(左下角) 勾选Show/hide iTerm2 with a system-wide hotkey
然后就按喜好设置快捷键啦

配色方案

可以自定终端背景色或导入现成的配色方案,比如Solarized
跳到Download下载后选择相应的文件导入

你可以选择双击’.itermcolors‘文件或在preference -> profiles -> colors -> Color Presets(右下角)-> import… 中导入

安装zsh

osx中默认zsh为4.0版本,可直接切换使用或下载最新的5.0版本

1
brew install zsh
阅读全文 »

分析问题

前端显示页面

数据库页面

目前可以推测出的几种情况:

数据库表的字符编码与服务端不同
字符编码为非utf-8,gbk等能识别中文的编码
配置文件出错(读取或编写格式

阅读全文 »

记得前阵子面试金山时碰到了这样一个问题

1)下面哪一种写法更好,为什么?
2)请写出另一种单例模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton {

private static Singleton singleton;

private Singleton() {}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {

private static volatile Singleton singleton;

private Singleton() {}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

很显然,第一种代码块是线程不安全的。
比如说这种情况,有一个线程调用了getInstance(),但执行到if(singleton==null)这一步时,另一个线程也进入了这个方法,那么便会造成最终创建了两个Singleton实例。
而若是第二种代码块,在同步锁中加入第二次验证,就不怕多个线程同时进入方法体导致的多个实例被创建了。

以上两个方法块俗称懒汉式单例模式,意为调用时再创建实例对象。

另一种单例模式称为饿汉式单例模式,不同的点在于类装载时便完成了类实例化,以下两种方法块都是饿汉式的表现方法,是一样的。

1
2
3
4
5
private static Singleton instance = new Singleton();

static {
instance = new Singleton();
}

最后再推荐个与双重检查一样线程安全的,静态内部类实现的懒汉式单例模式。

1
2
3
4
5
6
7
8
9
public class Singleton(){
private Singleton{};
private static class LazyHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return LazyHolder.INSTANCE;
}
}

这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

1
2
3
4
DEBUG SMTP: trying to connect to host "xxx.xxx.com", port 587, isSSL true
send failed... the exception is javax.mail.MessagingException: Could not connect to SMTP host: xxx.xxx.com, port: 587;
nested exception is:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

如果你遇到了这种报错,而其它办法又解决不了。
不妨试试调整properties的put()方法放置顺序吧。
起初我也觉得put()顺序并不会影响到后续的其他方法块对它的读取啊。
然而当我调转了它们的位置时,不再报错了。。
邮件成功的发送出去了。

这是我放置properties的方法块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MailSSLSocketFactory mssf = null;
try {
mssf = new MailSSLSocketFactory();
mssf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.socketFactory", mssf);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.port", "587");
properties.put("mail.smtp.ssl.socketFactory.port", "587");
properties.setProperty("mail.imap.ssl.socketFactory.class", "DummySSLSocketFactory");
properties.setProperty("mail.imap.ssl.socketFactory.fallback", "false");
// properties.setProperty("mail.smtp.port", "587");
// properties.setProperty("mail.smtp.socketFactory.port", "587");
// properties.setProperty("mail.imap.ssl.enable", "true");
// properties.setProperty("mail.imap.ssl.socketFactory.class", "DummySSLSocketFactory");
// properties.setProperty("mail.imap.ssl.socketFactory.fallback", "false");
} catch (final GeneralSecurityException e) {
e.printStackTrace();
}

而你需要做的便是把

properties.put(“mail.smtp.ssl.enable”, “true”);

放在

properties.put(“mail.smtp.port”, “587”);
properties.put(“mail.smtp.ssl.socketFactory.port”, “587”);

的下面。

玩了一下Java Mail,试图使用QQ邮箱作为发送者的邮箱,当然填写在代码中的邮箱密码写的是明文真实密码啦。
喜闻乐见的是出现了error 530,这个错误的产生实际上也是腾讯对自己邮箱用户的保护机制啦。其一是谁也不希望自己的产品被克隆。其二是用户异常操作时,找不到操作记录,是不是很扎心?

于是,兜了一大圈,再回到正题上来。

1
javax.mail.AuthenticationFailedException: 530 Error: A secure connection is requiered(such as ssl). More information at http://service.mail.qq.com/cgi-bin/help?id=28

530报错提示需要一个安全的链接(比如ssl啦stl啦),这里就po一下ssl加密的代码吧。(其实stl也差不多的啦~

1
2
3
4
5
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);

prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);

把它加进自己的代码里就阔以啦。
当然,邮箱里的POP3/SMTP服务与IMAP/SMTP服务就开起来吧。
嗯,还有,为了防止邮箱密码泄漏,腾讯给了每个用户数个登录第三方客户端的授权码,也就是可以当作密码使用的一段16位无序字母组合,那么,玩得开心。

相关链接
关于Java Mail简单粗暴的教程(菜鸟教程)
如何使用 Foxmail 等软件收发邮件?(腾讯)
什么是 IMAP,它又是如何设置?(腾讯)

将hexo从win迁移到mac时发生了安装错误。

没有保留报错截图,就从日志文件中截取了关键段落。

1
2
3
4
5
6
7
5751 error code ELIFECYCLE
5752 error errno 1
5753 error hexo-util@0.6.0 postinstall: `npm run build:highlight`
5753 error Exit status 1
5754 error Failed at the hexo-util@0.6.0 postinstall script.
5754 error This is probably not a problem with npm. There is likely additional logging output above.
5755 verbose exit [ 1, true ]

按照网上的几种解法都没能完成安装

sudo npm install -g hexo-cli

sudo npm install hexo –no-optional

sudo npm install -g hexo-cli –registry=https://registry.npm.taobao.org

最后尝试进入root权限中执行npm命令,即

1
2
sudo -s
npm install -g hexo-cli

安装成功。

阅读全文 »