秦悦明的运维笔记

redis基础

1. redis支持的五大数据结构

分别是

  • string
  • list
  • set
  • hash
  • zset (有序集合)

2. string 字符串

基本上用法跟另一个开源产品memcached的用法差不多了,k-v结构.
相关命令是:

  • set
  • get
  • del

没啥多说的,如果你喜欢的话可以存文件。

3. list 队列

redis里面的队列能做到双向队列,两头都可以操作。
相关命令是:

  • rpush
  • rpop
  • lpush
  • lpop
  • lindex 获取给定位置的单个元素
  • lrange 获取给定范围上的所有值

一个非常典型的用法是用作消息队列,如果是先进先出的那种,可以直接用rpush和lpop,so easy。

4. set 集合

存储的方式是无序的,用户可以通过sadd命令将元素添加到集合,使用srem将元素从集合中删除。
相关命令:

  • sadd
  • srem
  • sismember 判断是否是集合中的元素
  • smembers 获取集合包含的所有元素

5. hash

相关命令:

  • hset
  • hget
  • hgetall
  • hdel

6. zset 有序集合

集合带分值(score),分值必须为浮点数。有序集合是redis里面唯一一个即可以根据成员访问元素,又可以根据分值的排列顺序来访问元素的结构。
相关命令:

  • zadd
  • zrange
  • zrangebyscore
  • zrem

命令详细页面: https://redis.io/commands

spring jdbcTemplate配置

1. 创建Account类和AccountDao接口

1
2
3
4
5
6
7
public class Account {
private long id;
private String ownerName;
private double balance;
private Date accessTime;
private boolean locked;
...
1
2
3
4
5
6
7
8
9
10
public interface AccountDao {
public void insert(Account account);
public void update(Account account);
public void update(List<Account> accounts);
public void delete(long accountId);
public Account find(long accountId);
public List<Account> find(List<Long> accountIds);
public List<Account> find(String ownerName);
public List<Account> find(boolean locked);
}

2. 实现AccountDao接口的AccountDaoJdbcImpl类

1
2
3
4
5
6
7
8
9
10
11
12
public class AccountDaoJdbcImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void insert(Account account) {
// TODO Auto-generated method stub
}

3. 使用jdbcTemplate类定义jdbcTemplate Bean,并使用dataSource Bean 满足DataSource其依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}

4. 使用AccountDaoJdbcImpl创建accountDao bean,并将jdbcTemplate Bean注入其中:

1
2
3
4
5
6
@Bean
public AccountDao accountDao() {
AccountDaoJdbcImpl accountDao = new AccountDaoJdbcImpl();
accountDao.setJdbcTemplate(jdbcTemplate());
return accountDao;
}

5. main中查找accountDao bean

1
AccountDao accountDao = applicationContext.getBean(AccountDao.class);

之后便意味着可以在accountdaojdbcimpl中使用jdbctemplate 了。

6. 使用jdbctemplate运行查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Account find(long accountId) {
return jdbcTemplate
.queryForObject(
"select id,owner_name,balance,access_time,locked from account where id = ?",
new RowMapper<Account>() {
public Account mapRow(ResultSet rs, int rowNum)
throws SQLException {
Account account = new Account();
account.setId(rs.getLong("id"));
account.setOwnerName(rs.getString("owner_name"));
account.setBalance(rs.getDouble("balance"));
account.setAccessTime(rs
.getTimestamp("access_time"));
account.setLocked(rs.getBoolean("locked"));
return account;
}
}, accountId);
}

使用jdbctemplate的 queryforobject方法。

调用参数是

1
2
3
4
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
List<T> results = (List)this.query((String)sql, (Object[])args, (ResultSetExtractor)(new RowMapperResultSetExtractor(rowMapper, 1)));
return DataAccessUtils.requiredSingleResult(results);
}

第一个参数是string的sql 语句,sql语句里面用问号做了占位符。第二个是RowMapper的接口,这里创建了一个匿名类,第三个之后是可变参数列表。

1
2
3
public interface RowMapper<T> {
T mapRow(ResultSet var1, int var2) throws SQLException;
}

RowMapper 里面就一个函数,mapRow,从ResultSet对象中获取值填充属性。比如这里的,new了一个Account对象,然后把ResultSet里面的属性填充一下就行了。

在main中这样调用即可:

1
2
AccountDao accountDao = applicationContext.getBean(AccountDao.class);
Account account = accountDao.find(100L);

spring jdbc数据源

0. 所有jdbc的先决条件

配置数据源,spring里面是配置一个datasource bean。

1. maven依赖

需要导入jdbc包,spring包,h2包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.175</version>
</dependency>

2. 运行h2数据库

可以网上找h2的二进制包运行,也可以直接在idea里面找到org.h2.tools.Console类运行。
用户名sa,密码为空。

3. 创建一个spring bean配置类,使用DriverManagerDataSource定义一个datasource bean

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class Ch4Configuration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}

DriverManagerDataSource还有一个子类SingleConnectionDataSource,该类重复使用相同的连接。

1
2
3
4
5
6
7
8
9
10
11
12
public class Ch4Configuration {
@Bean
public DataSource dataSource() {
SingleConnectionDataSource dataSource = new SingleConnectionDataSource();
dataSource.setSuppressClose(true);
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}

4. 生产环境下使用连接池化的datasource

比如C3P0,或者DBCP,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
import org.apache.commons.dbcp.BasicDataSource;
@Configuration
public class Ch4ConfigurationForPooledDS1 {
@Bean(destroyMethod="close")
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2.1</version>
</dependency>
import com.mchange.v2.c3p0.ComboPooledDataSource;
@Configuration
public class Ch4ConfigurationForPooledDS2 {
@Bean(destroyMethod="close")
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("org.h2.Driver");
dataSource.setJdbcUrl("jdbc:h2:tcp://localhost/~/test");
dataSource.setUser("sa");
dataSource.setPassword("");
return dataSource;
}
}

5. 获取connection

1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) throws SQLException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Ch4Configuration.class);
DataSource dataSource = applicationContext.getBean("dataSource", DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection.isClosed());
connection.close();
System.out.println(connection.isClosed());
}
}

所有datasource 都实现了getConnection()接口,直接调用即可。这样我们就通过jdbc 数据源,获取了数据库连接。

spring boot与docker结合

1. 结合起来跟其他java程序差不多

无非就是dockerfile,然后build ,push ,pull 。但是spring boot特别适合微服务,特别适合在容器里面跑,因为他内嵌了tomcat,单进程。https://spring.io/guides/gs/spring-boot-docker/ 讲述了他和mvn结合的奇妙例子。

2. Dockerfile

1
2
3
4
5
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

虽然这是一个普通的不能再普通的dockerfile,但是里面的JAR_FILE很完美的替代了硬编码,具体是mvn传进去的参数。

3.mvn配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<properties>
<docker.image.prefix>springio</docker.image.prefix>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>

用了个dockerfile-maven-plugin的插件,直接将mvn package 的jar文件名传到dockerfile里面去。
可以直接用mvn命令来build 。

1
mvn install dockerfile:build

build完之后可以push,带tag的push,非常方便。官网https://github.com/spotify/docker-maven-plugin

spring-boot一般套路

1. 依赖

  • jdk
  • maven ,版本要比较新的
  • ide ,我用idea ,加vim 插件

2. pom文件

1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>

如果需要web的,则增加web的依赖

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

3. 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class Example {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}

几个注解下来就能运行一个简单的restful 应用,so easy.

1
mvn spring-boot:run

4.编译jar包

如果想编译成独立的jar 包,那么要添加spring-boot-maven-plugin到pom文件里去。

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

编译:

1
2
mvn package
...

然后运行

1
java -jar target/myproject-0.0.1-SNAPSHOT.jar

5. 用http://start.spring.io/ 生成项目文件

在线生产项目模版:

http://start.spring.io/

下载下来改改就能用。
或者用命令行的版本
http://repo.spring.io/release/org/springframework/boot/spring-boot-cli