日常问题汇总

背景

通过本文档记录下日常发现的一些问题。

  1. mysql任何命令返回ERROR 1115 (42000): Unknown character set: ‘’
    没有指定当前session使用的character set。简单解决,用charset 字符集来解决。如果上述报错里,set: 后明确了某种字符集,要看下当前mysql的版本是否支持,再更换为支持的字符集。

Go系列-入门01

背景

近期换了新的工作,新公司的主要技术栈使用的Go,当然我也是为了挑战自身,从之前的Java转型到go,来看看更广阔的技术世界。写一些学习心得来记录自己的总结和反思。

结构体方法

这是初学go的时候,最让人困惑的地方。一个方法既有入参,又有返回值,为什么还来了一个接受者。但无论如何,go的函数支持这种格式,struct+func的这种方法,似乎等价于Java中的class里的method。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package learning

type Student struct {
Name string
Number string
}

func (s *Student) GetName() string {
return s.Name
}

func (s *Student) SetName(name string) {
s.Name = name
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"qyd/first/eg/learning"
)

func main() {
student := learning.Student{"Camel", "0001"}
fmt.Println(student)
student.SetName("Camel2")
fmt.Println(student)
}

值传递

go仅支持值传递,这是个好事,也不是个好事。
java中基于基本类型和复合类型分为值传递和引用传递,go中如果要实现引用传递修改参数内容,可以明确使用指针,这确实比较清晰。
说这个不是好事,无非在一些场景,你需要仔细考虑使用指针的场景。例如上述的结构体函数,在进行修改等动作的时候,是否要影响结构体本身的参数值,是在开发的时候要斟酌的。

另外要补充的一点,基本类型的值不可能为null,也就是不能为nil。nil只能赋值给pointers, interfaces, channels, slices, maps and function,表示一种还没有初始化的状态。

go工具箱

go是使用多种命令来进行项目的构建,包的引用等。目前使用比较多的是go get,go build,go install,go mod。而且很神奇的一点,go mod可以灵活依赖任意go module,并且可以随意依赖github上的代码,十分刺激,简直天生开源。

面向对象

可能目前写go的感触还不是很深,现在只能用面向过程的编程方式来理解go的玩法。似乎结构体可以比较好的解决这个问题,但是代码写起来还是挺怪的。(通过定义结构体的方式来定义出来java里的各种service?)

包括注入等玩法,似乎也支持,只是自己没有学习的特别深入。

Hello World Again

又重新拾起Hexo了。

确实从上一次开始用Hexo写博客,感觉已经过去了好久,这次用Hexo和自定义域名打通推送博文,一方面是记录下自己的经历,另一方面也是为了督促自己尽快的拾起学习的动力。

希望这次Hello World是最后一次了,不要打脸啊。。。。

在CentOS上安装MySQL

背景

主要就是为了有一个地方能够存储数据,来提供一些服务,当然包括这个网站的数据服务。因为买的是阿里云的ECS,又没钱买RDS服务,所以干脆把网站和数据库放在一起了。

通过yum安装

  1. 查看已安装的MySQL信息

    1
    # yum list installed | grep mysql
  2. 如果有,可以卸载

    1
    # yum -y remove mysql-libs.x86_64
  3. 安装MySQL

    1
    # yum -y install mysql-server mysql mysql-devel
  4. MySQL的几个配置文件和命令

    1
    2
    3
    4
    5
    6
    7
    配置文件位置: /etc/my.cnf
    MySQL数据库文件存放位置: /var/lib/mysql/
    启动MySQL: service mysqld start
    停止MySQL: service mysqld stop
    重起MySQL: service mysqld restart
    设置开机启动: chkconfig mysqld on
    查看是否开机启动(2到5为on则正常): chkconfig --list | grep mysqld

配置MySQL

首先第一次登陆MySQL,使用root账户,不需要密码

1
# mysql -u root

修改root的账户密码,以及删除匿名用户

1
2
3
4
5
mysql>select user,host,password from mysql.user;
mysql>set password for root@localhost=password('你的root密码');
mysql>update mysql.user set host='%' where user='root' and host='localhost' // 为了后面可以使用root在其他主机连接MySQL服务
mysql>delete from mysql.user where user=''; // 删除匿名用户
mysql>GRANT ALL PRIVILEGES ON *.* TO ‘myuser’@'%’ IDENTIFIED BY ‘mypassword’ WITH GRANT OPTION; // 授予myuser用户使用mypassword连接本机的MySQL服务,最好重启一次mysqld

连接MySQL

我是下载的MySQL提供的GUI工具MySQL Workbench测试连接的,使用界面十分简单。Windows用户记得安装.net Framework,Mac用户应该直接可以使用。

Java对象的状态与可变性

问题引入

近期再看Java的多线程处理,其中有两对概念需要进行一下总结:有状态和无状态,可变类和不可变类。

首先要明确一点,这两对概念都是针对类实例化都的对象而言,因为对象是动态的,而类可以认为是一种数据模板。

有状态对象与无状态对象

有状态是指bean可以保存数据,是非线程安全的。而无状态是指bean不能保存数据,是线程安全的。

在这个概念中,数据既可以指实例变量,又可以指其他类的对象引用

实际上在工作中对对象的处理基本上都是使用spring框架,在spring中,类实例化的默认方式都是单例(singleton),这种方式生成的单例对象都是无状态的,这里由spring处理多线程问题(例如使用TreadLocal)。但是要注意:这并不是说单例就是无状态的,单例是可以为有状态的。同理,scope为原型(Prototype)的类实例化后就是有状态的。

在日常工作中,经常会按照MVC划分代码层次。一般而言,Service与Dao层的类都是无状态的,即仅使用一次。

可变对象与不可变对象

首先看下Oracle对于不可变对象(immutable object)的定义与示例。

当一个对象构建好后其状态不再会被改变,那么这个对象就可以被称作不可变对象。最大程度地依靠不可变对象是在编写简单可依赖代码的一个被广泛接受的成熟策略。

不可变对象在并发应用当中十分有用。鉴于它们的状态不能被改变,不可变对象不会被线程干扰毁坏或者被观察时处于不一致的状态。

程序员通常不愿意使用不可变对象,因为他们担心用对象的创建替换对象的更新的成本。对象创建的影响通常被过高的估计,并且可以被使用不可变对象相关的一些效率进行补偿。这包括由于垃圾回收而降低的开销以及去除了为保护可变对象不受污染的代码。

这段说明不仅给出了不可变对象的定义,还指出了不可变对象的优点:多线程并发下的同步性。根据Oracle中给出的不可变对象的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class SynchronizedRGB {

// Values must be between 0 and 255.
private int red;
private int green;
private int blue;
private String name;

private void check(int red,
int green,
int blue) {
if (red < 0 || red > 255
|| green < 0 || green > 255
|| blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}

public SynchronizedRGB(int red,
int green,
int blue,
String name) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}

public void set(int red,
int green,
int blue,
String name) {
check(red, green, blue);
synchronized (this) {
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}
}

public synchronized int getRGB() {
return ((red << 16) | (green << 8) | blue);
}

public synchronized String getName() {
return name;
}

public synchronized void invert() {
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
name = "Inverse of " + name;
}
}

在上述的SynchronizedRGB中,存在多线程的并发问题。例如在执行getRGB()getName()之中对这个类的对象进行改变后,就有可能得到不同的结果。在Oracle官方教程中给出的解决办法是:

1
2
3
4
synchronized (color) {
int myColorInt = color.getRGB();
String myColorName = color.getName();
}

而使用不可变对象处理上述场景时,可以编写如下的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
final public class ImmutableRGB {

// Values must be between 0 and 255.
final private int red;
final private int green;
final private int blue;
final private String name;

private void check(int red,
int green,
int blue) {
if (red < 0 || red > 255
|| green < 0 || green > 255
|| blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}

public ImmutableRGB(int red,
int green,
int blue,
String name) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}


public int getRGB() {
return ((red << 16) | (green << 8) | blue);
}

public String getName() {
return name;
}

public ImmutableRGB invert() {
return new ImmutableRGB(255 - red,
255 - green,
255 - blue,
"Inverse of " + name);
}
}

ImmutableRGB中,很明显可以看出,所有的成员变量都定义为final类型,并且去除了改变成员变量值的方法的synchronized属性。

尽管Oracle推荐使用不可变对象存储数据,但是显而易见的是,这会产生大量的无用对象,从而加重垃圾回收的负担。