# 1.创建数据库
CREATE DATABASE test charset=utf8mb4;
USE test;
# 2.创建表
CREATE TABLE User (
userId INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
registrationDate DATETIME NOT NULL,
lastLogin DATETIME,
createTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
updateTime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP -- 更新时间
);
# 3.插入测试数据
INSERT INTO test.`User` (username, email, registrationDate, lastLogin) VALUES
('JohnDoe01', 'john.doe01@example.com', '2023-02-01 08:00:00', '2023-02-02 09:00:00'),
('JaneDoe02', 'jane.doe02@example.com', '2023-02-02 10:00:00', '2023-02-03 11:00:00'),
('MikeSmith03', 'mike.smith03@example.com', '2023-02-03 12:00:00', '2023-02-04 13:00:00'),
('LucyBrown04', 'lucy.brown04@example.com', '2023-02-04 14:00:00', '2023-02-05 15:00:00'),
('DavidWilson05', 'david.wilson05@example.com', '2023-02-05 16:00:00', '2023-02-06 17:00:00'),
('LindaTaylor06', 'linda.taylor06@example.com', '2023-02-06 18:00:00', '2023-02-07 19:00:00'),
('RobertJones07', 'robert.jones07@example.com', '2023-02-07 20:00:00', '2023-02-08 21:00:00'),
('PatriciaWhite08', 'patricia.white08@example.com', '2023-02-08 22:00:00', '2023-02-09 23:00:00'),
('MichaelHarris09', 'michael.harris09@example.com', '2023-02-09 08:30:00', '2023-02-10 09:30:00'),
('SarahMartin10', 'sarah.martin10@example.com', '2023-02-10 10:30:00', '2023-02-11 11:30:00');
# 4.批量插入100w数据
# 4.1 创建存储过程
DELIMITER $$
CREATE PROCEDURE InsertUsers()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 1000000 DO
INSERT INTO User (username, email, registrationDate, lastLogin) VALUES
(CONCAT('User', LPAD(i, 7, '0')), CONCAT('user', LPAD(i, 7, '0'), '@example.com'), NOW(), NOW());
SET i = i + 1;
END WHILE;
END$$
DELIMITER ;
# 4.2 调用存储过程,生成100w用户数据
CALL InsertUsers();
步骤1、安装好clickhouse数据库
https://ooolo.net/article/442.html
步骤2、安装etl中间件ClickHouse JDBC Bridge
Clickhouse-jdbc-bridge:是clickhouse提供的一个jdbc组件,用于通过JDBC的方式远程访问其他数据库表。
Clickhouse支持通过JDBC连接外部数据库,所有支持JDBC驱动的数据库都能直接接入clickhouse。要实现JDBC连接,clickhouse需要使用以后台进程运行的程序 clickhouse-jdbc-bridge。
JDBC表引擎可以对接Mysql、Postgresql、SQLite等数据库,但是JDBC表引擎不能单独完成对接工作,需要依赖clickhouse-jdbc-bridge的查询代理服务,clickhouse-jdbc-bridge是java语言实现的sql代理服务,项目地址为:
https://github.com/ClickHouse/clickhouse-jdbc-bridge #作者的资源库有直接可以去下载RPM安装包
https://clickhouse.com/docs/zh/engines/table-engines/integrations/jdbc # clickhouse官网的介绍
我们看懂架构图,则需要保证
ClickHouse JDBC Bridge第三方插件要能正常连接到2个数据库。我们可以把这个插件看出是2个数据库直接的桥梁!
达梦8数据库肯定是完整支持jdbc协议的,所以这个就存在2个数据库数据类型的一一映射关系,这个关系,就在ClickHouse JDBC Bridge维护。
步骤3、ClickHouse JDBC Bridge安装部署方法
(1)在官网:https://github.com/ClickHouse/clickhouse-jdbc-bridge,
下载源码程序到本地,通过在idea或者eclipse中执行mvn的clean、packge完成打包后,到打包目录里面找到clickhouse-jdbc-bridge-2.0.7-shaded.jar。
也可以下载编译好的包。。
(2)将clickhouse-jdbc-bridge-2.0.7-shaded.jar
放在Linux服务器的目录/data/clickhouse-jdbc-bridge下,并在该文件同级目录下新建两个目录:
config/datasources --存放数据源配置文件
drivers --jdbc驱动存放目录
(3)以连接JDBC访问Oracle 11g为例:
①在官网https://mvnrepository.com下载Oracle对应的驱动包ojdbc8-12.2.0.1.jar放置到/data/clickhouse-jdbc-bridge/drivers目录下。
②设置clickhouse-jdbc-bridge远程的数据库信息
mkdir -p config/datasources #创建config目录及其子目录
在datasources目录下创建数据源配置文件,msjdbc.json文件名尽量与配置中的datasource名一致,如下配置:
{
"msjdbc": {
"driverUrls": [
"/data/clickhouse-jdbc-bridge/drivers/ojdbc8-12.2.0.1.jar"
],
"driverClassName": "oracle.jdbc.driver.OracleDriver",
"jdbcUrl": "jdbc:oracle:thin:@远程连接的数据库ip:端口:服务名",
"username": "账号",
"password": "密码",
"connectionTestQuery": ""
}
}
当前Linux服务器的目录为:
|--data
|--clickhouse-jdbc-bridge
|--clickhouse-jdbc-bridge-2.0.7-shaded.jar
|--noput.out
|--drivers
|--ojdbc8-12.2.0.1.jar
|--config
|-- datasources
|-- msjdbc.json
③运行clickhouse-jdbc-bridge
nohup java -jar clickhouse-jdbc-bridge-2.0.7-shaded.jar &
tail -f nohup.out
成功启动:
④在clickhouse部署的那台服务器中
到/etc/clickhouse-server目录下的config.xml文件,找到以下代码,移除注释,并修改host为执行clickhouse-jdbc-bridge-2.0.7-shaded.jar的ip地址:
<jdbc_bridge>
<host>XX.XX.XX.XX</host>
<port>9019</port>
</jdbc_bridge>
保存之后,重启clickhoust服务
systemctl restart clickhouse-server
3、访问
(1)查看能成功访问的的链接:select * from jdbc('','show datasource')
(2)远程查询oracle的某个表
select from jdbc('msjdbc', 'select * from test_tb')
(3)直接远程连接
select from jdbc('jdbc:oracle:thin:账号/密码@xx.xx.xx.xx:端口/服务名', 'select * from test_tb')
1、更新包列表
sudo apt update
2、运行安装脚本
sudo apt-get install -y apt-transport-https ca-certificates dirmngr
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754
echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \
/etc/apt/sources.list.d/clickhouse.list
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client
sudo service clickhouse-server start
clickhouse-client # or "clickhouse-client --password" if you've set up a password.
3、设置密码
安装脚本会让你输入默认用户default的密码,我们可以直接回车不设置密码
安装成功
4、启动服务
sudo clickhouse-server restart
5、测试连接
clickhouse-client -m
-m参数是指开启多行输入,否则每次回车都会直接执行当前sql语句
--password xxx:如果有密码请加入此参数
6.远程连接
1、修改本地配置
nano /etc/clickhouse-server/config.xml
2、把注释掉的<listen_host>::</listen_host>取消注释,然后重启服务
service clickhouse-server restart
最近在实现一个导入功能,数据量在5w左右,后续会持续增长,使用的是easyExcel,读取文件性能较好,但因为每条数据都要做复杂的数据校验,导致整体响应时间在三四十分钟,虽然说导入不是直接和用户交互,但现在数据量不算很大的情况下,这个响应时间还是需要优化的,读取文件速度在几秒以内,主要是在数据校验这块,所以就使用了多线程去工作。
主要代码:
import java.util.concurrent.*;
public class Test{
private static final int threadNum = Runtime.getRuntime().availableProcessors()*2;// 获取cpu核数
public void syncData(List<NewRegionReq> regionList) throws ExecutionException, InterruptedException {
/**
* 多线程分析数据
*/
List<Future> list = new ArrayList<>();
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
int num = (regionList.size() / threadNum) + 1; //计算每个线程需要处理的记录数
for (int j = 0; j < threadNum; j++) {
//读取数据的起始位置
int startNum = j * num;
//读取数据的结束位置
int endNum = startNum + num;
//添加任务
Callable<String> task = new ThredQuery(regionList, startNum, endNum);
Future f = executor.submit(task);
//接受返回结果
list.add(f);
}
// 关闭线程池
executor.shutdown();
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
System.out.println(f.get().toString()); //OPTION + return 抛异常
}
newRegionMapper.save(regionList);
log.info("共导入数据 {} 行", regionList.size());
}
class ThredQuery implements Callable<String> {
private List<NewRegionReq> regionList;
private int startNum;
private int endNum;
public ThredQuery(List<NewRegionReq> regionList, int startNum, int endNum) {
this.regionList = regionList;
this.startNum = startNum;
this.endNum = endNum;
//System.out.println(startNum + "\t" + endNum);
}
@Override
public String call() {
for (int i = startNum; i < endNum; i++) {
//自己的业务逻辑
//if (i < regionList.size()) {
//}
}
return "成功";
}
}
}
思路:
1:先计算出查询总量,根据服务器的cpu核数,求每个线程应处理的条数
2.使用Callable返回结果,然后聚合数据,最后处理。
这里有个问题就是线程池合理的线程数你是如何考虑的?这也是之前面试遇到的一个题:
1.先看下机器的CPU核数,然后在设定具体参数:
System.out.println(Runtime.getRuntime().availableProcessors());
即CPU核数 = Runtime.getRuntime().availableProcessors()
2.分析下线程池处理的程序是CPU密集型,还是IO密集型
CPU密集型:核心线程数 = CPU核数 + 1
IO密集型:核心线程数 = CPU核数 * 2
乐观锁
乐观锁大多是基于数据版本(version)的记录机制实现。何为数据版本?增加一个版本标识,在基于数据库表的解决方案中,一般是通过未数据库表增加一个version,在读取数据时,将版本号一起读出,之后更新时,对此版本号+1。
此时将提交的版本数据与数据库表中对应记录的当前版本信息进行比对,如果提交的数据版本信息大于当前数据版本信息,则予以更新,否则认为是过期数据。
优点:乐观锁机制避免了长事务中的数据库加锁开销(操作员A和操作员B操作过程中,都没对数据库数据加锁),大大提升了大并发量下的系统整体性能表现
实现方式:两种方式
1、加一个字段 数据版本(version)记录机制
2、加一个字段用时间戳代替版本
使用场景:
高并发读取数据环境:当应用程序需要进行大量读取操作时,使用乐观锁可以提交系统性能和吞吐量。乐观锁在在大多数情况下不会锁定资源,减少了性能丢失;
数据一致性的保障:尽管乐观锁减少对资源的锁定,但他们仍然可以提供一定的数据一致性保护。如果多个数据同时读取同一数据,并进行修改,乐观锁能够保证只有最终成功更新的线程才能继续执行后续操作
避免长事务等待:如果程序使用了悲观锁,那么每个读取操作都需要先获得锁,这回导致长事务等待时间增加
注意:
乐观锁可以减少对资源的锁定,但在面对大量写入操作的情况下,数据冲突的可能性增大,这时可能需要更多的查询操作来重新获取数据以保持一致性
悲观锁
实现方式:
悲观锁是指在对数据进行操作之前,先加锁,保证在操作期间不会有其他用户修改改数据。
行级锁:在对某一行进行操作时,先获取该行的锁,其他用户需要等待该行锁的释放才能操作
表级锁:在对整个表进行操作时,先获取整个表的锁,其他用户需要等待整个表锁的释放才能进行操作
使用场景:
适用于频繁对数据修改和更新的场景,例如银行转账,订单处理
注:悲观锁用之前考虑清楚