0%

    本文首发于cartoon的博客

    转载请注明出处:https://cartoonyu.github.io/cartoon-blog/post/assorted/4种极大提升学习效率的工具

  近段时间发现身边很多人都在用TUDO List,但是我觉得TUDO List的效率还是不够高,所以就写一下提升学习效率的工具。

TUDO List

​ 因为这阵子真的很多东西做,持续的时间比较长。而且会有时候(大概率)忘掉做某几件事,所以学习效率偏低,直到遇到了TUDO List。

​ TUDO List,可以理解为一个任务清单,它包含了你一天所有要做的事情,而且过一段时间你会发现自己已经依赖上TUDO List管理你的日程。

​ 市面上TUDO List的APP很多,有小黄条,TickTick,Mircosoft To-Do,Google Keep(好像是叫这个名字),还有很多很多,但是我还是喜欢TickTick。

​ 下面是我TickTick的收集箱。

(嗯,我知道我还有很多要做)

​ 我觉得TickTick比其他TUDO List好的主要有三点

  • 几乎全平台的支持
    • 安卓端是离线app加上联网更新形式,断网都可以继续用
    • 桌面端通过chrome插件提供服务
    • 苹果家的设备就不清楚了(穷)
  • 在界面舒适度与易用性取得平衡
    • 小黄条的界面,我就是看了一眼简介的截图就没有下载的欲望
    • Mircosoft家的,我不知道界面怎么样,但是我体验过小娜,我觉得不会好用
    • Google家的,好的,根本不能正常用
  • 自带番茄时钟
    • 我觉得现代人都摆脱不了手机(包括我),想认真看书的时候总是想看手机。所以番茄时钟能有效监督学习
    • 自带统计视图,能随时看到当周完成的情况

​ 有利也有弊,弊是有些功能需要付费使用,一个月10来块。始终还是要恰饭的嘛,能理解能理解。付费功能包括TUDO Task的统计,番茄时钟的统计建议。

​ 我对免费的功能已经满足了,所以我不是付费用户,付费解锁功能戳不到我的需求点。

思维导图

​ 不知道有多少读者是在做纸质笔记的,我的话已经很久没有做纸质笔记了。那么平常我在看书的时候,是怎么做笔记的呢。

​ 思维导图,我第一次接触已经爱上它了。

​ 下面是我学习帅张的git相关书籍做的思维导图,虽然过了三个月了,但是我还是可以根据思维导图讲出原书的大概内容。

​ 因为我是比较怕写字的(包括打字),所以我现在只会用思维导图做笔记了。

​ 市面上思维导图的软件很多,有XMind(开源,全平台支持),百度脑图(只有web端),MindMaster(苹果专属),MindLine(国人开发,支持云同步)等等。

​ 我说说我在用的XMind吧,优点有很多

  • 模板简洁而且漂亮。即使免费版也内置很多模板,ZEN版本跟Pro版本会更多
  • 操作简单。桌面端新建子分支或者兄弟分支会使用到快捷键(我比较少用,但是上手了非常方便),移动端(我常用)主要操作底下四颗按钮完成日常功能
  • 支持导出多格式。免费版只支持导出图片以及pdf,PRO版支持更多,但是我觉得这方面日常使用免费版已经足够了。

​ 下面到缺点的部分了。

​ 其实在我看来缺点只有一个,就是不支持云同步,确实有点反人类。

​ 我记得上次我双清平板忘记备份思维导图了(因为平板上独占数据只有思维导图),结果除了之前上传到OneDrive的几个之外,全都没了。。。大概10个上面图片的规模的思维导图吧。。。。

​ 我断断续续找了一个月,找到一个MindLine符合我使用场景之余是支持云同步的,但是界面说实话还有待改进,所以我只能继续用XMind。

Markdown

​ 如果不习惯用思维导图但是又想摆脱纸张的限制,我也可以提供选择。

​ 可能有人已经注意到,这篇文章的风格有点怪怪的。确实,是有点朴素(打死都不承认是怪怪的),因为我是用markdown去写的,具体原因看第二条推文。

​ 效果不截图了,整篇文章都是效果,或者可以去我的博客逛一下,有时间我也会写搭建博客的教程放在博客上。

​ 首先先说一下,markdown是一种标记语言,不是什么软件。具体介绍可以点击查看

​ 在我看来,markdown浑身都是优点

  • 操作简单。只需要掌握特定语法就可以写出比word整洁很多的文章,而且可以完全摆脱鼠标(纯文字文章的话)

  • 花样很多。markdown原生支持html语言,就是如果你懂html,可以像写网页那样写文章

  • 可选编辑器很多。微软家的VSCode,GitHub家的Sublime(实际上也是微软家的),Typora(我在用的,支持实时渲染),有道云笔记,印象笔记等等

  • 将主要精力放在思考上。整体风格更加符合思考的习惯,而且摆脱了鼠标的使用,可以将主要精力放在思考上。

    缺点嘛,也有两个,但是都是面对新手的。

  • 上手复杂。因为需要特定语法,所以上手需要一个阵痛期,但是practice makes prefect。习惯了之后效率会飞涨。我觉得这个教程不错

  • 插入图片比较麻烦,markdown支持三种图片插入方式

    • (不推荐)插入相对目录下的图片,但是需要确保路径的正确
    • (还行,但是不推荐)插入转码后的图片。这个比较麻烦,首先需要将图片转换成Base64字符串,再将字符串复制到markdown底部(转码后的字符串会很长),再利用语法引用。
    • (推荐)引用图床图片。图床这个不解释了,可以将它理解为一个网络的图片仓库。图床主要有三种
      • 免费的公有图床。百度一搜会很多。不推荐,容易出现图片丢失
      • 免费的私人图床。我所知道的只有微博图床,但是操作上有点麻烦,还行,但是不推荐。
      • 收费的私人图床。简单来说就是自己用OSS搭一个图床,本地上传到云端OSS。七牛云(一定容量免费),阿里云(我在用),腾讯云。七牛云就算了,需要拍身份证。个人推荐阿里云(9块/年)。

云盘

​ 可能很多人bb我:云盘谁没有,某度云盘几个T。

​ 是的,某度云盘确实占领了天朝大部分的市场。但是我想说的是,免费的是最贵的。想想某度的广告,想想几十K的下载速度,我不想吐槽了。

​ 云盘为什么能提升效率呢。

​ 我个人需求是

  • 平板是Wifi版的,需要经常带出去,出去的地方大多没有网络或者网络很差
  • 平常数据种类多而且量级比较大,而且需要多设备同步
  • 需要在线或缓存中阅读pdf

​ 我日常使用情况

  • 电脑下载需要看的电子书,直接放在OneDrive文件夹上,Win10自动上传

  • 平板脱机缓存电子书,网络环境不允许时可以随时使用电子书

  • 在平板上做好XMind之后,上传到OneDrive,需要再继续时下载

​ 所以我OneDrive是这样子的。

​ 通过OneDrive,我的数据能随时同步而且不丢失(再次为我丢失的思维导图伤心。。。)

​ 市面上有很多很多云盘。有我们能用到的,也有我们用不到的:OneDrive,某度云盘,亚马逊,iCloud,Google Drive,坚果云等等。

​ 苹果党,iCloud;

​ Win10党,OneDrive(虽然免费空间只有5G,但是好用,我愿意付费);

​ 有特殊手段的安卓党,Google Drive;

​ 数据量大且不常使用,某度还是可以选择一下的;

​ 以上几款软件都是开源或者免费+付费形式的。免费的部分基本上够用了,付费也在承受范围之内(真希望XMind出一个云同步的功能,我绝对付费)。

题外话:

​ 这段时间在混帅张的星球,受到了很多启发。关于软件跟知识是否付费的争论,我是站在付费的那一边。

​ 曾经在星球上面看到一个观点:免费是最贵的。软件都是程序猿一块块砖搬出来的,也是有成本的。免费使用,意味着在某些方面软件开发方是赚钱的,广告,流量,会员等等。

​ 自己本身也是学编程的,明白写程序是很辛苦的。免费产品我是不排斥的,没人嫌钱多。付费产品?我也愿意付费的,前提是有足够理由让我付费以及我能承担起这个费用。

​ 盗版我是不提倡的,但是有时候超出我的承受范围,我会选择某宝。而且盗版可能有一部分功能缺失掉了,恰好缺失的功能能极大提高你的效率。

​ 再次希望以上几款软件能对你们有帮助!

    本文首发于cartoon的博客

    转载请注明出处:https://cartoonyu.github.io/cartoon-blog

当修改gitnore文件后,常常出现文件不生效的情况,是因为之前的修改已经提交到暂存区上了。
解决方法

1
2
3
git add .     //防止已有修改还没到暂存区的情况
git rm -r --cached . //清除暂存区记录
git add . //提交修改记录到暂存区中

执行到第三步即能使gitnore文件生效,后续操作会按照gitnore规则执行

    本文首发于cartoon的博客

    转载请注明出处:https://cartoonyu.github.io/cartoon-blog

今天在做leetcode的时候,遇到了运算符的不同而导致结果不一致的问题。记录一下提醒自己

中文名称与英文名称

&:按位与(Bitwise and)
&&:逻辑与(logical and)
|:按位或(Bitwise or)
||:逻辑或(logical or)

区别

若第一个条件就可以决定表达式的值,逻辑运算符不会继续检查后续条件,而位运算符则会全部检查。

    本文首发于cartoon的博客

    转载请注明出处:https://cartoonyu.github.io/cartoon-blog

    这段时间把疯狂JAVA再看了一遍,发现Stack,ArrayDeque,LinkedList都可以作为栈使用,所以就稍微从性能以及实现的细节对比这三者的区别。

类继承树

区别

底层数据存储方式

  存储方式
Stack 长度为10的数组
ArrayDeque 长度为16的数组
LinkedList 链表

方法参照表

Stack ArrayDeque LinkedList
push(e) addFirst(e)/offerFirst(e) addFirst(e)/offerFirst(e)
pop() removeFirst()/pollFirst() removeFirst()/pollFirst()
peek() getFirst()/peekFirst() getFirst()/peekFirst()

线程安全

  线程安全
Stack 线程同步
ArrayDeque 线程不同步
LinkedList 线程不同步

性能选项

   通常情况下,不推荐使用Vector以及其子类Stack

1.需要线程同步

    使用Collections工具类中synchronizedXxx()将线程不同步的ArrayDeque以及LinkedList转换成线程同步。

2.频繁的插入、删除操作:LinkedList

3.频繁的随机访问操作:ArrayDeque

4.未知的初始数据量:LinkedList

    本文首发于cartoon的博客

    转载请注明出处:https://cartoonyu.github.io/cartoon-blog

    近段时间把自己电脑(win)、虚拟机(Ubuntu)以及阿里云(ubuntu)都重置了一遍,三个地方都有用到JDK,不想之后找教程找的那么麻烦。所以就自己总结一遍,一次性把轮子造好。

  • 环境

    1
    2
    3
    Win10 1803 Home
    Ubuntu 16.04.3
    Ubuntu 18.04.1

        其中服务器与虚拟机配置方法一致,只是目录不同,就归成Ubuntu一类好了。

  • Windows环境下安装

  1. 下载JDK的安装程序

    1
    https://www.oracle.com/technetwork/java/javase/downloads/jdk10-downloads-4416644.html
  2. 按照步骤安装

  3. 配置环境变量

    此电脑–属性–编辑系统设置–环境变量

  • 新建系统变量JAVA_HOME,并在变量值选择Java的安装目录

  • 新建变量CLASSPATH,写入图中的变量值

  • 选择变量Path–编辑文本–在最后追加图中的值

  • 验证安装是否成功

    cmd下输入java -version

    出现图中的输出语句即为成功

  • Ubuntu环境下安装
  1. 下载JDK的压缩包

    1
    https://www.oracle.com/technetwork/java/javase/downloads/jdk10-downloads-4416644.html

        勾选同意协议后选择.tar.gz结尾的选项

  2. 解压到指定文件夹

    1
    tar -zxvf packageName.tar.gz  //packageName为jdk压缩包包名

        在服务器中我是直接通过xftp的GUI进行移动,虚拟机中受限于权限,我在终端上用root打开文件管理器移动的。

  3. 配置环境变量

    • 打开etc目录下的profile或者bashrc

      1
      2
      vim /etc/profile
      vim ~/.bashrc

          vim的安装以及基本命令可以戳此查看

    • 在末尾追加以下信息并保存

      1
      2
      3
      4
      export JAVA_HOME=/root/usr/jdk
      export JRE_HOME=/root/usr/jre
      export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
      export PATH=${JAVA_HOME}/bin:$PATH
    • 刷新配置文件

      1
      2
      source /etc/profile
      source ~/.bashrc
  4. 验证安装是否成功

        终端下输入java -version

前言

近段时间在使用easyopen时,发现定义的请求体与实际参数不符时会出现参数无法正常传递的现象,于是就把easyopen的源码 clone 下来研究了一波。

easyopen 测试版本

1
1.16.6.1

场景复现

  • 请求体定义如下
1
2
3
4
5
6
7
8
9
10
11
12
13
public class GoodsParam {

@ApiDocField(description = "商品名称", required = true, example = "iphoneX", name = "goods")
private String goodsName;

public String getGoodsName() {
return goodsName;
}

public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
}
  • 接口定义如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ApiService
@ApiDoc("商品模块")
public class GoodsApi {

private static final Logger log = LoggerFactory.getLogger(GoodsApi.class);

@Api(name = "goods.get")
@ApiDocMethod(description = "获取商品")
public String getGoods(GoodsParam param) {
log.info("incoming param: {}", JSONObject.toJSONString(param));
return param.getGoodsName();
}

}
上述代码使用[官方示例](https://gitee.com/durcframework/easyopen/tree/master/easyopen-demo/easyopen-server-normal)修改。

因为我是要复现出错的场景,所以我对请求体属性 goodsName 进行修改,并修改原有接口逻辑,使得接口打印请求体数据并直接返回请求体 goodsName 属性。

启动项目,请求接口 [goods.get](http://localhost:8081/api/doc#201),日志与结果截图如下

接口并未如文档定义一般拿到请求体的参数,场景复现。

寻找原因

代码的好处是,0 即是 0,1 就是 1,如果 0 变成 1,那就是你写的 bug 或者你有意为之,这个场景必定有代码作为支撑。

  因为研读源码的经验较浅,所以一开始从框架打印日志入手。

 程序在启动时总会打这几行日志,所以就全局搜索了一波,定位到 src\main\java\com\gitee\easyopen\register\ApiRegister.java 的 doWith 方法中。
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
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
checkTransactionalAnnotation(method);
ReflectionUtils.makeAccessible(method);
Api api = AnnotationUtils.findAnnotation(method, Api.class);
boolean ignoreSign = api.ignoreSign() ? true : this.apiServiceAnno.ignoreSign();
boolean ignoreValidate = api.ignoreValidate() ? true : this.apiServiceAnno.ignoreValidate();
boolean isWrapResult = this.apiServiceAnno.wrapResult() ? api.wrapResult() : false;
ApiDefinition apiDefinition = new ApiDefinition();
//apiDefinition setter....
Parameter[] parameters = method.getParameters();
Class<?> paramClass = null;
if (parameters != null && parameters.length > 0) {
Parameter parameter = parameters[0];
paramClass = parameter.getType();
boolean isNumberOrStringType = FieldUtil.isNumberOrStringType(paramClass);
apiDefinition.setSingleParameter(isNumberOrStringType);
apiDefinition.setMethodArguClass(paramClass);
if (isNumberOrStringType) {
SingleParameterContext.add(handler, method, parameter, api);
}
}
logger.debug("注册接口name={},version={},method={} {}({})", api.name(), api.version(),
method.getReturnType().getName(), method.getName(), paramClass == null ? "" : paramClass.getName());
try {
DefinitionHolder.addApiDefinition(apiDefinition);
apiConfig.getApiRegistEvent().onSuccess(apiDefinition);
} catch (DuplicateApiNameException e) {
logger.error(e.getMessage(), e);
System.exit(0);
}
apiCount++;
}

public static void addApiDefinition(ApiDefinition apiDefinition) throws DuplicateApiNameException {
String key = getKey(apiDefinition);
boolean hasApi = apiDefinitionMap.containsKey(key);
if (hasApi) {
throw new DuplicateApiNameException("重复申明接口,name:" + apiDefinition.getName() + " ,version:"+ apiDefinition.getVersion() + ",method:" + apiDefinition.getMethod().getName());
}
apiDefinitionMap.put(key, apiDefinition);
}
阅读代码发现,这一段代码只负责定义接口的解析并形成一个 String to ApiDefinition 的 Map,并没有请求体参数转换逻辑,所以这不是目的地。

但是这么大段代码只形成一个 Map,这个 Map 必定有其作用。于是寻找调用这个 Map 的 getter 方法,最后定位到 src\main\java\com\gitee\easyopen\register\ApiInvoker.java 的 doInvoke 方法中。
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
protected Object doInvoke(ApiParam param, HttpServletRequest request, HttpServletResponse response) throws Throwable {
ApiDefinition apiDefinition = this.getApiDefinition(param);
ApiContext.setApiMeta(apiDefinition);
if (!apiDefinition.isIgnoreJWT()) {
this.initJwtInfo(request, param);
}
// 方法参数
Object methodArgu = null;
// 返回结果
Object invokeResult = null;
Validator validator = ApiContext.getApiConfig().getValidator();
param.setIgnoreSign(apiDefinition.isIgnoreSign());
param.setIgnoreValidate(apiDefinition.isIgnoreValidate());
// 验证操作,这里有负责验证签名参数
validator.validate(param);
// 业务参数json格式
String busiJsonData = ApiContext.getApiConfig().getDataDecoder().decode(param);
// 业务参数Class
Class<?> arguClass = apiDefinition.getMethodArguClass();
boolean isSingleParameter = apiDefinition.isSingleParameter();
Object singleParamProxy = null;
int interceptorIndex = 0;
try {
// 将参数绑定到业务方法参数上,业务方法参数可以定义的类型:JSONObject,Map<String,Object>,String,业务参数类
if (arguClass != null) {
if(arguClass == JSONObject.class) {
methodArgu = JSON.parseObject(busiJsonData);
} else if(arguClass == Map.class) {
methodArgu = new HashMap<String,Object>(JSON.parseObject(busiJsonData));
} else if(isSingleParameter) {
SingleParameterContext.SingleParameterContextValue value = SingleParameterContext.get(param.fatchName(), param.fatchVersion());
if (value != null) {
JSONObject jsonObj = JSON.parseObject(busiJsonData);
methodArgu = jsonObj.getObject(value.getParamName(), arguClass);
singleParamProxy = jsonObj.toJavaObject(value.getWrapClass());
}
} else {
methodArgu = JSON.parseObject(busiJsonData, arguClass);
}
this.bindUploadFile(methodArgu);
}
// 拦截器
ApiInterceptor[] interceptors = ApiContext.getApiConfig().getInterceptors();
if(interceptors == null) {
interceptors = EMPTY_INTERCEPTOR_ARRAY;
}
//1. 调用preHandle
for (int i = 0; i < interceptors.length; i++) {
ApiInterceptor interceptor = interceptors[i];
if (interceptor.match(apiDefinition) && !interceptor.preHandle(request, response, apiDefinition.getHandler(),methodArgu)) {
//1.1、失败时触发afterCompletion的调用
triggerAfterCompletion(apiDefinition, interceptorIndex, request, response, methodArgu, null,null);
return null;
}
//1.2、记录当前预处理成功的索引
interceptorIndex = i;
}
// 验证业务参数JSR-303
this.validateBizArgu(validator, methodArgu, singleParamProxy);
/* *** 调用业务方法,被@Api标记的方法 ***/
MethodCaller methodCaller = apiDefinition.getMethodCaller();
if (methodCaller != null) {
invokeResult = methodCaller.call(new ApiInvocation(apiDefinition, methodArgu));
} else {
invokeResult = Callers.call(apiDefinition, methodArgu);
}
//3、调用postHandle,业务方法调用后处理(逆序)
for (int i = interceptors.length - 1; i >= 0; i--) {
ApiInterceptor interceptor = interceptors[i];
if(interceptor.match(apiDefinition)) {
interceptor.postHandle(request, response, apiDefinition.getHandler(), methodArgu, invokeResult);
}
}
if(invokeResult == null) {
invokeResult = EMPTY_OBJECT;
}
// 最终返回的对象
Object finalReturn = this.wrapResult(apiDefinition, invokeResult);
setMsg(finalReturn);
//4、触发整个请求处理完毕回调方法afterCompletion
triggerAfterCompletion(apiDefinition, interceptorIndex, request, response, methodArgu, finalReturn, null);
return finalReturn;
} catch (Exception e) {
this.triggerAfterCompletion(apiDefinition, interceptorIndex, request, response, methodArgu, invokeResult, e);
throw e;
}
}
 阅读代码发现,此段代码主要做了四个事情:解析网络请求数据,从  apiDefinitionMap 获取接口对应配置,反射调用对应接口,包装调用接口返回结果并返回。参数解析必定在此段代码中处理!
 
 通过断点 debug 查看数据得知,参数解析集中于以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (arguClass != null) {
if (arguClass == JSONObject.class) {
methodArgu = JSON.parseObject(busiJsonData);
} else if (arguClass == Map.class) {
methodArgu = new HashMap(JSON.parseObject(busiJsonData));
} else if (isSingleParameter) {
SingleParameterContextValue value = SingleParameterContext.get(apiDefinition.getMethod());
if (value != null) {
JSONObject jsonObj = JSON.parseObject(busiJsonData);
methodArgu = jsonObj.getObject(value.getParamName(), arguClass);
singleParamProxy = jsonObj.toJavaObject(value.getWrapClass());
}
} else {
methodArgu = JSON.parseObject(busiJsonData, arguClass);
}

this.bindUploadFile(methodArgu);
}

step into断点得知,easyopen 依赖 fastjson 的序列化机制进行参数的序列化,原因得知:easyopen 使用 fastjson 序列化参数成为参数类获取参数,所以当 @ApiDocField 的属性 name 与参数类对应的属性名不一致时,属性值获取失败。

&nbsp;&nbsp;&nbsp;&nbsp;本文首发于 cartoon的博客
转载请注明出处:https://cartoonyu.github.io/cartoon-blog/post/source-code-unscramble/easyopen参数无法正常传递现象解析

&nbsp;&nbsp;&nbsp;&nbsp;本文首发于cartoon的博客

&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:https://cartoonyu.github.io/cartoon-blog

&nbsp;&nbsp;&nbsp;&nbsp;众所周知,Linux与Win之间的区别是Linux需要大量的命令行操作,而有些配置文件也是在命令行中输入的。

&nbsp;&nbsp;&nbsp;&nbsp;这些操作就需要编辑器的帮助了。

&nbsp;&nbsp;&nbsp;&nbsp;我接触Ubuntu的时间不长,碰到过三个编辑器

1
2
3
gedit  //好像是叫这个名字
vi //Linux和Unix上最基本的文本编辑器
vim //比vi更好用的文本编辑器
  • 安装vim

&nbsp;&nbsp;&nbsp;&nbsp;终端内输入

1
sudo apt-get install vim
  • 常用命令
    1
    2
    3
    4
    5
    6
    vim fileName  //vim打开文件,文件需带有绝对路径
    i //编辑文件
    esc //退出编辑状态
    :q //不保存直接退出
    :wq //保存并退出
    ! //覆盖原文件

&nbsp;&nbsp;&nbsp;&nbsp;后三个命令必须与esc配合使用,可以组合使用

&nbsp;&nbsp;&nbsp;&nbsp;本文首发于cartoon的博客

&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:https://cartoonyu.github.io/cartoon-blog

&nbsp;&nbsp;&nbsp;&nbsp;近段时间把自己电脑(win)、虚拟机(Ubuntu)以及阿里云(ubuntu)都重置了一遍,其中本机以及阿里云都有用到MySQL,不想之后找教程找的那么麻烦。所以就自己总结一遍,一次性把轮子造好。

&nbsp;&nbsp;&nbsp;&nbsp;环境

1
2
Win10 1803 Home
Ubuntu 16.04.3

Windows环境下安装

  1. 下载MySQL压缩包
    1
    https://dev.mysql.com/downloads/mysql/
  2. 解压到本地目录,并添加一个配置文件,命名为my.ini,内容如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [mysqld] 
    # 设置为自己MYSQL的安装目录
    # 注意是双斜杆,我就入过坑
    basedir=D:\\MySQL
    # 设置为MYSQL的数据目录
    # 文件夹需手动创建
    datadir=D:\\MySQL\\data
    default-storage-engine=INNODB
    character-set-server=utf8
    [mysql]
    # 设置mysql客户端默认字符集
    default-character-set=utf8
    [client]
    # 设置mysql客户端连接服务端时默认使用的端口
    port=3306
    default-character-set=utf8
  3. 以管理员权限进入MySQL的bin目录
    1
    2
    d: //MySQL的安装目录盘符
    cd MySQL/bin
  4. 安装MySQL服务
    1
    2
    mysqld --install
    //出现Service successfully installed即安装成功
  5. 初始化日志文件
    1
    mysqld --initialize --console
    &nbsp;&nbsp;&nbsp;&nbsp;记住mysql反馈语句中最后一条:a temporary password is….为第八步出现的问题作铺垫。

  1. 配置环境变量
    1
    2
    ;D:\MySQL\bin;
    //分号分隔前属性,bin目录的路径换成自己电脑的路径
  2. 启动服务
    1
    net start mysql
  3. 登录服务器
    1
    mysql -uroot -p
    &nbsp;&nbsp;&nbsp;&nbsp;输入密码提示Access denied for user ‘root‘@’localhost’ (using password: YES)

    &nbsp;&nbsp;&nbsp;&nbsp;解决方法及后续步骤:解决MySQL 8.0登录Access denied for user ‘root‘@’localhost’ (using password: YES)

Ubuntu环境下安装

  1. 打开终端

  2. 输入命令

    1
    2
    3
    sudo apt-get install mysql-server
    sudo apt-get isntall mysql-client
    sudo apt-get install libmysqlclient-dev

    &nbsp;&nbsp;&nbsp;&nbsp;在安装过程中会让你输入密码以及确认密码,不要忘掉,那是mysql的root用户密码

  3. 检查是否安装成功

    1
    sudo netstat -tap | grep mysql

    &nbsp;&nbsp;&nbsp;&nbsp;若出现截图内的语句即说明安装成功

&nbsp;&nbsp;&nbsp;&nbsp;存在的一点点问题

&nbsp;&nbsp;&nbsp;&nbsp;原本我是想在ubuntu下像在win一样通过配置文件进行安装的,但是试了很久都不行最后再次重置了服务器。

&nbsp;&nbsp;&nbsp;&nbsp;如果你们有什么方法是可以的可以在评论告诉我。

&nbsp;&nbsp;&nbsp;&nbsp;本文首发于cartoon的博客

&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:https://cartoonyu.github.io/cartoon-blog

&nbsp;&nbsp;&nbsp;&nbsp;近段时间在ubuntu中搭建jdk并在jdk的基础上建设Oracle数据库,遇到一个问题:常规GUI不能把文件移到usr目录下,提示permission denied。

&nbsp;&nbsp;&nbsp;&nbsp;取了一个巧,利用终端获取管理员权限后移动文件。

&nbsp;&nbsp;&nbsp;&nbsp;方法:终端输入

1
sudo nautilus

&nbsp;&nbsp;&nbsp;&nbsp;然后新创建的窗口默认带有管理员权限,问题就解决了。

&nbsp;&nbsp;&nbsp;&nbsp;本文首发于cartoon的博客

&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:https://cartoonyu.github.io/cartoon-blog

&nbsp;&nbsp;&nbsp;&nbsp;近段时间一直在学java三大框架,遇到了一个问题:eclipse中jsp默认编码格式不是UTF-8,导致页面显示中文出现乱码,每次单独修改过于麻烦。

&nbsp;&nbsp;&nbsp;&nbsp;解决方案:window–Preferences–Web–JSP File–在encoding的下拉列表选择UTF-8。