Clickhouse单机部署以及从mysql增量同步数据
背景:
随着数据量的上升,OLAP一直是被讨论的话题,虽然druid,kylin能够解决OLAP问题,但是druid,kylin也是需要和hadoop全家桶一起用的,异常的笨重,再说我也搞不定,那只能找我能搞定的技术。故引进clickhoue,关于clickhoue在17年本人就开始关注,并且写了一些入门的介绍,直到19年clickhoue功能慢慢的丰富才又慢慢的关注,并且编写了同步程序,把mysql数据实时同步到clickhoue,并且最终在线上使用起来。
关于clickhouse是什么请自行查阅官网:https://clickhouse.yandex/
clickhouse官方性能测试:https://clickhouse.yandex/benchmark.html
clickhouse面对海量数据,比如单表过百亿可以使用集群(复制+分片),如果数据量比较小,比如单表10-20亿使用单机就足以满足查询需求。如果使用复制需要使用zk,更多集群的请自行查阅官方资料。
单机部署(以前的文章也有写过单机部署) :
在2016年clickhouse刚开始开源的时候对Ubuntu支持非常友好,一个apt命令就可以安装了。对于centos等系统 支持就比较差,需要自己编译,而且不一定能够成功。随着使用人群的扩大,目前对于centos支持也是非常的友好 了,有rpm包可以直接安装。甚至目前Altinity公司已经制作了yum源,添加源之后直接yum安装完成。这个在官方 文档里面也有提到,参考: https://clickhouse.yandex/docs/en/getting_started/ https://github.com/Altinity/clickhouse-rpm-install 。目前线上使用的是centos 7.0的系统。之所以使用7.0的系统是因为同步数据的程序是用python写的,而且用到的 一个核心包:python-mysql-replication需要使用python 2.7的环境。同时由于clickhouse不兼容mysql协议,为了方便开发接入系统不用过多更改代码,引入了proxysql兼容mysql协议,clickhouse最新版本已经支持mysql协议,支持clickhouse的proxysql也需要python 2.7的环境,所以干脆直接用centos 7.0系统
测试环境:
服务器数量:1台
操作系统:centos 7.1
安装服务:clickhouse,mysql
安装mysql是测试clickhouse从mysql同步数据。
clickhouse安装:
添加yum源
curl -s https://packagecloud.io/install/repositories/altinity/clickhouse/script.rpm.sh | sudo bash
yum安装
yum install -y clickhouse-server clickhouse-client
服务启动
/etc/init.d/clickhouse-server start
默认数据存放位置是: /var/lib/clickhouse/
登录,查看数据库(默认用户是default,密码为空)
[root@ck-server- sync]# clickhouse-client -h 127.0.0.1
ClickHouse client version 19.9.2.4.
Connecting to 127.0.0.1: as user default.
Connected to ClickHouse server version 19.9. revision . ck-server- :) show databases; SHOW DATABASES ┌─name────┐
│ default │
│ system │
└─────────┘ rows in set. Elapsed: 0.003 sec. ck-server- :)
default数据库里面没有任何东西,和mysql里面的test库是一样的。system库看名字就知道是什么。到这里clickhouse就部署完成,是不是很简单?
补充一点,在官方的文档里面有几点建议:
1. 关闭大页
2. 调整内存使用
3. 关闭cpu节能模式
echo 'performance' | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
echo > /proc/sys/vm/overcommit_memory
echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled
mysql部署请自行部署。这里不做介绍。如果想从mysql同步数据那么binlog 格式必须是row。而且必须binlog_row_image=full
安装同步程序依赖的包;同步程序可以放在clickhouse服务器上面,也可以单独放在其他服务器。同步程序使用pypy启动,所以安装包的时候需要安装pypy的包。
yum -y install pypy-libs pypy pypy-devel
wget https://bootstrap.pypa.io/get-pip.py
pypy get-pip.py
/usr/lib64/pypy-5.0./bin/pip install MySQL-python
/usr/lib64/pypy-5.0./bin/pip install mysql-replication
/usr/lib64/pypy-5.0./bin/pip install clickhouse-driver
/usr/lib64/pypy-5.0./bin/pip install redis
这里也安装了redis模块是因为同步的binlog pos可以存放在redis里面,当然程序也是支持存放在文件里面
proxysql安装(主要是为了clickhouse兼容mysql协议): proxysql在这里下载:https://github.com/sysown/proxysql/releases 选择带clickhouse的包下载,否则不会支持clickhouse。ps:较新版本的clickhouse已经原生兼容mysql协议。
proxysql安装及配置
rpm -ivh proxysql-2.0.--clickhouse-centos7.x86_64.rpm
启动(必须这样启动,否则是不支持clickhouse的):
proxysql --clickhouse-server
登录proxysql,设置账户:
mysql -uadmin -padmin -h127.0.0.1 -P6032
INSERT INTO clickhouse_users VALUES ('clicku','clickp',1,100);
LOAD CLICKHOUSE USERS TO RUNTIME;
SAVE CLICKHOUSE USERS TO DISK;
使用proxysql连接到clickhouse:
[root@ck-server- sync]# mysql -u clicku -pclickp -h 127.0.0.1 -P6090
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is
Server version: 5.5. (ProxySQL ClickHouse Module) Copyright (c) , , Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases;
+---------+
| name |
+---------+
| default |
| system |
+---------+
mysql同步数据到clickhouse
mysql里面有个库yayun,库里面有张表tb1,同步这张表到clickhoue
mysql> use yayun;
Database changed
mysql> show create table tb1\G
*************************** 1. row ***************************
Table: tb1
Create Table: CREATE TABLE `tb1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pay_money` decimal(20,2) NOT NULL DEFAULT '0.00',
`pay_day` date NOT NULL,
`pay_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
1. clickhoue里面建库,建表。
ck-server-01 :) create database yayun; CREATE DATABASE yayun Ok. 0 rows in set. Elapsed: 0.021 sec. ck-server-01 :)
2. 建表(clickhouse建表的格式以及字段类型和mysql完全不一样,如果字段少还可以自己建,如果字段多比较痛苦,可以使用clickhouse自带的从mysql导数据的命令来建表),在建表之前需要进行授权,因为程序同步也是模拟一个从库拉取数据.
GRANT REPLICATION SLAVE, REPLICATION CLIENT, SELECT ON *.* TO 'ch_repl'@'127.0.0.1' identified by '';
3. 登陆clickhouse进行建表
ck-server-01 :) use yayun; USE yayun Ok. 0 rows in set. Elapsed: 0.001 sec. ck-server-01 :) CREATE TABLE tb1
:-] ENGINE = MergeTree
:-] PARTITION BY toYYYYMM(pay_time)
:-] ORDER BY (pay_time) AS
:-] SELECT *
:-] FROM mysql('127.0.0.1:3306', 'yayun', 'tb1', 'ch_repl', '') ; CREATE TABLE tb1
ENGINE = MergeTree
PARTITION BY toYYYYMM(pay_time)
ORDER BY pay_time AS
SELECT *
FROM mysql('127.0.0.1:3306', 'yayun', 'tb1', 'ch_repl', '') Ok. 0 rows in set. Elapsed: 0.031 sec.
这里使用MergeTree引擎,MergeTree是clickhouse里面最牛逼的引擎,支持海量数据,支持索引,支持分区,支持更新删除。toYYYYMM(pay_time)的意思是根据pay_time分区,粒度是按月。ORDER BY (pay_time)的意思是根据pay_time排序存储,同时也是索引。上面的create table命令如果mysql表里面以后数据那么数据也会一并进入clickhouse里面。通常会limit 1,然后更改一下表结构。上面没有报错的话我们看看clickhouse里面的表结构:
ck-server-01 :) show create table tb1; SHOW CREATE TABLE tb1 ┌─statement────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE TABLE yayun.tb1 (`id` UInt32, `pay_money` String, `pay_day` Date, `pay_time` DateTime) ENGINE = MergeTree PARTITION BY toYYYYMM(pay_time) ORDER BY pay_time SETTINGS index_granularity = 8192 │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 1 rows in set. Elapsed: 0.002 sec.
其中这里的index_granularity = 8192是指索引的粒度。如果数据量没有达到百亿,那么通常无需更改。表结构也创建完成以后现在配置同步程序配置文件:metainfo.conf
[root@ck-server- sync]# cat metainfo.conf
# 从这里同步数据
[master_server]
host='127.0.0.1'
port=
user='ch_repl'
passwd=''
server_id= # redis配置信息,用于存放pos点
[redis_server]
host='127.0.0.1'
port=
passwd=''
log_pos_prefix='log_pos_' #把log_position记录到文件
[log_position]
file='./repl_pos.log' # ch server信息,数据同步以后写入这里
[clickhouse_server]
host=127.0.0.1
port=
passwd=''
user='default'
#字段大小写. 1是大写,0是小写
column_lower_upper= # 需要同步的数据库
[only_schemas]
schemas='yayun' # 需要同步的表
[only_tables]
tables='tb1' # 指定库表跳过DML语句(update,delete可选)
[skip_dmls_sing]
skip_delete_tb_name = ''
skip_update_tb_name = '' #跳过所有表的DML语句(update,delete可选)
[skip_dmls_all]
#skip_type = 'delete'
#skip_type = 'delete,update'
skip_type = '' [bulk_insert_nums]
#多少记录提交一次
insert_nums=
#选择每隔多少秒同步一次,负数表示不启用,单位秒
interval= # 同步失败告警收件人
[failure_alarm]
mail_host= 'xxx'
mail_port=
mail_user= 'xxx'
mail_pass= 'xxx'
mail_send_from = 'xxx'
alarm_mail = 'xxx' #日志存放路径
[repl_log]
log_dir="/tmp/relication_mysql_clickhouse.log"
设置pos点:
和mysql搭建从库一样,配置从哪里开始同步,看mysql的pos点:
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000069 | 4024404 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
把pos点写入文件或者redis,我选择记录到文件就是。
[root@ck-server- sync]# cat repl_pos.log
[log_position]
filename = mysql-bin.
position = [root@ck-server- sync]#
启动同步程序:
[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --help
usage: Data Replication to clikhouse [-h] [-c CONF] [-d] [-l] mysql data is copied to clikhouse optional arguments:
-h, --help show this help message and exit
-c CONF, --conf CONF Data synchronization information file
-d, --debug Display SQL information
-l, --logtoredis log position to redis ,default file By dengyayun @
[root@ck-server- sync]#
默认pos点就是记录文件,无需再指定记录binlog pos方式
[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --conf metainfo.conf --debug
:: INFO 开始同步数据时间 -- ::
:: INFO 从服务器 127.0.0.1: 同步数据
:: INFO 读取binlog: mysql-bin.:
:: INFO 同步到clickhouse server 127.0.0.1:
:: INFO 同步到clickhouse的数据库: ['yayun']
:: INFO 同步到clickhouse的表: ['tb1']
mysql插入10条数据:
mysql> insert into tb1 (pay_money,pay_day,pay_time)values('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00'),('66.22','2019-06-29','2019-06-29 14:00:00') ;
Query OK, 10 rows affected (0.01 sec)
Records: 10 Duplicates: 0 Warnings: 0 mysql> select * from tb1;
+----+-----------+------------+---------------------+
| id | pay_money | pay_day | pay_time |
+----+-----------+------------+---------------------+
| 1 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 3 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 5 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 7 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 9 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 11 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 13 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 15 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 17 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
| 19 | 66.22 | 2019-06-29 | 2019-06-29 14:00:00 |
同步程序日志输出:
[root@ck-server- sync]# pypy mysql-clickhouse-replication.py --conf metainfo.conf --debug
:: INFO 开始同步数据时间 -- ::
:: INFO 从服务器 127.0.0.1: 同步数据
:: INFO 读取binlog: mysql-bin.:
:: INFO 同步到clickhouse server 127.0.0.1:
:: INFO 同步到clickhouse的数据库: ['yayun']
:: INFO 同步到clickhouse的表: ['tb1']
:: INFO INSERT 数据插入SQL: INSERT INTO yayun.tb1 VALUES, [{u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}, {u'id': , u'pay_money': '66.22', u'pay_day': datetime.date(, , ), u'pay_time': datetime.datetime(, , , , )}]
clickhoue数据查询:
ck-server-01 :) select * from tb1; SELECT *
FROM tb1 ┌─id─┬─pay_money─┬────pay_day─┬────────────pay_time─┐
│ 1 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 3 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 5 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 7 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 9 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 11 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 13 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 15 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 17 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 19 │ 66.22 │ 2019-06-29 │ 2019-06-29 14:00:00 │
└────┴───────────┴────────────┴─────────────────────┘ 10 rows in set. Elapsed: 0.005 sec.
mysql数据更新:
mysql> update tb1 set pay_money='88.88';
Query OK, 10 rows affected (0.00 sec)
Rows matched: 10 Changed: 10 Warnings: 0 mysql> select * from tb1;
+----+-----------+------------+---------------------+
| id | pay_money | pay_day | pay_time |
+----+-----------+------------+---------------------+
| 1 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 3 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 5 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 7 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 9 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 11 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 13 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 15 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 17 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
| 19 | 88.88 | 2019-06-29 | 2019-06-29 14:00:00 |
+----+-----------+------------+---------------------+
10 rows in set (0.00 sec)
clickhoue数据查询:
ck-server-01 :) select * from tb1; SELECT *
FROM tb1 ┌─id─┬─pay_money─┬────pay_day─┬────────────pay_time─┐
│ 1 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 3 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 5 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 7 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 9 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 11 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 13 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 15 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 17 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
│ 19 │ 88.88 │ 2019-06-29 │ 2019-06-29 14:00:00 │
└────┴───────────┴────────────┴─────────────────────┘ 10 rows in set. Elapsed: 0.009 sec.
可以看见数据都同步完成。
代码地址:
https://github.com/yymysql/mysql-clickhouse-replication
总结:
目前线上报表业务都已经在使用clickhoue,数据同步采用自行开发的同步程序进行同步。目前数据一致性没有什么问题。当然同步的表需要有自增主键,否则有些情况比较难处理。延时也比较小。数据的延时以及数据的一致性都有监控。
总体来说使用clickhoue处理olap还是非常不错的选择,小伙伴们可以尝试。
参考资料
https://clickhouse-driver.readthedocs.io/en/latest/
https://python-mysql-replication.readthedocs.io/en/latest/examples.html
https://clickhouse.yandex/docs/en/
https://github.com/sysown/proxysql/wiki/ClickHouse-Support
Clickhouse单机部署以及从mysql增量同步数据的更多相关文章
- 实现从Oracle增量同步数据到GreenPlum
简介: GreenPlum是一个基于PostgreSQL数据库开发的MPP架构的数据库仓库,适用于OLAP系统,支持50PB(1PB=1000TB)级海量数据的存储和处理. 背景: 目前有一个业务是需 ...
- Elasticsearch mysql 增量同步
主要用到了一个JDBC importer for Elasticsearch的库. 想要增量同步,有一些先决条件.首先数据库中要维护一个update_time的时间戳,这个字段表示了该记录的最后更新时 ...
- Elasticsearch mysql 增量同步 三表联合 脚本
在上一篇中简略的说了一下es同步数据脚本的大致情况,但是实际情况里肯定不会像上一篇里面的脚本那么简单.比如目前我就有三张表,两张实体表,一张关联表.大致实现如下: bin目录建立一个statefile ...
- 使用 DataX 增量同步数据(转)
关于 DataX DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL.Oracle.SqlServer.Postgre.HDFS.Hive.ADS.HBase.Tab ...
- 用canal监控binlog并实现mysql定制同步数据的功能
业务背景 写任何工具都不能脱离实际业务的背景.开始这个项目的时候是因为现有的项目中数据分布太零碎,零零散散的分布在好几个数据库中,没有统一的数据库来收集这些数据.这种情况下想做一个大而全的会员中心系统 ...
- Canal:同步mysql增量数据工具,一篇详解核心知识点
老刘是一名即将找工作的研二学生,写博客一方面是总结大数据开发的知识点,一方面是希望能够帮助伙伴让自学从此不求人.由于老刘是自学大数据开发,博客中肯定会存在一些不足,还希望大家能够批评指正,让我们一起进 ...
- 这次一定要教会你搭建Redis集群和MySQL主从同步(非Docker)
前言 一直都想自己动手搭建一个Redis集群和MySQL的主从同步,当然不是依靠Docker的一键部署(虽然现在企业开发用的最多的是这种方式),所以本文就算是一个教程类文章吧,但在动手搭建之前,会先聊 ...
- 从mysql读取大量数据时的实践
背景 程序启动时,从mysql读取所有的数据,在内存中建立数据结构.mysql表中至少有100w条记录.以后根据时间定期从mysql增量读取数据,刷新内存结构. 表结构为{uid, product, ...
- MySQL数据实时增量同步到Kafka - Flume
转载自:https://www.cnblogs.com/yucy/p/7845105.html MySQL数据实时增量同步到Kafka - Flume 写在前面的话 需求,将MySQL里的数据实时 ...
随机推荐
- webwork遍历数组标签
WebWork中提供了一个<ww:iterator></ww:iterator>标签用于遍历数组. 01 如果数组中是普通类型,比如String.int等类型,可以通过标签中的 ...
- vue项目中引入iconfont
背景 对于前端而言,图标的发展可谓日新月异.从img标签,到雪碧图,再到字体图标,svg,甚至svg也有了类似于雪碧图的方案svg-sprite-loader.雪碧图没有什么好讲的了,只是简单地利用了 ...
- PHP获取网址详情页的内容导出到WORD文件
亲自测试效果一般, css的样式文件获取不到 如果没有特殊的样式 或者是内容里面包括样式的 直接输出有样式的内容 然后导出 这样还是可以的 class word { function start ...
- c# winform 窗体失去焦点关闭(钩子实现)
先来一个辅助类 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Inte ...
- SQL常用函数之STR()
使用str函数 :STR 函数由数字数据转换来的字符数据. 语法 STR ( float_expression [ , length [ , ...
- Python 容器使用的 5 个技巧和 2 个误区
"容器"这两个字很少被 Python 技术文章提起.一看到"容器",大家想到的多是那头蓝色小鲸鱼:Docker,但这篇文章和它没有任何关系.本文里的容器,是 P ...
- JVM内存分配策略,及垃圾回收算法
本人免费整理了Java高级资料,一共30G,需要自己领取;传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q 说起垃圾收集(Garbage Co ...
- 用ggplot包画一个简单饼图
首先用library函数加载ggplot2包 library(ggplot2) library(dplyr) library(tidyr) library(splines) 接下来,进行数据准备: d ...
- SpringBoot(五) SpringBoot整合mybatis
一:项目结构: 二:pom文件如下: <parent> <groupId>org.springframework.boot</groupId> <artifa ...
- django2-登录与出版社
1.django核心功能 因为django功能很多 ,出版社可以使用到部分功能,最快最简单了解django的运行模式,每个点后续细化去梳理 django的路由 django的视图 django的模板 ...