派大星的博客

很多事情不是会了才能做,而是做了才能学会


  • 首页

  • 标签

  • 分类

  • 关于

  • 搜索

git高级使用

发表于 2019-09-12 | 分类于 工具使用,git

此篇是为了我以后回顾而写的,所以写的有点简单,也有点乱,如果想系统的学习,请去这个网站:https://learngitbranching.js.org

此网站常用命令

1
2
3
4
5
6
# 回到关卡选择页面
levels
# 查看答案
show solution
# 重新开始
level advance3

1. rebase

  • 合并分支
    我在bugFix分支来rebase master分支,那么我这个bugFix 分支就是基于master分支的一个新的节点

    1
    2
    3
    4
    # 切换到bugFix分支
    git checkout bugFix
    # 让bugFix分支融合master分支的内容
    git rebase master
  • 合并提交

    1
    2
    # 合并这次与上次提交
    git rebase -i HEAD~2
  • 解决远程仓库fast-forward
    当我们提交代码时,可能别人已经提交过内容到远程仓库了,这时我们提交代码时就会提醒我们fast-forward,让我们先更新下代码再提交,我们可以用rebase很快的解决这个问题。

    1
    2
    3
    4
    # 先拉取最新代码进行rebase
    git pull --rebase origin master
    # 然后再提交
    git push
  • 本地分支与远程分支关联
    将本地master分支与远程master分支关联,这样可以在master分支中直接执行git pull进行拉取代码,不用再指定后面的分支

    1
    git branch --set-upstream-to=origin/master  master

2. merge

我在master分支来merge bugFix分支,那么我这个master分支就是在master分支的基础上再次融合bugFix分支的内容。

1
2
3
4
# 切换到master分支
git checkout master
# 融合bugFix分支的内容
git merge bugFix

3. checkout

  • 移动当前分支
    也可以理解为回滚上一次提交,放弃本次提交的修改,c2是通过git log进行查看的 commit id

    1
    git checkout c2
  • 移动某个分支

    移动提交记录。也可以理解为回滚,回滚到上一次提交,移动分支到某个提交记录处,

    1
    git branch -f bugFix c2

也可以直接通过HEAD^来指向上一个提交记录,或通过HEAD~3 往上移动3级

1
2
git branch -f bugFix HEAD^
git branch -f bugFix HEAD~2

4. reset

回退到上一次提交的版本,

1
2
3
4
# 回到此分支的上一个提交
git reset HEAD^
# 回到master分支的上一个提交
git reset master^

如果是远程也想要回退到上一个版本,可以使用

1
git revert HEAD^

如果想撤销远程分支上的内容需要使用git revert,它会新创建一个提交,而新创建的提交的状态正好等于你上一个版本的状态,假如我们现在的版本是c2,它上一个版本就是c1,那么执行完这个命令之后,就会新创建一个提交 为 c1’,它与c1的内容一致,我们将这它推送到远程端,别人更新之后就可以了

1
git revert HEAD^

5. cherry-pick

将其他提交,抓过来,放到此分支下面, c2,c2,c7是git log中的commit id

1
2
3
4
5
# 切换到master分支
git checkout master
# 将其他分支的提交,拿过来,放到master上,特别注意,这几个记录的顺序问题
git cherry-pick c2 c4 c7
# 结果: HEAD——> c7——> c4——> c2

6. tag

也就是做个锚点,因为分支是很容易被改变,为了防止以后不能返回,所以可以打个tag,做个回滚记录点

1
2
# c1 为提交记录的id
git tag tag名 c1

MySQL中JSON类型使用

发表于 2019-09-12 | 分类于 数据库

@[toc]

1. 结构

1.1 表结构

1
2
3
4
5
6
7
CREATE TABLE test
(
id int(10)NOT NULL AUTO_INCREMENT,
content JSON default null,
arrs JSON default null,
PRIMARY KEY (id)
);

1.2 content 结构

1
2
3
4
type content struct {
name string
age int
}

1.3 arrs 结构

1
var arrs []int

2. 插入

2.1 字符串插入

1
INSERT INTO test('id','content', 'arrs') VALUES (1,'{"name": "pibigstar","age": 20}', '[1,2,3]' )

2.2 JSON函数插入

1
INSERT INTO test('id','content', 'arrs') VALUES (1, JSON_OBJECT("name","pibigstar","age",20), JSON_ARRAY(1,2,3))

3. 查询

查询JSON中的数据用 column->path的形式,其中对象类型path的表示方式 .path

3.1 查询内容

1
SELECT id,content->'$.name' AS name, content->'$.age' AS age, arrs->'$[0]' AS arr1,arrs->'$[1]' AS arr2 FROM test;

当JSON里面的字段为string时,使用上面的方式查出来内容的带 “”,可使用 ->> 方式去掉 “”

1
SELECT id,content->>'$.name' AS name FROM test;

3.2 搜索条件

3.2.1 全匹配

1
SELECT * FROM test WHERE content = CAST('{"name": "pibigstar","age": 20}' AS JSON);

3.2.2 JSON某字段匹配

1
2

SELECT * FROM test WHERE content->'$.name' = 'pibigstar';

忽略类型

使用 ->>的方式会忽略其类型

1
2
3
4
5
# 查不到
SELECT * FROM test WHERE category->'$.age' = '20'

# 能查到
SELECT * FROM test WHERE category->>'$.age' = '20'

3.2.2 使用JSON函数

1
SELECT * FROM test WHERE JSON_CONTAINS(content,'20','$.age');

4. 更新

4.1 全量更新

1
2
3
UPDATE test
SET content = JSON_OBJECT("name","haimian","age",22)
WHERE id = 1;

4.2 插入新值(不覆盖已存在值)

1
2
3
UPDATE test
SET content = JSON_INSERT(content, '$.name', 'haimian', '$.sex', '男')
WHERE id = 1;

执行完之后,name值还是 pibigstar,但会新增加一个 sex字段

4.3 插入新值,并覆盖已存在的值

1
2
3
UPDATE test
SET content = JSON_SET(content, '$.name', 'haimian', '$.age', 22, '$.sex', '男')
WHERE id = 1

执行完之后,name会改变,但会新增加一个 sex字段

4.4 替换某字段值

1
2
3
UPDATE test
SET content = JSON_REPLACE(content, '$.name', 'haimian')
WHERE id = 1

将name从原先的 pibigstar 改为 haimian,它只会替换已存在的字段的值

4.5 删除某字段的值

1
2
3
UPDATE test
SET content = JSON_REMOVE(content, '$.name', '$.age')
WHERE id = 1

删除 name 和 age 字段

浅谈Java中的内存区域划分

发表于 2019-09-12 | 分类于 Java

1. java中内存区域的划分

上节谈了Java中的垃圾回收机制,今天我们聊聊Java中内存区域的划分。
总得来说Java中内存分为四块:栈、堆、数据域、代码域

1. 栈

栈中主要存放基本类型的数据和对象的引用也就是存放变量。

Java虚拟机会为每一个方法申请一个栈空间,在这个方法中声明的变量都是放到此栈中的,他们会随此方法的调用结束而回收掉。

如果存放的是基本类型数据(普通变量非静态变量),则直接将变量名和值存入栈中的内存中;

如果是引用类型,则将变量名存入栈,然后指向它new出的对象(存放在堆中)。

2. 堆

简单来说就是存放通过关键字new创造出来的对象

3. 数据域

数据域分为两块:静态域和常量池

1.静态域

存放被关键字static修饰的变量也就是静态变量
如果该静态变量是基本类型则将变量名和值存入静态域,如果是引用类型则指向new出的对象。

2.常量池
通俗来讲就是存放那些被final修饰的变量的值

常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等)和对象型(如String及数组)的常量值还包含一些以文本形式出现的符号引用,比如:类和接口的全限定名;字段的名称和描述符;方法和名称和描述符。

4. 代码域

就是放代码的区域

2. 用图来表示

例1 普通变量和静态变量的创建

代码:

1
2
String str = "hello";  
static int a = 1;


这里的str是非静态变量所以将其放入到栈中,而静态变量a则需要放入静态域中,对于变量值”abc”和10则都应该放入到常量池当中

例2 对象的创建

代码:

1
String str=new String("hello");

这里的str是String类型的对象,所以放入栈中,而new出来的东西则放入到堆中,对于初始值”hello”则放入到常量池中。

例3 数组的创建

代码:

1
2
int s[] = new int[3];
s[0]=1;s[1]=2;s[2]=3;

这里的s[]是一个数组变量,所以放入到栈中,new出来的东西还是放入到堆中,最后的每个元素的值则放入到常量池当中

面试总结---数据库部分

发表于 2019-09-06 | 分类于 面试

[TOC]

1. 数据库中一些名词的理解

1.1 事务

是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

1.1.1 事务的4个特性

  • 原子性(Atomic):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。

  • 一致性(Consistency):事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。

  • 隔离性(Isolation):由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,到底是另一个事务执行之前的状态还是中间某个状态,相互之间存在什么影响,是可以通过隔离级别的设置来控制的。

  • 持久性(Durability):事务结束后,事务处理的结果必须能够得到固化,即写入数据库文件中即使机器宕机数据也不会丢失,它对于系统的影响是永久性的。

1.1.2 事务并发控制

我们从另外一个方向来说说,如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形,有些使我们可以接受的,有些是不能接受的,注意这里的异常就是特定语境下的,并不一定就是错误什么的。假设有一个order表,有个字段叫count,作为计数用,当前值为100

  • 第一类丢失更新(Update Lost):此种更新丢失是因为回滚的原因,所以也叫回滚丢失。此时两个事务同时更新count,两个事务都读取到100,事务一更新成功并提交,count=100+1=101,事务二出于某种原因更新失败了,然后回滚,事务二就把count还原为它一开始读到的100,此时事务一的更新就这样丢失了。

  • 脏读(Dirty Read):此种异常时因为一个事务读取了另一个事务修改了但是未提交的数据。举个例子,事务一更新了count=101,但是没有提交,事务二此时读取count,值为101而不是100,然后事务一出于某种原因回滚了,然后第二个事务读取的这个值就是噩梦的开始。

  • 不可重复读(Not Repeatable Read):此种异常是一个事务对同一行数据执行了两次或更多次查询,但是却得到了不同的结果,也就是在一个事务里面你不能重复(即多次)读取一行数据,如果你这么做了,不能保证每次读取的结果是一样的,有可能一样有可能不一样。造成这个结果是在两次查询之间有别的事务对该行数据做了更新操作。举个例子,事务一先查询了count,值为100,此时事务二更新了count=101,事务一再次读取count,值就会变成101,两次读取结果不一样。

  • 第二类丢失更新(Second Update Lost):此种更新丢失是因为更新被其他事务给覆盖了,也可以叫覆盖丢失。举个例子,两个事务同时更新count,都读取100这个初始值,事务一先更新成功并提交,count=100+1=101,事务二后更新成功并提交,count=100+1=101,由于事务二count还是从100开始增加,事务一的更新就这样丢失了。

  • 幻读(Phantom Read):幻读和不可重复读有点像,只是针对的不是数据的值而是数据的数量。此种异常是一个事务在两次查询的过程中数据的数量不同,让人以为发生幻觉,幻读大概就是这么得来的吧。举个例子,事务一查询order表有多少条记录,事务二新增了一条记录,然后事务一查了一下order表有多少记录,发现和第一次不一样,这就是幻读。

1.2 索引

索引好比字典的目录,让你按照一定的规则更快的找到目标数据

为什么需要索引?数据在磁盘上是以块的形式存储的。为确保对磁盘操作的原子性,访问数据的时候会一并访问所有数据块。磁盘上的这些数据块与链表类似,即它们都包含一个数据段和一个指针,指针指向下一个节点(数据块)的内存地址,而且它们都不需要连续存储(即逻辑上相邻的数据块在物理上可以相隔很远)。

举个例子
我们有一个数据表User.为了简便,这个表没有主键。
Identity | Name | Age | Grade
——–|——-|——|——
1|Robin|28|90
5|Lilei|26|60|
3|Hanmei|25|50|
4|Lucy|27|66|
2|Lily|29|80|

虽然这些数据都存在于一个User表中,但是物理上,这些数据可能存储在分散的数据块中。
查找Lily这个人的信息, 已知Lily的Identity为2, select * fromUser where Identity= 2.

在查找的时候,首先找到这个表的第一条记录所在的数据库地址,然后发现Identity为1,并不是所需要的值,然后在这个数据库的底端,找到了下一个数据块的地址。(这个类似于链表),如此一来,查询了5次才找到了所需要的值。(为了简单起见,我们考虑Identity不能有重复值)

为了加快搜索速度,这里就出现了索引。索引是对某个字段进行排序的一种方式。对表中的某个字段建立索引会创建另一种数据结构,其中保存着字段的值,每个值又指向与它相关的记录。这种索引的数据结构是经过排序的,因而可以对其执行二分查找。

1
2
3
4
/**创建索引*/
create index 索引名 on 表名(列名)
/**删除索引*/
drop index 索引名

2. 数据库三范式

  • 第一范式(1NF)

字段具有原子性,不可再分。

所有关系型数据库系统都满足第一范式)数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必须作为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两个独立的字段。

  • 第二范式(2NF)

要有主键,要求其他字段都依赖于主键。

要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。

  • 第三范式(3NF)

各种信息只在一个地方存储,不出现在多张表中。

满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

所以第三范式具有如下特征:

  1. 每一列只有一个值

  2. 每一行都能区分。

  3. 每一个表都不包含其他表已经包含的非主关键字信息。

3. 表连接

3.1 JOIN和UNION的区别

  • join 是两张表做交连后里面条件相同的部分记录产生一个记录集,
  • union是产生的两个记录集(字段要一样的)并在一起,成为一个新的记录集。

    3.2 JOIN联接

JOIN用于按照ON条件联接两个表,主要有四种:

  • 内联接( inner join)

内部联接两个表中的记录,仅当至少有一个同属于两表的行符合联接条件时,内联接才返回行。我理解的是只要记录不符合ON条件,就不会显示在结果集内。

SQL写法:

1
2
3
SELECT msp.name, party.name FROM msp inner JOIN party ON party=code
/**或者*/
SELECT msp.name, party.name FROM msp JOIN party ON party=code
  • 左联接(LEFT JOIN / LEFT OUTER JOIN)

外部联接两个表中的记录,并包含左表中的全部记录。如果左表的某记录在右表中没有匹配记录,则在相关联的结果集中右表的所有选择列表列均为空值。理解为即使不符合ON条件,左表中的记录也全部显示出来,且结果集中该类记录的右表字段为空值。

SQL写法:

1
2
SELECT msp.name, party.name 
FROM msp LEFT JOIN party ON party=code
  • 右联接(RIGHT JOIN / RIGHT OUTER JOIN)

外部联接两个表中的记录,并包含右表中的全部记录。简单说就是和LEFTJOIN反过来。

SQL写法:

1
2
SELECT msp.name, party.name 
FROM msp RIGHT JOIN party ON msp.party=party.code
  • 全联接(FULL JOIN / FULL OUTER JOIN)

完整外部联接返回左表和右表中的所有行。就是LEFTJOIN和RIGHTJOIN和合并,左右两表的数据都全部显示。

SQL写法:

1
2
SELECT msp.name, party.name
FROM msp FULL JOIN party ON msp.party=party.code

3.3 UNION联接

将两个或更多查询的结果集组合为单个结果集,该结果集包含联合查询中的所有查询的全部行。UNION的结果集列名与UNION运算符中第一个Select语句的结果集的列名相同。另一个Select语句的结果集列名将被忽略。

UNION 与 UNION ALL 的区别:

UNION 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录.

  • union 检查重复
  • union all 不做检查

SQL写法:

1
2
/**table1和table2的列名一定要相同*/
SELECT * FROM Table1 UNION SELECT * FROM Table2

4.Group by 的使用

语法:select 列a,聚合函数 from 表名 where 过滤条件 group by 列a having 过滤条件

4.1 概念与使用

对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理

注意:group by 是先排序后分组

一般要使用聚集函数时,group by也会使用
如果要用到group by 一般用到的就是“每” 这个字,例如:每个部门有多少人, 就要用到分组的技术,语句如下:

1
select DepartmentID,COUNT(*) from Department group by DepartmentID

4.2 聚集函数

  • SUM 求和
  • MAX 求最大值
  • MIN 求最小值
  • AVG 求平均值

4.3 having的使用

having子句限制的是组,而不是行。where子句中不能使用聚集函数,而having子句中可以。

需要注意having和where的用法区别:

  1. having只能用在group by之后,对分组后的结果进行筛选(即使用having的前提条件是分组)。

  2. where肯定在group by 之前

  3. where后的条件表达式里不允许使用聚合函数,而having可以。

举个例子:
查询每一个班级中年龄大于20,性别为男的人数

1
2
select classid,COUNT(*) from table where sex='男'
group by classid,age having age>20

① 先根据where sex = ‘男’ 拿到所有的男生
② 再根据group by classid,age 将所有的男生根据班级id和年龄进行分组
③ 再通过having age>20 剔除年龄段小于20 的分组
④ 最后通过select count(*),classid 拿到每个班级的人数

5. SQL分页技术

  • mysql

    1
    2
    3
    /**pageSize:每页显示多少数据,pageNumber:当前是第几页 */
    select * from students order by id
    limit pageSize*(pageNumber-1),pageSize
  • sql Server

    1
    2
    3
    "select top" + pageSize + " * from students 
    where id not in" +"(select top "+ pageSize * (pageNumber-1)
    + " id from students order by id)" +"order by id
  • oracle

    1
    2
    3
    4
    String sql ="select * from " 
    +(select *,rownum rid from (select * from students order by postime desc)
    where rid<=" + pagesize*pagenumber +") as t"
    +"where t>" +pageSize*(pageNumber-1);

6. ORM与 JDBC的关系

orm 是一种思想,就是把object 转变成数据库中的记录,或者把数据库中的记录转变成objecdt,我们可以用jdbc 来实现这种思想,
用的较多的orm 工具是hibernate、Mybatis、toplink

使用Java做ORC图片识别

发表于 2019-09-04 | 分类于 java工具类

1. 下载训练库

下载地址:https://github.com/tesseract-ocr/tessdata

不用全部下载,中文识别下载那个chi_sim.traineddata即可。

2. 添加依赖

1
2
3
4
5
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.3.1</version>
</dependency>

3. 编写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static String getTextByImage(String imgPath) throws TesseractException {
File imageFile = new File(imgPath);
if (!imageFile.exists()){
throw new RuntimeException("图片不存在");
}
Tesseract tesseract = new Tesseract();
// 设置训练库的位置,https://github.com/tesseract-ocr/tessdata
tesseract.setDatapath("D://OCR/tessdata");
// 设置识别语言为中文
tesseract.setLanguage("chi_sim");

String result = tesseract.doOCR(imageFile);
return result;
}

4. 测试

1
2
3
public static void main(String[] args) throws TesseractException {
System.out.println(getTextByImage("D://OCR/img/test.png"));
}

Linux随笔记

发表于 2019-09-04 | 分类于 Linux

@[toc]

后台执行任务

  1. 开启任务

    1
    nohup 命令 > temp.log &
  2. 查看正在运行的任务

    1
    jobs -l

查找文件

从 根目录/ 开始查询

1
find / -name "my.ini"

Fork炸弹

请不要轻易执行,会耗尽服务器资源,使服务器不能正常的对外提供服务

1
:(){:|:&};:

根据名称停止所有相关进程

杀死进程中所有进程名中有 kube关键字的进程

1
pkill -9 kube

漂亮的进程监控

  1. 安装htop

    1
    yum install -y htop
  2. 查看进程

    1
    htop
  3. 效果

SpringBoot使用redis做缓存机制

发表于 2019-09-04 | 分类于 springboot,SpringBoot技能大全

SpringBoot 2.0.3 版本、redis3.2版本

1. 加入jar包

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

2. 编写RedisConfig类

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
package com.pibigstar.common.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;


@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

//缓存管理器
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).build();
return cacheManager;
}
//自定义缓存key生成策略
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator(){
@Override
public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for(Object obj:params){
sb.append(obj.toString());
}
System.out.println("调用Redis生成key:"+sb.toString());
return sb.toString();
}
};
}
}

2.1 配置application.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
redis:
host: 127.0.0.1
port: 6379
database: 0 # 设置数据库索引为0 默认为0
password: # 密码为空
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 2 # 连接池中的最小空闲连接
timeout: 2000 # 连接超时时间(毫秒)

3. 在 适当的地方加入缓存

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
package com.pibigstar.service.impl;

import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.pibigstar.dao.GradeMapper;
import com.pibigstar.domain.Grade;
import com.pibigstar.service.GradeService;

@Service
@CacheConfig(cacheNames="grades")
public class GradeServiceImpl implements GradeService{

@Autowired
private GradeMapper gradeMapper;

@Override
@Cacheable //开启缓存
public Grade getOneById(Long id) {
return gradeMapper.selectByPrimaryKey(id);
}

@Override
@Cacheable //开启缓存
public List<Grade> list() {
return gradeMapper.findAll();
}
}
  • @Cacheable将查询结果缓存到redis中,(key=”#p0”)指定传入的第一个参数作为redis的key。
  • @CachePut,指定key,将更新的结果同步到redis中
  • @CacheEvict,指定key,删除缓存数据,allEntries=true,方法调用后将立即清除缓存

4. 启动

4.1 启动redis

下载: https://pan.baidu.com/s/1tTYcCRUF-qDikhPTkSiJTQ

解压,双击 start.bat 即可

RedisDesktopManager 文件夹放的是redis 可视化工具

4.2 启动项目

调用 开启缓存的那两个方法,就可以看到控制台输出了:

通过redis 可视化工具可以看到:

已经有key值生成了,

当再一次查询的时候就不会去从数据库中查询了,而是直接从我们的redis中查询,速度会非常快。

需要注意的是:当数据库中值改变了,因为它查询的是从缓存中查询,所以查出来的数据还是之前的数据,只有当key过期之后或者被删除之后才能查到最新的值

5. 常用redis命令

  • flushdb:清空当前数据库。
  • select [index]:选择索引数据库,index为索引值名,如:select 1。
  • keys *:查看数据库内所有的key。
  • del [key]:删除一条指定key的值。
  • get [key] : 获得 指定key的值
  • flushall:清空所有数据库。
  • quit:退出客户端连接

关注我的公众号,获取最新Java干货

欢迎关注我的公众号

js特效

发表于 2019-08-30 | 分类于 前端

鼠标点击产生红心特效

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
! function (e, t, a) {
function n() {
c(
".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
), o(), r()
}

function r() {
for (var e = 0; e < d.length; e++) d[e].alpha <= 0 ? (t.body.removeChild(d[e].el), d.splice(e, 1)) : (d[e].y--,
d[e].scale += .004, d[e].alpha -= .013, d[e].el.style.cssText = "left:" + d[e].x + "px;top:" + d[e].y +
"px;opacity:" + d[e].alpha + ";transform:scale(" + d[e].scale + "," + d[e].scale +
") rotate(45deg);background:" + d[e].color + ";z-index:99999");
requestAnimationFrame(r)
}

function o() {
var t = "function" == typeof e.onclick && e.onclick;
e.onclick = function (e) {
t && t(), i(e)
}
}

function i(e) {
var a = t.createElement("div");
a.className = "heart", d.push({
el: a,
x: e.clientX - 5,
y: e.clientY - 5,
scale: 1,
alpha: 1,
color: s()
}), t.body.appendChild(a)
}

function c(e) {
var a = t.createElement("style");
a.type = "text/css";
try {
a.appendChild(t.createTextNode(e))
} catch (t) {
a.styleSheet.cssText = e
}
t.getElementsByTagName("head")[0].appendChild(a)
}

function s() {
return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + ")"
}
var d = [];
e.requestAnimationFrame = function () {
return e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.oRequestAnimationFrame ||
e.msRequestAnimationFrame || function (e) {
setTimeout(e, 1e3 / 60)
}
}(), n()
}(window, document);

常用Shell方法集合

发表于 2019-08-29 | 分类于 shell

判断是否是root用户

1
2
3
4
5
6
7
8
9
10
check_root() {
local user=""
user="$(id -un 2>/dev/null || true)"
if [ "$user" != "root" ]; then
cat >&2 <<-'EOF'
权限错误, 请使用 root 用户运行此脚本!
EOF
exit 1
fi
}

判断命令是否存在

1
2
3
4
5
6
7
8
9
10
command_exists() {
command -v "$@" >/dev/null 2>&1
}
if command_exists ip;then
echo "存在ip命令"
elif command_exists ifconfig; then
echo "存在ifconfig命令"
else
echo "都不存在"
fi

判断参数是否为数字

1
2
3
4
5
6
7
8
9
is_number() {
expr "$1" + 1 >/dev/null 2>&1
}
if ! ( is_number "$1" ); then
cat >&2 <<-EOF
请输入数字
EOF
exit 1
fi

获取服务器IP地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
get_server_ip() {
local server_ip=""
local interface_info=""

if command_exists ip; then
interface_info="$(ip addr)"
elif command_exists ifconfig; then
interface_info="$(ifconfig)"
fi

server_ip=$(echo "$interface_info" | \
grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" | \
grep -vE "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | \
head -n 1)

# 自动获取失败时,通过网站提供的 API 获取外网地址
if [ -z "$server_ip" ]; then
server_ip="$(wget -qO- --no-check-certificate https://ipv4.icanhazip.com)"
fi

echo "$server_ip"
}

下载文件,重试3次

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
download_file() {
# 文件下载链接
local url="$1"
# 文件下载后存放路径
local file="$2"
local retry=0

download_file_to_path() {
if [ $retry -ge 3 ]; then
rm -f "$file"
cat >&2 <<-EOF
文件下载失败! 请重试。
URL: ${url}
EOF
fi

( set -x; wget -O "$file" --no-check-certificate "$url" )
if [ "$?" != "0" ] || [ -n "$verify_cmd" ] && ! verify_file; then
retry=$(expr $retry + 1)
download_file_to_path
fi
}
download_file_to_path
}

# 使用
DOCKERFILE_DOWNLOAD_URL="https://github.com/pibigstar/go-todo/blob/master/Dockerfile"
download_file "$DOCKERFILE_DOWNLOAD_URL" "/usr/local/todo"

Linux防火墙操作

发表于 2019-08-29 | 分类于 Linux

1. 查看防火墙状态

1
sudo firewall-cmd --state

如果是运行中则会输出 running,如果没有运行则会输出 not running

2. 关闭防火墙

1
2
3
4
# 关闭
systemctl stop firewalld
# 关闭开机自启
systemctl disable firewalld

3. 开启防火墙

1
systemctl start firewalld

4. 添加端口白名单

将 5901-5905端口添加到白名单中

1
sudo firewall-cmd --permanent --zone=public --add-port=5901-5905/tcp

5. 重新加载

1
sudo firewall-cmd --reload

6. 查看白名单端口列表

1
sudo firewall-cmd --list-all-zones
123…14
派大星

派大星

137 日志
64 分类
230 标签
GitHub CSDN
© 2019 派大星