I.はじめに
筆者の現在のプラットフォームは H2 を使用しています。利用シーンと使用方法は次のとおりです。H2 を使用する理由は次の 2 つです。
1. プラットフォームベースのプロジェクトでは、一般的にユーザーが一般的な実行にスクリプトまたは SQL を使用する必要があるため、管理クラス間の導入、依存関係、コンパイルを必要とせずにローコード プラットフォームを実現できます。ページ上でクリックして入力するだけで、クロスデータベース、クロスインスタンス、クロスサービスのデータ分析を実現するには、SQL 分析のためにデータを H2 に配置する必要がある場合があります。
2. データセットの記述が非常に複雑な場合、たとえば、セット a、b、および ab のオブジェクトには 1 対 1 対応のフィールド c があり、セット a の他のフィールドはそのセットに対応します。要素 b の下にぶら下がっています はい、この組み合わせは書くのが面倒ですが、H2 に格納し、sql と組み合わせて大きくて広いテーブルを形成すると、その後のロジックと分析の検証が容易になります。
2. H2の導入
H2 は、Java で書かれたオープンソースのリレーショナル データベース管理システム (RDBMS) です。これは組み込みデータベースとして設計されており、アプリケーションの一部として Java アプリケーションに直接埋め込むことも、スタンドアロン データベース サーバーとして実行することもできます。
H2 データベースには次の特徴があります。
1. 埋め込みデータベース: H2 データベースはライブラリ ファイルとして Java アプリケーションに埋め込むことができるため、アプリケーションは追加のデータベース サーバーを必要とせずにデータベースに直接アクセスして管理できます。
2. 複数のモードのサポート: H2 データベースは、メモリ モード、ディスク モード、混合モードを含む複数のモードをサポートします。メモリ モードはデータの一時保存に使用でき、ディスク モードはデータをディスクに保存でき、ハイブリッド モードはデータをメモリとディスクに保存できるため、より高いパフォーマンスと信頼性が得られます。
3. 複数のデータベース エンジンのサポート: H2 データベースは、組み込みモード、サーバー モード、クラスター モードを含む複数のデータベース エンジンをサポートします。組み込みモードは単一のアプリケーションに適しており、サーバー モードはデータベースを共有する複数のアプリケーションに適しており、クラスター モードは高可用性と負荷分散のシナリオに適しています。
4. 標準 SQL 構文のサポート: H2 データベースは、DDL (データ定義言語)、DML (データ操作言語)、DQL (データ クエリ言語) を含む標準 SQL 構文をサポートします。また、トランザクション、インデックス、トリガー、ストアド プロシージャ、ユーザー定義関数などの高度な機能もサポートします。
5. 軽量かつ高性能: H2 データベースは、起動時間が短く、メモリ消費量が少ない軽量のデータベース管理システムです。効率的なデータ ストレージとインデックス作成アルゴリズムを使用して、優れた読み取りおよび書き込みパフォーマンスを提供します。
6. クロスプラットフォームのサポート: H2 データベースは、Windows、Linux、Mac OS などの複数のプラットフォームで実行できます。
3、使用する
1、ポム
H2 の依存関係を導入するため、接続プールはすでにパッケージ化されていますが、結局のところ、H2 だけを使用して接続を開くことはできず、これによって消費されるハンドルとソケットはひどいものになります。リンクの再利用は必須です。
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.220</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
2.リンク
ここで、H2の依存パッケージを導入しておけば、実行時に自動で作成されます。
URL = "jdbc:h2:mem:testdb";
ユーザー名 = "sa";
パスワード = "";
インメモリデータベースなので、あまり使わないパッケージだと気軽にインポートできず、パッケージ単体では何をするのか分かりません。
public class H2ConnectionPool {
private static final String url = "jdbc:h2:mem:testdb";
private static final String username = "sa";
private static final String password = "";
private static final HikariConfig config = new HikariConfig();
private static final HikariDataSource dataSource;
static {
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
// 设置连接池大小,默认为10
config.setMaximumPoolSize(10);
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close() {
dataSource.close();
}
}
3. テーブルを作成する
リアルタイムで動的にテーブルを構築するには、テーブル名、フィールド名、タイプを知る必要があります。状況は 2 つあります。1 つはデータベースからチェックアウトされた ResultSet で、その後 List<HashMap<String,Object>> になります。変換、ハッシュマップはテーブルです データの各行がマップを形成します 最下層の一般的な変換を行った人はそれを知っているはずです 知らない学生は問題ありません 作成者とプライベートにチャットできます
この場合、マップに基づいてテーブル作成ステートメントを生成できます。
public static boolean createTable(String tableName, HashMap map) throws SQLException {
if (StringUtilsExt.isBlank(tableName)) {
return false;
}
if (map == null) {
return false;
}
Connection conn = null;
Statement stmt = null;
try {
// 连接到H2数据库
conn = H2ConnectionPool.getConnection();
// 创建Statement对象
stmt = conn.createStatement();
// 创建表的SQL语句
String sql = getCreateSql(tableName, map);
// 执行SQL语句
stmt.executeUpdate(sql);
} finally {
if (conn != null) {
conn.close();
}
if (stmt != null) {
stmt.close();
}
}
return true;
}
private static String getCreateSql(String tableName, HashMap map) {
StringBuilder builder = new StringBuilder("CREATE TABLE " + tableName + " (");
map.forEach((key, value) -> {
builder.append(key);
builder.append(" ");
if (value instanceof Long) {
builder.append("bigint");
} else if (value instanceof Integer) {
builder.append("int");
} else if (value instanceof String) {
builder.append("varchar");
} else if (value instanceof BigDecimal) {
builder.append("decimal");
} else if (value instanceof Boolean) {
builder.append("int");
} else if (value instanceof Timestamp) {
builder.append("datetime");
}
builder.append(",");
});
builder.deleteCharAt(builder.length() - 1);
// 创建表的SQL语句
return builder + ")";
}
2 番目のケースは、インターフェイスを呼び出すか、他のデータをチェックするときに List<T> を取得し、リフレクションに従ってフィールド名と T の値を取得する必要がある場合です。
public boolean createTableByT(String tableName, T t) throws SQLException {
if (StringUtilsExt.isBlank(tableName)) {
return false;
}
if (t == null) {
return false;
}
Connection conn = null;
Statement stmt = null;
try {
// 连接到H2数据库
conn = H2ConnectionPool.getConnection();
// 创建Statement对象
stmt = conn.createStatement();
// 创建表的SQL语句
String sql = getCreateSqlByT(tableName, t);
// 执行SQL语句
stmt.executeUpdate(sql);
} finally {
if (conn != null) {
conn.close();
}
if (stmt != null) {
stmt.close();
}
}
return true;
}
private String getCreateSqlByT(String tableName, T t) {
StringBuilder builder = new StringBuilder("CREATE TABLE " + tableName + " (");
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
Object fieldValue = null;
try {
fieldValue = field.get(t);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
builder.append(fieldName);
builder.append(" ");
if (fieldValue instanceof Long) {
builder.append("bigint");
} else if (fieldValue instanceof Integer) {
builder.append("int");
} else if (fieldValue instanceof String) {
builder.append("varchar");
} else if (fieldValue instanceof BigDecimal) {
builder.append("decimal");
} else if (fieldValue instanceof Boolean) {
builder.append("int");
} else if (fieldValue instanceof Timestamp) {
builder.append("datetime");
}
}
builder.deleteCharAt(builder.length() - 1);
// 创建表的SQL语句
return builder + ")";
}
4. データを挿入する
1 つ目は、データベース変換に従ってマップを挿入することです。
public static boolean insertByHashMap(String tableName, List<HashMap> listMap) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
try {
// 连接到H2数据库
connection = H2ConnectionPool.getConnection();
HashMap<String, Integer> indexMap = new HashMap<>(listMap.get(0).size());
String sql = getInsertSql(tableName, listMap.get(0), indexMap);
statement = connection.prepareStatement(sql);
setValue(listMap, indexMap, statement);
// 执行批处理
int[] rowsInserted = statement.executeBatch();
if (rowsInserted.length != listMap.size()) {
return false;
}
} finally {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
}
return true;
}
private static void setValue(List<HashMap> listMap, HashMap<String, Integer> indexMap,
PreparedStatement statement) throws SQLException {
// 批量插入数据
for (HashMap m : listMap) {
m.forEach((key, value) -> {
if (value instanceof Long) {
try {
statement.setLong(indexMap.get(key), (Long)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Integer) {
try {
statement.setInt(indexMap.get(key), (Integer)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof String) {
try {
statement.setString(indexMap.get(key), (String)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof BigDecimal) {
try {
statement.setBigDecimal(indexMap.get(key), (BigDecimal)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Boolean) {
int flag = (Boolean) value ? 1 : 0;
try {
statement.setInt(indexMap.get(key), flag);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Byte) {
try {
statement.setByte(indexMap.get(key), (Byte) value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
});
statement.addBatch();
}
}
private static String getInsertSql(String tableName, HashMap map, HashMap<String, Integer> indexMap) {
StringBuilder builder = new StringBuilder("INSERT INTO " + tableName + " (");
StringBuilder builder2 = new StringBuilder(" VALUES (");
AtomicInteger index = new AtomicInteger(1);
map.forEach((key, value) -> {
builder.append(key);
builder.append(" ");
builder.append(",");
builder2.append("?");
builder2.append(" ");
builder2.append(",");
indexMap.put((String)key, index.get());
index.getAndIncrement();
});
builder.deleteCharAt(builder.length() - 1);
builder2.deleteCharAt(builder2.length() - 1);
// 插入表的SQL语句
return builder + ")" + builder2 + ")";
}
2 つ目は、リストに従ってデータを挿入することです
public boolean insertByList(String tableName, List<T> list) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
try {
// 连接到H2数据库
connection = H2ConnectionPool.getConnection();
HashMap<String, Integer> indexMap = new HashMap<>();
String sql = getInsertSqlByList(tableName, list.get(0), indexMap);
statement = connection.prepareStatement(sql);
setValueByList(list, indexMap, statement);
// 执行批处理
int[] rowsInserted = statement.executeBatch();
if (rowsInserted.length != list.size()) {
return false;
}
} finally {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
}
return true;
}
private void setValueByList(List<T> list, HashMap<String, Integer> indexMap,
PreparedStatement statement) throws SQLException {
// 批量插入数据
for (T t : list) {
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String key = field.getName();
Object value = null;
try {
value = field.get(t);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (value instanceof Long) {
try {
statement.setLong(indexMap.get(key), (Long)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Integer) {
try {
statement.setInt(indexMap.get(key), (Integer)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof String) {
try {
statement.setString(indexMap.get(key), (String)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof BigDecimal) {
try {
statement.setBigDecimal(indexMap.get(key), (BigDecimal)value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Boolean) {
int flag = (Boolean) value ? 1 : 0;
try {
statement.setInt(indexMap.get(key), flag);
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else if (value instanceof Byte) {
try {
statement.setByte(indexMap.get(key), (Byte) value);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
statement.addBatch();
}
}
private String getInsertSqlByList(String tableName, T t, HashMap<String, Integer> indexMap) {
StringBuilder builder = new StringBuilder("INSERT INTO " + tableName + " (");
StringBuilder builder2 = new StringBuilder(" VALUES (");
AtomicInteger index = new AtomicInteger(1);
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
builder.append(fieldName);
builder.append(" ");
builder.append(",");
builder2.append("?");
builder2.append(" ");
builder2.append(",");
indexMap.put(fieldName, index.get());
index.getAndIncrement();
}
builder.deleteCharAt(builder.length() - 1);
builder2.deleteCharAt(builder2.length() - 1);
// 插入表的SQL语句
return builder + ")" + builder2 + ")";
}
5. クエリ
クエリするものは何もありません。SQL を実行するだけです。ここでは、データベース クエリからの ResultSet が一般的な関数によって変換されていることがわかります。
public static List<HashMap> query(String sql) throws SQLException {
// 创建List对象来存储查询结果
List<HashMap> resultList = new ArrayList<>();
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
try {
connection = H2ConnectionPool.getConnection();
// 执行查询
stmt = connection.createStatement();
rs = stmt.executeQuery(sql);
// 获取结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
// 处理查询结果
while (rs.next()) {
HashMap<String, Object> map = new HashMap<>(columnCount);
for (int i = 1; i <= columnCount; i++) {
map.put(metaData.getColumnName(i), rs.getObject(i));
}
resultList.add(map);
}
} finally {
if (connection != null) {
connection.close();
}
if (stmt != null) {
stmt.close();
}
if (rs != null) {
rs.close();
}
}
return resultList;
}
6. テーブルの削除
public static boolean dropTable(String tableName) throws SQLException {
if (StringUtilsExt.isBlank(tableName)) {
return false;
}
Connection conn = null;
Statement stmt = null;
try {
// 连接到H2数据库
conn = H2ConnectionPool.getConnection();
// 创建Statement对象
stmt = conn.createStatement();
String sql = "DROP TABLE " + tableName;
stmt.executeUpdate(sql);
} finally {
if (conn != null) {
conn.close();
}
if (stmt != null) {
stmt.close();
}
}
return true;
}
4. まとめ
プラットフォームの構築ではローコードと汎用性を考慮する必要があります, そうしないとソース コードがあらゆる場所で変更されてしまいます. ここで著者は、汎用化されたライブラリ間、インスタンス間、およびサービス間のデータ分析とロジックを実行するための H2 を紹介します。議論することを歓迎します!