tonglin0325的个人主页

MySQL学习笔记——约束

1.数据库约束简介

1.约束是在表上强制执行的数据检验规则,约束主要用于保证数据库的完整性。

2.当表中数据有相互依赖性时,可以保护相关的数据不被删除。

3.大部分数据库支持下面五类完整性约束:

  - NOT NULL非空

  - UNIQUE Key唯一值

  - PRIMARY KEY主键

  - FOREIGN KEY外键

  - CHECK检查

4.约束作为数据库对象,存放在系统表中,也有自己的名字

5.创建约束的时机:

  -在建表的同时创建

  -建表后创建(修改表)

6.有单列约束和多列约束

2.列级约束和表级约束

列级约束直接跟在列后面定义,不再需要指定列名,与列定义之间用空格分开

表级约束通常放在所有的列定义之后定义,要显式指定对哪些列建立列级约束,与列定义之间采用英语逗号,隔开

如果是对多列建联合约束,只能使用表级约束语法

1.非空约束(NOT NULL)

全文 >>

MySQL学习笔记——基本语法

SQL——结构化查询语言(Structured Query Language)

1. 字符集和大小写

SQL语言不区分大小写,建议关键字用大写,但是字符串常量区分大小写

字符集

1
2
3
4
5
6
7
8
9
character_set_client:服务器将系统变量character_set_client作为客户端发送语句时使用的字符集。
character_set_connection:用于没有字符集介绍器指定的字面量和用于数字到字符串转换的字符集。
character_set_database:默认数据库使用的字符集。每当默认数据库更改时,服务器都会设置此变量。
character_set_filesystem:文件系统字符集。
character_set_results:用于向客户端返回查询结果的字符集。这包括结果数据(如列值)、结果元数据(如列名)和错误消息。
character_set_server:服务器的默认字符集。如果你设置了这个变量,你还应该设置collation_server来指定字符集的排序规则。
character_set_system:服务器用于存储标识符的字符集。
character_sets_dir:安装字符集的目录。

MySQL5.7的默认字符集character和排序字符集collation

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
mysql> show variables like '%character%';
+--------------------------+--------------------------------------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /opt/rh/rh-mysql57/root/usr/share/rh-mysql57-mysql/charsets/ |
+--------------------------+--------------------------------------------------------------+
8 rows in set (0.00 sec)

mysql> show variables like '%collation%';
+----------------------+-------------------+
| Variable_name | Value |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database | latin1_swedish_ci |
| collation_server | latin1_swedish_ci |
+----------------------+-------------------+
3 rows in set (0.00 sec)

MySQL8.0的默认字符集

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
mysql> show variables like '%character%';
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.00 sec)

mysql> show variables like '%collation%';
+-------------------------------+--------------------+
| Variable_name | Value |
+-------------------------------+--------------------+
| collation_connection | latin1_swedish_ci |
| collation_database | utf8mb4_0900_ai_ci |
| collation_server | utf8mb4_0900_ai_ci |
| default_collation_for_utf8mb4 | utf8mb4_0900_ai_ci |
+-------------------------------+--------------------+
4 rows in set (0.00 sec)

查看mysql table字段的字符集

MySQL5.7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> create table user
(
id bigint unsigned auto_increment comment '主键' primary key,
username varchar(128) not null comment '用户名',
email varchar(128) not null comment '邮箱'
)
comment '用户表' charset=utf8mb4;

mysql> SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'default' and TABLE_NAME = 'user';
+-------------+--------------------+--------------------+
| COLUMN_NAME | CHARACTER_SET_NAME | COLLATION_NAME |
+-------------+--------------------+--------------------+
| id | NULL | NULL |
| username | utf8mb4 | utf8mb4_general_ci |
| email | utf8mb4 | utf8mb4_general_ci |
+-------------+--------------------+--------------------+
3 rows in set (0.00 sec)

或者

1
2
3
4
5
6
7
8
9
10
11
mysql > CREATE TABLE IF NOT EXISTS `t_user` (`username` varchar(64) NOT NULL,`password` varchar(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;

mysql > SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'default' and TABLE_NAME = 't_user';
+-------------+--------------------+-----------------+
| COLUMN_NAME | CHARACTER_SET_NAME | COLLATION_NAME |
+-------------+--------------------+-----------------+
| username | utf8 | utf8_general_ci |
| password | utf8 | utf8_general_ci |
+-------------+--------------------+-----------------+
2 rows in set (0.00 sec)

MySQL8.0

1
2
3
4
5
6
7
8
9
10
11
mysql> CREATE TABLE IF NOT EXISTS `t_user123` (`username` varchar(64) NOT NULL,`password` varchar(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'test' and TABLE_NAME = 't_user123';
+-------------+--------------------+-----------------+
| COLUMN_NAME | CHARACTER_SET_NAME | COLLATION_NAME |
+-------------+--------------------+-----------------+
| password | utf8mb3 | utf8_general_ci |
| username | utf8mb3 | utf8_general_ci |
+-------------+--------------------+-----------------+

utf8(别名utf8mb3)utf8 是 MySQL 早期版本使用的字符集,它实际上是 UTF-8 的一种实现,只支持最多 3 字节来存储一个字符。utf8 是 utf8mb3 的别名。从 MySQL 8.0.28 版本开始,utf8 已经被明确标识为 utf8mb3,但在此之前,它们是同义的。utf8适用于大多数情况,但不能用于需要存储 4 字节 UTF-8 字符的场景(如表情符号)。

utf8mb4 是 MySQL 完整实现的 UTF-8 字符集,支持最多 4 字节来存储一个字符。支持所有 Unicode 字符,包括所有表情符号和扩展字符。

utf8mb4_general_ci 的 ci 表示 case-insensitive,即不区分大小写

utf8mb4_bin 的 bin 表示 binary,这种排序规则是区分大小写的。

将字段类型修改成可区别大小写

1
2
CREATE TABLE your_table_name (column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);

在创建表的时候指定可区别大小写

1
2
3
4
5
6
7
CREATE TABLE user (
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键' PRIMARY KEY,
username VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用户名',
email VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '邮箱'
)
COMMENT '用户表' CHARSET=utf8mb4;

如果想区分case insensitive的字段,也可以使用binary函数将其转换成大小写敏感的,如下

1
2
select * from user where binary username = 'mlinnockax'

2. Database

1.列出MySQL服务器主机上的数据库

1
2
SHOW DATABASES[LIKE wild];

2. 用给定的名字创建一个数据库

语法:CREATE DATABASE[IF NO EXISTS]

全文 >>

使用confluent schema registry将protobuf schema转换成avro schema

confleunt提供了一些方法,可以将protobuf schema转换成avro schema,用于支持将kafka protobuf序列化的message落盘成avro格式的文件

1.引入依赖

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
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
<repository>
<id>confluent</id>
<url>https://packages.confluent.io/maven/</url>
</repository>
</repositories>

<dependencies>
<!--pb-->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.21.7</version>
</dependency>
<!--confluent-->
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-schema-registry</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-protobuf-provider</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-connect-avro-data</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-connect-protobuf-converter</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-connect-avro-data</artifactId>
<version>7.1.1</version>
</dependency>
<!--kafka-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>connect-api</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>

2.定义protobuf schema

定义一个protobuf schema

1
2
3
4
5
6
7
8
9
10
11
12
syntax = "proto3";
package com.acme;

message MyRecord {
string f1 = 1;
OtherRecord f2 = 2;
}

message OtherRecord {
int32 other_id = 1;
}

编译java代码

1
2
protoc -I=./ --java_out=./src/main/java ./src/main/proto/other.proto

得到schema的java代码

3.将protobuf schema转换成avro schema

confluent schema registry在处理处理protobuf,avro,json格式的数据的时候,会统一先将其转换成connect schema格式的数据,然后再将其写成parquet,avro等具体的文件格式

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
import com.acme.Other;
import io.confluent.connect.avro.AvroData;
import io.confluent.connect.avro.AvroDataConfig;
import io.confluent.connect.protobuf.ProtobufData;
import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchema;
import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchemaUtils;
import org.apache.kafka.connect.data.SchemaAndValue;

public class ProtobufToAvro {

public static void main(String[] args) {
// 初始化protobuf定义的类
Other.MyRecord obj = Other.MyRecord.newBuilder().build();
// 获取pb schema
ProtobufSchema pbSchema = ProtobufSchemaUtils.getSchema(obj);
ProtobufData protobufData = new ProtobufData();
// SchemaAndValue result = protobufData.toConnectData(pbSchema, obj);
// System.out.println(result);

AvroDataConfig avroDataConfig = new AvroDataConfig.Builder()
.with(AvroDataConfig.SCHEMAS_CACHE_SIZE_CONFIG, 1)
.with(AvroDataConfig.CONNECT_META_DATA_CONFIG, false)
.with(AvroDataConfig.ENHANCED_AVRO_SCHEMA_SUPPORT_CONFIG, true)
.build();
AvroData avroData = new AvroData(avroDataConfig);
// 先将protobuf schema转换成connect schema,然后再转换成avro schema
org.apache.avro.Schema avroSchema = avroData.fromConnectSchema(protobufData.toConnectSchema(pbSchema));
System.out.println(avroSchema);
}

}

转换的avro schema输出如下

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
{
"type":"record",
"name":"MyRecord",
"fields":[
{
"name":"f1",
"type":[
"null",
"string"
],
"default":null
},
{
"name":"f2",
"type":[
"null",
{
"type":"record",
"name":"OtherRecord",
"fields":[
{
"name":"other_id",
"type":[
"null",
"int"
],
"default":null
}
]
}
],
"default":null
}
]
}

注意:confluent在具体实现的时候,比较严谨,在protobuf的uint32(0 到 2^32 -1)的时候,会统一转换成long(-2^63 ~ 2^63-1),不会出现越界的情况,参考源码

1
2
https://github.com/confluentinc/schema-registry/blob/v7.1.1/protobuf-converter/src/main/java/io/confluent/connect/protobuf/ProtobufData.java#L1485

转换实现参考源码

1
2
https://github.com/confluentinc/schema-registry/blob/v7.1.1/avro-data/src/test/java/io/confluent/connect/avro/AdditionalAvroDataTest.java

全文 >>

Hive学习笔记——安装hive客户端

hive client安装文档

1
2
https://cwiki.apache.org/confluence/display/Hive/GettingStarted

hive 配置官方文档

1
2
https://cwiki.apache.org/confluence/display/hive/configuration+properties

hive 配置中文文档

1
2
https://www.docs4dev.com/docs/zh/apache-hive/3.1.1/reference/Configuration_Properties.html

avro学习笔记——实现序列化和反序列化

1.使用java语言来实现avro序列化和反序列化

使用DatumWriter和DatumReader对avro进行序列化和反序列化

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
public static <T> byte[] binarySerializable(T t) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BinaryEncoder binaryEncoder = EncoderFactory.get().binaryEncoder(out, null);
DatumWriter<T> writer = new SpecificDatumWriter<T>((Class<T>) t.getClass());
try {
writer.write(t, binaryEncoder);
binaryEncoder.flush();
out.flush();
} catch (IOException e) {
LOGGER.error("binary serializable error");
e.printStackTrace();
}
LOGGER.debug("ByteArrayOutputStream = {}", new String(out.toByteArray()));
return out.toByteArray();
}


public static <T> T binaryDeserialize(byte[] bytes, Schema schema) {
try {
BinaryDecoder binaryDecoder = DecoderFactory.get().binaryDecoder(bytes, null);
DatumReader<T> datumReader = new SpecificDatumReader<T>(schema);
T read = datumReader.read(null, binaryDecoder);
return read;
} catch (IOException e) {
LOGGER.error("binary deserialize error");
e.printStackTrace();
}
return null;
}

使用Twitter 的 Bijection 类库来实现avro对象的序列化和反序列化

参考:Kafka 中使用 Avro 序列化框架(二):使用 Twitter 的 Bijection 类库实现 avro 的序列化与反序列化

全文 >>

JavaWeb学习笔记——ServletConfig和ServletContext

1.只有在第一次请求服务器产生实例的时候才会调用init()方法,有一种办法能在服务器一启动的时候就加载init()方法。

即服务器启动即加载Servlet,且按数字大小顺序实例化Servlet。

方法:

  创建一个TestObject.java

  在web.xml中的1,数字小的Servlet将先启动。

  再创建一个TestObject2.java,然后在web.xml中写2

  

    1>在Servlet的配置文件中,可以使用一个或多个标签为servlet配置一些初始化参数。(配置在某个servlet标签或者整个web-app下)

全文 >>

如何使用Hexo搭建静态博客

介绍如何使用Hexo和Github搭建静态博客
使用的主题为Bootstrap
搭建的环境是ubuntu 14.04 LTS

<1>什么是Hexo

Hexo 是一款基于node 的静态博客网站生成器,作者:tommy351是一个台湾的在校大学生。 相比其他的静态网页生成器而言有着,生成静态网页最快,插件丰富(已经移植了大量Octopress插件)。 同其他很多轻量级博客如jekyll、octopress、jekyllbootstrap等一样,也是使用Markdown语法进行编辑博文,即编辑.md后缀的文件。

hexo的github主页地址: Hexo_Github
Markdown的中文语法: Hexo_Docs

全文 >>

Chrome使用笔记

1.开启debug模式

可以通过在启动命令中添加

1
2
--remote-debugging-port=9222

来开启chrome的debug端口,这样就可以通过这个端口来获取或者操作chrome,如下

macos

1
2
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222

linux

1
2
google-chrome --remote-debugging-port=9222

windows

1
2
3
右键点击 Chrome 的快捷方式图标,选择属性
在目标一栏,最后加上--remote-debugging-port=9222 注意要用空格隔开

可以打开另一个chrome浏览器B来监控开启了debug端口的chrome浏览器A

在Chrome浏览器B中打开

1
2
chrome://inspect/#devices

将其中的端口设置成开启了debug模式的chrome浏览器B的端口

这样就可以在浏览器A中看到浏览器B的浏览记录

1
2
chrome://inspect/#pages

参考:Google Chrome远程调试的简单利用

也可以使用selenium来连接开启了debug端口的chrome

参考:Python爬虫——使用selenium和chrome爬取js动态加载的网页

如果想获取chrome用户的cookie的话,需要指定chrome的用户目录,如下

1
2
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/Users/xxx/Library/Application\ Support/Google/Chrome

vscode设置chrome远程调试

参考:设置 Chrome 远程调试端口

2.打开waterfall

在控制台的启动栏那一栏右键,选中瀑布,可以添加waterfall用于查看接口和资源的请求和响应时间

3.浏览器调整动画播放速度

全文 >>