Eclipse搭建SpringBoot(三)用Mybatis连接MySQL数据库

1.搭建 MySQL 数据库

安装 MySQL 的步骤就不在此赘述了,如果没接触过 MySQL 安装的话,可以参考:

单台windows搭建mysql主从机备份

现在我们已经有了一个可用的数据库,以及 root 的密码(我使用的密码是:root)。

1.1.登录账户

Win + R 输入 cmd 敲回车,打开一个终端,在里面输入:

1
> mysql -uroot -proot

1.2.建立数据库

在终端输入:

1
> create database yun;

因为我之前已经建立过了,所以会显示 ERROR。正常情况下应该显示:

1
Query OK, 1 row affected (0.01 sec)

查询一下,输入:

1
> show databases;

可以看到我们刚才建立的数据库 yun

1.3.建立对应表

有了数据库,我们还需要建立响应的表并插入数据,这样才能够查询。为此我们先简历一张表:

1
2
> use yun;
> CREATE TABLE IF NOT EXISTS user (id INT(11),name VARCHAR(255));

1.4.向表中插入数据

在终端输入:

1
2
> INSERT INTO user (id,name) values(1,"Jackie");
> INSERT INTO user (id,name) values(2,"Nacu");

查询一下表中是否有插入的数据:

1
> SELECT * FROM user;

到了这一步,数据库就搭建完成了。接下来我们来搭建网站。

2.向 SpringBoot 集成 Mybatis

2.1.修改 src/main/java 目录和添加文件

按照下图的修改项目的包名,并添加新的包和类。

2.1.1.YunAppalication.java

YunAppalication.java 所在的包名修改成 com.yun ,并修改其内容如下所示:

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
package com.yun;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yun.service.UserService;
/*
* 控制器使用示例
*/
@SpringBootApplication
@Controller
public class YunApplication {
public static void main(String[] args) {
SpringApplication.run(YunApplication.class, args);
}
/*
* 返回字符串
* 调用示例 : localhost:8080
*/
@ResponseBody
@RequestMapping("/")
public String greeting() {
return "Hello World!";
}
/*
* 不带参数的模版渲染
* 调用示例 : localhost:8080/index
*/
@RequestMapping("/index")
public String index() {
return "index";
}
/*
* 带参数的模版渲染(/风格)
* 调用示例 : localhost:8080/hello/1/jackie
*/
@RequestMapping("/hello/{id}/{name}")
public String hello(@PathVariable("id") String id, @PathVariable("name") String name,Model model) {
model.addAttribute("id", id);
model.addAttribute("name", name);
return "hello";
}
/*
* 带参数的模版渲染(?风格)
* 调用示例 : http://localhost:8080/hello?id=1&name=jackie
*/
@RequestMapping(value = "/hello")
public String hello2(@RequestParam String id, @RequestParam String name, Model model) {
model.addAttribute("id", id);
model.addAttribute("name", name);
return "hello";
}
@Autowired
private UserService userService;
@ResponseBody
@RequestMapping("/database/{id}")
public String hello(@PathVariable("id") Integer id) {
return userService.getById(id).getName();
}
}

2.1.2.User.java

User.java 是一个实体类,一般来说,实体类会被放在 model 包下。如我们的 User.java 就被放到了 com.yun.model 包下,其内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.yun.model;
public class User {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

2.1.3.UserMapper.java

UserMapper.java 是一个 Mapper(用于映射 model 中的实体类与数据库的查询结果)。其一半位于 mapper 包或者 dao 包下,我们就把它放在 com.yun.mapper 包下。其内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.yun.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import com.yun.model.User;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE user.id = #{id}")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name")
})
User getById(@Param("id") Integer id);
}

2.1.4.UserService.java

UserService.java 是一个 Service(主要用于实现业务的逻辑)。一般位于 service 包下,我们将其放在 com.yun.service 包下。其内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.yun.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yun.mapper.UserMapper;
import com.yun.model.User;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getById(Integer id) {
return userMapper.getById(id);
}
}

2.2.修改 application.properties 文件

修改 application.properties 文件的扩展名为 yml注意:这很重要!!!!!! ),并添加如下内容:

1
2
3
4
5
6
spring:
datasource:
url: jdbc:mysql://localhost:3306/yun?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver

2.3.修改 pom.xml 文件

pom.xml 文件添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 使用数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>

完整的 pom.xml 文件的内容如下所示:

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>yun</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>yun</name>
<description>yun demo web</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 使用数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

添加完成之后,Ctrl + S 保存。保存之后 maven 会自动下载相关的依赖,这可能需要一定的时间。

3.运行和测试

右击 YunApplication.java,选择 Run as,然后选择 Java Application

在浏览器输入:

1
localhost:8080/database/1

即可查询数据库中 1 号用户的名字。

当然,你也可以查询 2 号用户。

到了这一步,向 SpringBoot 集成 Mybatis 基本就完成了。

4.参考链接

SpringBoot学习3之数据库集成mybatis

mybatis 官网

如何解决github上传每次都要输入账号密码的问题

1.需要输入账号密码的原因

之所以每次上传都需要输入账号密码,是因为使用了 https 的方式进行 push。只要改成 ssh 的方式就不必输入账号密码了。

2.操作步骤

  1. git remote -v
  2. git remote rm origin
  3. git remote add origin git@github.com:JackSmithThu/MarkdownPhotos.git
  4. git push origin
  5. git push –set-upstream origin master

上面的 jackSmithThuMarkDownPhotos 需要改成你 github用户名项目名( 第5步中,set 前面是两个 “-”,出于 hexo 的原因。直接复制可能无法使用,建议粘贴 git bash 里面的提示)。

3.参考链接

push到github时,每次都要输入用户名和密码的问题

Eclipse搭建SpringBoot(二)控制器Controller

1.新建项目

首先,我们重新创建一个名为 yun 的 SpringBoot 项目,创建完成后项目结构如图所示:

2.修改 YunApplication.java

我们将 YunApplication.java 中的内容按照如下代码修改:

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
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/*
* 控制器使用示例
*/
@SpringBootApplication
@Controller
public class YunApplication {
public static void main(String[] args) {
SpringApplication.run(YunApplication.class, args);
}
/*
* 返回字符串
* 调用示例 : localhost:8080
*/
@ResponseBody
@RequestMapping("/")
public String greeting() {
return "Hello World!";
}
/*
* 不带参数的模版渲染
* 调用示例 : localhost:8080/index
*/
@RequestMapping("/index")
public String index() {
return "index";
}
/*
* 带参数的模版渲染(/风格)
* 调用示例 : localhost:8080/hello/1/jackie
*/
@RequestMapping("/hello/{id}/{name}")
public String hello(@PathVariable("id") String id, @PathVariable("name") String name,Model model) {
model.addAttribute("id", id);
model.addAttribute("name", name);
return "hello";
}
/*
* 带参数的模版渲染(?风格)
* 调用示例 : localhost:8080/hello?id=1$name=jackie
*/
@RequestMapping(value = "/hello")
public String hello2(@RequestParam String id, @RequestParam String name, Model model) {
model.addAttribute("ihttp://localhost:8080/hello?id=1&name=jackied", id);
model.addAttribute("name", name);
return "hello";
}
}

下面进行一些解释:

我们在响应请求时,主要分为两种情况:
  1. 我们想要返回一个字符串(可能是一个 json 串)。
  2. 我们想要返回一个页面。

对于前一种情况,我们可以使用 @ResponseBody 注解使返回的内容为我们想要返回的字符串。对于后一种情况,我们其实返回的是两样东西:

  1. 一个前端页面(我们称之为 templates)。
  2. 该页面所需要的数据(我们称之为 model)。

一个被返回的页面同时包括这两种东西,其中 model 可以直接用如下语句赋值:

1
model.addAttribute("id", id);

model 的每一个属性既可以是一个基本类型,也可以是字符串,列表(List)等。

templates 位于 src/main/resources/templates 下,后面我们会详细介绍。

下面介绍前面使用过的几种注解。

@Controller 注解的类会被当作一个控制器 Controller,专门用来处理不同请求不同的URL,从而有针对性的返回内容。

@RequestMapping 注解是用来处理请求地址映射的注解,可以用在类或方法上,如果用在类上,则表示所有该类中的响应方法都是以该地址作为父路径。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@RequestMapping("/root")
public class YunApplication {
// 调用示例 : http://localhost:8080/root
@RequestMapping("/")
public String hello() {
return " Hello World1!";
}
// 调用示例 : http://localhost:8080/root/hello2
@RequestMapping("/hello2")
public String hello2() {
return "Hello World2!";
}
}

@ResponseBody 注解的类或方法在响应请求时只返回字符串,因此不能返回被渲染的模板。如我们上面提到的:

1
2
3
4
5
@ResponseBody
@RequestMapping("/")
public String greeting() {
return "Hello World!";
}

@RestController 注解整合了 @Controller@ResponseBody。在该类中所有的请求都只会返回字符串。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class YunApplication {
@RequestMapping("/")
public String greeting() {
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

3.修改 pom.xml 文件

为了使我们的应用能够自动地去对应的位置去寻找 templates,我们需要使用thymeleaf模板引擎进行渲染。我们唯一需要做的事就是在 dependencies 标签中添加如下代码:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

添加完成的结果应该是这个样子的:

4.创建模板文件

src/main/resources/templates 文件夹下创建模板文件 index.html,内容如下:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello SomeOne</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p> hello index! </p>
</body>
</html>

再在该文件夹下创建 hello.html,内容如下:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello SomeOne</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello ' + ${name} + ', your id is ' + ${id} + '!'" />
</body>
</html>

从上面的代码中,我们是可以看到模板文件是如何调用 model 中的属性的。

1
${属性名}

5.测试结果

5.1.启动项目

完整的项目结构如下图所示:

右键 Yunapplication.java ,点击Run as,然后选择 Java Application

控制台输出如下所示:

5.2.进行测试

5.2.1.打开浏览器,输入:
1
localhost:8080

输出结果如下所示:

5.2.2.输入:
1
localhost:8080/index

5.2.3.输入:
1
localhost:8080/hello/1/jackie

5.2.4.输入:
1
http://localhost:8080/hello?id=1&name=jackie

Docker入门之(二)Docker的安装与基本操作

1.Docker的安装

1.1.安装 curl 包

按 Ctrl + Alt +T 打开终端,输入:

1
$ sudo su

然后输入密码。

获取超级用户权限之后,输入:

1
2
$ apt-get update
$ apt-get install curl

1.2.用 curl 获取最新的 docker 安装包

在终端输入:

1
curl -sSL https://get.docker.com/ | sh

1.3.检查 docker 是否安装成功

在终端输入:

1
$ docker run hello-world

由于本地没有 hello-world 镜像,docker 会自动从网上下载这个镜像,然后运行。

2.Docker的使用

为了演示 Docker 的使用方法,我们新建一个镜像并在里面安装一个 vim,然后上传到云端。

2.1.账号注册

首先你需要一个 Docker 的账号,登录:https://www.docker.com/

点击上图标红部分,进入账号申请页面:

填写好信息之后点击 【Sign Up】。注意,到这一步注册还没有完全成功,因为它会给你的邮箱发一封验证邮件,在你去邮箱验证该邮件之前账号都是不能使用的。

所以千万不要忘了验证邮件!!!

2.2.登录账号

在终端输入:

1
$ docker login

此时会提示输入账号密码,输入完成后会提示登录成功。

2.3.启动一个容器

在终端输入:

1
$ docker run -t -i ubuntu:16.04

此时会下载 ubuntu 16.04 的镜像并启动。 -i 的意思是以交互模式运行,-t 的意思是打开一个该容器的伪终端。

根据提示我们可以看出,我们已经进入了一个 docker 容器的伪终端。

2.4.安装 vim

在新打开的伪终端输入:

1
$ apt-get update

然后输入:

1
$ apt-get install vim

询问是否继续(Y/n)时,输入 y。

2.5.测试vim

在伪终端输入:

1
$ vim a.txt

建立一个叫做 a.txt 的文件。

打开 vim 程序如图所示:

按下键盘上的 i ,进入插入模式(insert),随便输入一点字符。

然后按下 Esc 进入命令模式,输入:

1
:wq

保存文件并退出。

我们已经建立了一个 a.txt 的文档,接下来输入:

1
$ cat a.txt

查看文档是否存在,以及其内容是否为我们输入的内容。

3.Docker镜像的保存

3.1.提交镜像

在伪终端输入:

1
$ exit

从伪终端退出。

然后输入:

1
$ docker commit f0a jacksmith/demo

其中 f0a 是虚拟机容器序号的前三位,jacksmith 需要改成你自己的用户名,demo 是你给你自己镜像取的名字。

3.2.上传镜像

在终端输入:

1
$ docker push jacksmith demo

3.3.查看镜像是否上传成功

在终端输入:

1
$ docker search jacksmith

可见已经上传已经成功了。

4.重用Docker镜像

Ctrl + Alt +T,打开一个新终端,输入:

1
$ sudo su

输入密码之后,输入:

1
$ docker run -i -t jacksmith/demo

打开伪终端,输入:

1
$ vim a.txt

可以看到这就是我们刚才发布的镜像:

5.参考链接

Docker 命令大全

Docker手册

6.操作系统 Ubuntu 16.04

ActiveMQ入门之(一)ActiveMQ的安装及使用

1.什么是ActiveMQ

与 Kafka 类似,ActiveMQ 也是一种消息队列。与 Kafka 相比,其性能不如 Kafka 强大。那么,为什么要用 ActiveMQ 呢?最重要的原因在于它的易用性。Kafka 虽然强大,但是在使用 Kafka 的过程中需要部署 ZooKeeper。而 ActiveMQ 不需要提前安装依赖,部署简单,与各种语言亲和度高,这给了ActiveMQ 极强的生命力。

2.ActiveMQ的安装与部署

2.1.下载ActiveMQ

下载地址:http://activemq.apache.org/download.html

如上图所示,当前最高的版本是 5.14.5 Release。点击红色方框中的超链接,进入下载页。

因为我们使用的是 Windows 操作系统,因此下载 zip 压缩包即可。

2.2.解压缩

下载好之后,解压到你想要的位置,我的是 D:\WorkSpace 目录。

2.3.启动服务

双击 D:\WorkSpace\ActiveMQ\apache-activemq-5.14.5\bin\win64 目录下的 activemq.bat 文件。

服务启动,如下图所示:

2.4.浏览器登录

在浏览器输入:

http://127.0.0.1:8161/admin/

用户名和密码都是:admin。输入之后,显示如下界面。

这说明 ActiveMQ 已经部署成功了。

3.ActiveMQ的使用(Java为例)

3.1.建立项目

打开 Eclipse,新建一个项目,名为Active。

命名之后,点击 【Finish】即可。

3.2.添加代码

在 src 目录下添加一个叫做 active 的包,并在该包添加两个类,分别名为:JMSProducer 和 JMSConsumer。

JMSPruducer:

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
package active;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息的生产者(发送者)
*/
public class JMSProducer {
//默认连接用户名
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
//默认连接密码
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
//默认连接地址
private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;
//发送的消息数量
private static final int SENDNUM = 10;
public static void main(String[] args) {
//连接工厂
ConnectionFactory connectionFactory;
//连接
Connection connection = null;
//会话 接受或者发送消息的线程
Session session;
//消息的目的地
Destination destination;
//消息生产者
MessageProducer messageProducer;
//实例化连接工厂
connectionFactory = new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL);
try {
//通过连接工厂获取连接
connection = connectionFactory.createConnection();
//启动连接
connection.start();
//创建session
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//创建一个名称为HelloWorld的消息队列
destination = session.createQueue("HelloWorld");
//创建消息生产者
messageProducer = session.createProducer(destination);
//发送消息
sendMessage(session, messageProducer);
session.commit();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
/**
* 发送消息
* @param session
* @param messageProducer 消息生产者
* @throws Exception
*/
public static void sendMessage(Session session,MessageProducer messageProducer) throws Exception{
for (int i = 0; i < JMSProducer.SENDNUM; i++) {
//创建一条文本消息
TextMessage message = session.createTextMessage("ActiveMQ 发送消息" +i);
System.out.println("发送消息:Activemq 发送消息" + i);
//通过消息生产者发出消息
messageProducer.send(message);
}
}
}

JMSConsumer:

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
package active;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/*
* 消息的消费者(接受者)
*/
public class JMSConsumer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;//默认连接用户名
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码
private static final String BROKEURL = ActiveMQConnection.DEFAULT_BROKER_URL;//默认连接地址
public static void main(String[] args) {
ConnectionFactory connectionFactory;//连接工厂
Connection connection = null;//连接
Session session;//会话 接受或者发送消息的线程
Destination destination;//消息的目的地
MessageConsumer messageConsumer;//消息的消费者
//实例化连接工厂
connectionFactory = new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL);
try {
//通过连接工厂获取连接
connection = connectionFactory.createConnection();
//启动连接
connection.start();
//创建session
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建一个连接HelloWorld的消息队列
destination = session.createQueue("HelloWorld");
//创建消息消费者
messageConsumer = session.createConsumer(destination);
while (true) {
TextMessage textMessage = (TextMessage) messageConsumer.receive(100000);
if(textMessage != null){
System.out.println("收到的消息:" + textMessage.getText());
}else {
break;
}
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}

现在代码还不能运行,因为没有引用 AvtiveMQ 的依赖包。

3.3.引入jar包

在项目上右键,然后选择【properties】

然后选择【java Build Path】-> 【Libraries】 -> 【Add Externals JARs】

在刚才加压的压缩包里,有一个 activemq-all-5.14.4.jar 文件,引用进来。

这时项目里就没有 error 了。

3.4.测试

右键 JMSProducer.java,选择【Run as】 -> 【Java Application】

可以看到控制台输出如下消息:

打开浏览器,点击【Queues】,可以看到刚才发送的消息:

右键 JMSConsumer.java,选择【Run as】 -> 【Java Application】,可以看到消费了的消息:

再打开浏览器,刷新,发现这些消息已经出队了:

4.参考链接

深入浅出JMS(一)–JMS基本概念

Docker入门之(一)什么是Docker

1.什么是Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

通俗地说,Docker 是一种虚拟机(广义上的,准确的说法应该是容器)。Docker 与其他虚拟机(如:VMWare,Vitrual Box)的区别在于,Docker是一种高度特化的虚拟机。Docker的效率更高,但是它只能运行与其所运行在的操作系统相同的系统。也就是说,如果你的服务器上安装的是Ubuntu,那么你所有的 Docker 虚拟机都必须是 Ubuntu 系统。

2.什么时候使用Docker

如果你只是想让尽可能多的服务器应用实例在尽可能少的硬件上运行,可能不大关心运行多个操作系统虚拟机。要是同一应用程序的多个副本正是你需要的,那么你会喜欢上容器。

虚拟机管理程序能做容器做不了的一件事就是,使用不同的操作系统或内核。由于所有的容器都需要使用同样的操作系统和内核,因此如果你想仅依靠 Docker 在一台电脑上同时部署 Windows 和 Linux 是一件不可能的事情。不过,这并不影响 Docker 的广泛使用,毕竟 Docker 的效率远高于普通虚拟机,而这意味着更低的成本。

3.Docker到底有多快

docker相对于物理机其计算能力几乎没有损耗,而虚拟机对比物理机则有着非常明显的损耗。虚拟机的计算能力损耗在50%左右。

下图是在IBM x3650 M4 服务器运算 Linpack 程序得到的测试结果:

我们可以看到,使用 Docker 和不使用任何虚拟技术得到的结果基本没什么差别,而使用 KVM(一种虚拟机)则要慢的多了。

那么,为什么 Docker 能够达到如此高的效率呢?我们来看两张图:

上边是传统虚拟机的架构图,下边是 Docker 。总的来说,Docker 比传统虚拟机快主要在于以下两点原因:

  1. docker有着比虚拟机更少的抽象层。
  2. docker利用的是宿主机的内核,而不需要Guest OS。

Docker 和传统虚拟机的区别,就好比前者是在集装箱里面打了隔板,而后者则是在集装箱里有塞进去了小的集装箱。因此前者的效率比后者更高也就不足为奇了。

4.参考链接

Docker到底是什么?为什么它这么火!

如何通俗解释Docker是什么?

docker与虚拟机性能比较

利用canal实现MySQL数据同步到redis(二)同步MySQL的数据到redis集群

1.如何同步

我们已经解析了能够从 canal 服务器获取 解析过的 MySQL 的 binlog。接下来我们需要根据解析过的 binlog 将相同的数据写入到 redis 中。

2.同步程序

我们在 canal.example 的目录下建立两个新的 java 类,分别名为 ClusterSample.java 和 ClusterUtil.java。文件结构如下图所示:

在我的目录中,还有一些其他的 java 文件,它们都是不必要的,不必理会就好。只要你的目录中最后有 ClusterSample.java 和 ClusterUtil.java 两个文件就可以。

ClusterSample.java

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package com.alibaba.otter.canal.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
// Redis服务器IP
private static String ADDR = "127.0.0.1";
// Redis的端口号
private static int PORT = 7002;
// 访问密码
//private static String AUTH = "admin";
// 可用连接实例的最大数目,默认值为8;
// 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 1024;
// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 200;
// 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 10000;
// 过期时间
protected static int expireTime = 660 * 660 *24;
// 连接池
protected static JedisPool pool;
/**
* 静态代码,只在初次调用一次
*/
static {
JedisPoolConfig config = new JedisPoolConfig();
//最大连接数
config.setMaxTotal(MAX_ACTIVE);
//最多空闲实例
config.setMaxIdle(MAX_IDLE);
//超时时间
config.setMaxWaitMillis(MAX_WAIT);
//
config.setTestOnBorrow(false);
pool = new JedisPool(config, ADDR, PORT, 1000);
}
/**
* 获取jedis实例
*/
protected static synchronized Jedis getJedis() {
Jedis jedis = null;
try {
jedis = pool.getResource();
} catch (Exception e) {
e.printStackTrace();
if (jedis != null) {
pool.returnBrokenResource(jedis);
}
}
return jedis;
}
/**
* 释放jedis资源
*
* @param jedis
* @param isBroken
*/
protected static void closeResource(Jedis jedis, boolean isBroken) {
try {
if (isBroken) {
pool.returnBrokenResource(jedis);
} else {
pool.returnResource(jedis);
}
} catch (Exception e) {
}
}
/**
* 是否存在key
*
* @param key
*/
public static boolean existKey(String key) {
Jedis jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(0);
return jedis.exists(key);
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
return false;
}
/**
* 删除key
*
* @param key
*/
public static void delKey(String key) {
Jedis jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(0);
jedis.del(key);
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
}
/**
* 取得key的值
*
* @param key
*/
public static String stringGet(String key) {
Jedis jedis = null;
boolean isBroken = false;
String lastVal = null;
try {
jedis = getJedis();
jedis.select(0);
lastVal = jedis.get(key);
jedis.expire(key, expireTime);
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
return lastVal;
}
/**
* 添加string数据
*
* @param key
* @param value
*/
public static String stringSet(String key, String value) {
Jedis jedis = null;
boolean isBroken = false;
String lastVal = null;
try {
jedis = getJedis();
jedis.select(0);
lastVal = jedis.set(key, value);
jedis.expire(key, expireTime);
} catch (Exception e) {
e.printStackTrace();
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
return lastVal;
}
/**
* 添加hash数据
*
* @param key
* @param field
* @param value
*/
public static void hashSet(String key, String field, String value) {
boolean isBroken = false;
Jedis jedis = null;
try {
jedis = getJedis();
if (jedis != null) {
jedis.select(0);
jedis.hset(key, field, value);
jedis.expire(key, expireTime);
}
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
}
}

ClusterUtil.java

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package com.alibaba.otter.canal.example;
import java.util.HashSet;
//import java.util.LinkedHashSet;
import java.util.Set;
import redis.clients.jedis.HostAndPort;
//import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
//import redis.clients.jedis.JedisPool;
//import redis.clients.jedis.JedisPoolConfig;
public class ClusterUtil {
// 访问密码
// private static String AUTH = "admin";
// 过期时间
protected static int expireTime = 660 * 660 * 24;
// private static String host="10.0.76.192";
private static String host="127.0.0.1";
private static JedisCluster cluster;
static {
// 只给集群里一个实例就可以
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort(host, 7000));
jedisClusterNodes.add(new HostAndPort(host, 7001));
jedisClusterNodes.add(new HostAndPort(host, 7002));
jedisClusterNodes.add(new HostAndPort(host, 7003));
jedisClusterNodes.add(new HostAndPort(host, 7004));
jedisClusterNodes.add(new HostAndPort(host, 7005));
cluster = new JedisCluster(jedisClusterNodes);
}
/**
* 获取jedis实例
*/
protected static synchronized JedisCluster getJedis() {
return cluster;
}
/**
* 释放jedis资源
*
* @param jedis
* @param isBroken
*/
protected static void closeResource(JedisCluster cluster, boolean isBroken) {
}
/**
* 是否存在key
*
* @param key
*/
public static boolean existKey(String key) {
JedisCluster jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(0);
return jedis.exists(key);
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
return false;
}
/**
* 删除key
*
* @param key
*/
public static void delKey(String key) {
JedisCluster jedis = null;
boolean isBroken = false;
try {
jedis = getJedis();
jedis.select(0);
jedis.del(key);
} catch (Exception e) {
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
}
/**
* 取得key的值
*
* @param key
*/
public static String stringGet(String key) {
JedisCluster jedis = null;
boolean isBroken = false;
String lastVal = null;
try {
jedis = getJedis();
// jedis.select(0);
lastVal = jedis.get(key);
jedis.expire(key, expireTime);
} catch (Exception e) {
isBroken = true;
} finally {
// closeResource(jedis, isBroken);
}
return lastVal;
}
/**
* 添加string数据
*
* @param key
* @param value
*/
public static String stringSet(String key, String value) {
JedisCluster jedis = null;
boolean isBroken = false;
String lastVal = null;
try {
jedis = getJedis();
// jedis.select(0);
lastVal = jedis.set(key, value);
jedis.expire(key, expireTime);
} catch (Exception e) {
e.printStackTrace();
isBroken = true;
} finally {
closeResource(jedis, isBroken);
}
return lastVal;
}
/**
* 添加hash数据
*
* @param key
* @param field
* @param value
*/
public static void hashSet(String key, String field, String value) {
boolean isBroken = false;
JedisCluster jedis = null;
try {
jedis = getJedis();
if (jedis != null) {
//jedis.select(0);
jedis.hset(key, field, value);
jedis.expire(key, expireTime);
}
} catch (Exception e) {
isBroken = true;
} finally {
//closeResource(jedis, isBroken);
}
}
}

注意,redis 单点模式和集群模式的连接方法是不同的。详情参考:

Redis 单点模式和集群模式代码测试及问题记录

由于我们现在要连接的是 redis 集群,所以使用集群模式。

3.测试结果

启动 MySQl,Canal 服务器和 redis 集群,运行 ClusterSample.java 类。

3.1.在 MySQL 数据库中添加数据:

3.2.这时我们打开 Eclipse,就可以看到读取 binlog 成功的提示。

3.3.打开 redis 的客户端,查询响应的数据

红色方框内就是最新插入 MySQL 的三条数据。可见,redis 和 MySQL 的数据已经同步成功了。

4.参考链接

Redis 单点模式和集群模式代码测试及问题记录

jedis针对三种redis工作模式的连接方式

5.操作系统:Windows 10

利用canal实现MySQL数据同步到redis(一)canal的搭建

1.什么是canal

canal 的原理相对比较简单:

  1. canal 模拟 mysql slave 的交互协议,伪装自己为mysql slave,向 mysql master发送 dump 协议
  2. mysql master 收到 dump 请求,开始推送 binary log 给 slave (也就是 canal)
  3. canal 解析 binary log 对象(原始为 byte 流)

2.服务器端的配置

2.1.配置MySQL

2.1.1.修改配置文件

打开 MySQL 根目录,修改 my-default.ini 文件。

添加如下内容至文件中

1
2
3
log-bin=mysql-bin #添加这一行就ok
binlog-format=ROW #选择row模式
server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复

添加结果如图所示:

2.1.2.新建一个名为 canal 的用户,赋予其相应的权限

SQL 语句如下:

1
2
3
4
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'localhost';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'localhost' ;
FLUSH PRIVILEGES;

语句中的 localhost 在实际应用中需要改成 canal 服务器的 ip 地址。如果你和我一样使用本机进行配置,使用 localhost 即可。

2.2.下载 canal

下载地址:https://github.com/alibaba/canal/releases

我们下载下图中标红的两个文件。

在你喜欢的位置(我的是D:\WOrkSapce\)建立一个名为 canal 的文件夹,将这两个压缩包放到里面,然后分别解压到各自的文件夹即可。

2.3.修改 canal 配置文件

进入 D:\WorkSpace\canal\canal.deployer-1.0.24\conf\example 目录下

找到 instance.properties 文件,将数据库参数修改成你自己的信息。

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
#################################################
## mysql serverId
canal.instance.mysql.slaveId = 1234
# position info
canal.instance.master.address = 127.0.0.1:3306
canal.instance.master.journal.name =
canal.instance.master.position =
canal.instance.master.timestamp =
#canal.instance.standby.address =
#canal.instance.standby.journal.name =
#canal.instance.standby.position =
#canal.instance.standby.timestamp =
# username/password
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal
canal.instance.defaultDatabaseName = test
canal.instance.connectionCharset = UTF-8
# table regex
canal.instance.filter.regex = .*\\..*
# table black regex
canal.instance.filter.black.regex =
#################################################

2.4.启动 canal 服务端

进入 D:\WorkSpace\canal\canal.deployer-1.0.24\bin 目录下,输入:

1
startup.bat

启动 canal 服务端,得到结果如下图所示:

3.客户端的配置

3.1.导入 maven 项目

打开 eclipse,【File】->【Import】

选择 【Maven】 -> 【Existing Maven Projects】

找到你刚才下载解压的 canal-canal-1.0.24 ,确定

你会发现这些项目已经导入进来了

3.2.打开并运行 example

打开 canal.example ,找到 ClusterCanalClientTest ,运行

3.3.更新数据库并测试

打开 MySQL 终端,输入:

1
2
use test
create table table0(id int);

这时查看 ClusterCanalClientTest 的终端,发现 binlog 信息已经被解析出来了

4.参考链接

alibaba/canal 项目介绍:
https://github.com/alibaba/canal/wiki

5.操作系统:Windows10

一次惊险的体验(伪)

本故事纯属虚构,如有雷同,不可能。

今天我去公园玩,逛着逛着,发现天上有一架直升机。


直升机越飞越近,而我却没有察觉到即将到来的危险。


突然,它投下了一枚炸弹!


爆炸过后,惊慌失措的游客。


看着直升飞机渐渐远去的身影,我暗自感叹,以后再也不逛公园了!

SCAtoolbox应用指南

首先,什么是SCAtoolbox

SCAtoolbox是一个用于求解最优化问题的开源工具,使用matlab实现。
那么,什么是最优化问题呢?举个简单的例子:


z = x + y (0 < x < 1, 0 < y < 1),求 z 的最大值


这就是一个简单版的最优化问题,其中:
z = x + y 称作目标函数
0 < x < 1, 0 < y < 1 称作约束条件

接下来,我们来看看SCAtoolbox怎么用

SCAtoolbox可以从以下链接获取。
http://www.alimirjalili.com/SCA.html
解压之后,用matlab打开SCAtoolbox.m即可食用。


我们先来看一张SCAtoolbox的近照。

figure