日常開發中,對於操作ClickHouse中的數據,查詢是最常用的功能。本文通過代碼示例介紹使用JDBC方式連接ClickHouse查詢數據的兩種接口:Statement 和 PreparedStatement接口。
1. 引入ClickHouse驅動依賴包
筆者使用idea開發工程,首先創建maven項目,POM文件引入ClickHouse驅動依賴包。
<dependency>
<groupId>ru.yandex.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.2.4</version>
</dependency>
2. 編寫應用程序代碼查詢ClickHouse數據
JDBC連接ClickHouse的兩種接口主要區別是:Statement 接口不接受參數,PreparedStatement 接口運行時接受輸入的參數。
2.1 Statement接口
Statement可以正常訪問數據庫,適用於運行靜態 SQL 語句。 Statement 接口不接受參數。
import java.sql.*;
public class ClickHouseClient {
private static final String URL = "jdbc:clickhouse://<host>:<port>[/<database>]";
private static final String USER = "your username";
private static final String PASSWORD = "your password";
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 注冊JDBC驅動
Class.forName("ru.yandex.clickhouse.ClickHouseDriver");
// 打開連接
connection = DriverManager.getConnection(URL, USER, PASSWORD);
System.out.println("connected database successfully");
// 執行查詢
statement = connection.createStatement();
String sql = "select * from database.table_name limit 10";
ResultSet rs = statement.executeQuery(sql);
// 從結果集中提取數據
while (rs.next()){
String name = rs.getString("name");
float size = rs.getFloat("size");
System.out.println(name + " " + size);
}
rs.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 釋放資源
try {
if(statement!=null){
statement.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
2.2 PreparedStatement接口
PreparedStatement計划多次使用 SQL 語句, PreparedStatement 接口運行時接受輸入的參數。
import java.sql.*;
public class ClickHouseClient2 {
private static final String URL = "jdbc:clickhouse://<host>:<port>[/<database>]";
private static final String USER = "your username";
private static final String PASSWORD = "your password";
public static void main(String[] args) {
Connection connection = null;
// 注意這里使用的CK自己實現的PreparedStatement
ClickHousePreparedStatement statement = null;
try {
// 注冊JDBC驅動
Class.forName("ru.yandex.clickhouse.ClickHouseDriver");
// 打開連接
connection = DriverManager.getConnection(URL, USER, PASSWORD);
System.out.println("connected database successfully");
// 執行查詢
String sql = "select * from database.table_name where name = ?";
ClickHousePreparedStatement statement = (ClickHousePreparedStatement)connection.prepareStatement(sql);
statement.setString(1, "bjehp");
ResultSet rs = statement.executeQuery();
// 打印填充后的SQL語句(ck實現的PreparedStatement類包含了打印sql語句的方法)
System.out.println("execute: " + statement.asSql());
// 從結果集中提取數據
while (rs.next()){
String name = rs.getString("name");
float size = rs.getFloat("size");
System.out.println(name + " " + size);
}
rs.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 釋放資源
try {
if(statement!=null){
statement.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
這里要注意的是,在調用executeQuery方法時,Statement需要傳入sql參數,而PreparedStatement無需傳入sql參數,因為在創建PrepareStatement對象時,已經傳入sql參數。PrepareStatement可以使用占位符,會對傳入的sql進行預編譯,批處理比Statement效率高。
3. 參考資料
[1] JDBC教程 https://www.yiibai.com/jdbc/jdbc_quick_guide.html
[2] ClickHouse/clickhouse-jdbc https://github.com/ClickHouse/clickhouse-jdbc