Java-低代码平台使用H2内存数据库

一、引言

        作者目前在做的平台使用到了H2,这里介绍下使用场景、使用方式,出于以下两个原因会使用H2:

        1、平台化的项目一般是用户使用脚本或者sql进行通用的执行,这样可以实现低代码平台,不需要管理类之间的引入、依赖、编译,页面上点点点和输入就可以了,所以很多时候需要把数据放入H2进行sql解析实现跨库、跨实例、跨服务的数据分析

        2、在数据集合写起来非常复杂的时候,举个例子:集合a、b,ab的对象有字段c是一一对应的,然后集合a的其他字段和b元素下面挂着的集合又是对应的,这个组合写起来就很麻烦,但是如果存入H2用sql进行关联组合,形成一张大宽表,那么接下来的逻辑和分析验证就会好做。

二、H2介绍

        H2是一个用Java编写的开源关系型数据库管理系统(RDBMS)。它被设计为一个嵌入式数据库,可以作为应用程序的一部分直接嵌入到Java应用程序中使用,也可以作为独立的数据库服务器运行。

        H2数据库具有以下特点:

1. 嵌入式数据库:H2数据库可以作为一个库文件嵌入到Java应用程序中,这样应用程序可以直接访问和管理数据库,而无需额外的数据库服务器。
2. 支持多种模式:H2数据库支持多种模式,包括内存模式、磁盘模式和混合模式。内存模式可以用于临时数据存储,磁盘模式可以持久化数据到磁盘,混合模式可以将数据存储在内存和磁盘上,提供更高的性能和可靠性。
3. 支持多种数据库引擎:H2数据库支持多种数据库引擎,包括嵌入式模式、服务器模式和集群模式。嵌入式模式适用于单个应用程序,服务器模式适用于多个应用程序共享数据库,集群模式适用于高可用性和负载均衡的场景。
4. 支持标准SQL语法:H2数据库支持标准的SQL语法,包括DDL(数据定义语言)、DML(数据操作语言)和DQL(数据查询语言)。它还支持事务、索引、触发器、存储过程和用户定义函数等高级特性。
5. 轻量级和高性能:H2数据库是一个轻量级的数据库管理系统,具有快速的启动时间和低内存消耗。它采用了高效的数据存储和索引算法,提供了优秀的读写性能。
6. 跨平台支持:H2数据库可以在多个平台上运行,包括Windows、Linux和Mac OS等。

三、使用

1、Pom

        要引入H2的依赖,还有链接池有已经封装好的,毕竟不能用一下h2就开一个链接,这个消耗的句柄和socket就可怕了。链接复用是必须的。

<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";

        username = "sa";
        password = "";

        的内存数据库,所以要是不用很多包是不能随便引入的,你不知道这些包都自己做了什么事。

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);// 设置连接池大小,默认为10config.setMaximumPoolSize(10);dataSource = new HikariDataSource(config);}public static Connection getConnection() throws SQLException {return dataSource.getConnection();}public static void close() {dataSource.close();}
}

3、建表

        实时动态的建表就需要知道表名称,字段名称和类型,有两种情况,一种是从数据库查出来的ResultSet,经过转化之后会变成List<HashMap<String,Object>>,hashmap是表的字段名和值,每行数据形成了一个map,做过底层通用转化的应该都知道,不清楚的同学也没关系,可以私聊作者。

        这种情况就可以根据map生成建表语句。

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 + ")";}

        第二种情况是调用接口或者查其他一些数据的时候,得到的是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、插数据

        第一种是根据数据库转化的map插入

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 + ")";}

        第二种就是根据list插入数据 

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;}

四、总结

        平台化的建设要考虑低代码和通用,不然源码处处改就很完蛋,这里作者介绍了H2做通用化跨库、跨实例、跨服务数据分析和逻辑,有兴趣的同学欢迎讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1380080.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

制造业企业数字化转型之设备数据采集

导 读 ( 文/ 1894 ) 随着信息技术的快速发展和制造业的转型升级&#xff0c;企业数字化转型已成为保持竞争力和实现可持续发展的关键。在数字化转型过程中&#xff0c;设备数据采集作为重要的一环&#xff0c;发挥着关键的作用。设备数据采集通过收集、分析和利用设备所产生的数…

怎样找回e盘删除的文件夹?分享三种恢复方法

我们都知道&#xff0c;电脑可以划分多个区域来存储数据&#xff0c;例如C盘、D盘、E盘、F盘等&#xff0c;而不论是存储在哪个磁盘&#xff0c;都容易出现文件丢失的问题&#xff0c;那么电脑e盘文件夹删除了怎么恢复呢&#xff1f;下面小编分享一些方法&#xff0c;一起来看下…

C#多线程开发详解

C#多线程开发详解 持续更新中。。。。。一、为什么要使用多线程开发1.提高性能2.响应性3.资源利用4.任务分解5.并行计算6.实时处理 二、多线程开发缺点1.竞态条件2.死锁和饥饿3.调试复杂性4.上下文切换开销5.线程安全性 三、多线程开发涉及的相关概念常用概念(1)lock(2)查看当前…

基于计算机的色彩描述

计算机中的色彩描述方法主要有RGB、CMY、Lab、HSB、sRGB、YUV、YCbCr、YIQ等。 CMYK色彩模式主要用于使用色料呈色的彩色设备。CMYK模式实质指的是再现色彩时单位面积上含C、M、Y、K点的百分比。 Lab色彩模式是建立在CIE 1976 L*a*b 颜色空间基础上的色彩模式&#xff0c;包含…

HSV色彩范围

一般对颜色空间的图像进行有效处理都是在HSV空间进行的&#xff0c;然后对于基本色中对应的HSV分量需要给定一个严格的范围&#xff0c;下面是通过实验计算的模糊范围&#xff08;准确的范围在网上都没有给出&#xff09;。 H: 0 — 180 S: 0 — 255 V: 0 — 255 此处把部分红色…

OBS推流时的视频色彩相关参数设置

在使用OBS进行推流直播时&#xff0c;特别是采集卡采集摄像机信号进行推流直播时&#xff0c;我们可能会遇到这样的问题&#xff1a;   1.为什么流信号与源信号相比有色彩偏差&#xff1f;   2.明暗对比较大的视频信号&#xff0c;比如有树荫和太阳&#xff0c;在摄像机上可…

视频产生的本质及色彩空间:RGB 和 YUV

一、前言 在前面几篇文章中&#xff0c;我们完成了音频相关基础知识的学习&#xff0c;从今天开始&#xff0c;我们要暂别音频&#xff0c;继续学习视频相关基础内容。 虽说声音在我们日常的生活、工作、娱乐过程中&#xff0c;发挥着不可替代的作用&#xff0c;但人们常说&a…

彩色图像色彩模型

彩色图像处理可分为两个主要领域&#xff1a;全彩色处理和伪彩色处理。全彩色处理通常要求图像用全彩色传感器获取&#xff0c;伪彩色处理是对一种特定的单色灰度活灰度范围赋予一种颜色。 定义&#xff1a; 亮度&#xff1a;具体表达了无色的强度概念&#xff0c;显示图像的…

ArcGIS基础:分级色彩和换行标注(VbCrLf)操作(以制作社会经济分析图为例)

我们需要用到的实验数据如下&#xff1a; 村&#xff08;点数据和面数据&#xff09;&#xff0c;主要属性就是【人口数】、【经济总量】&#xff0c;如下图所示。 点数据的要使用的两个字段【人口数】、【经济总量】如下&#xff1a; 面数据的要使用的两个字段【人口数】、【…

计算机图像处理入门基础知识——色域,色度图,色彩空间和色彩管理

作者&#xff1a;❄️固态二氧化碳❄️ (主页) 链接&#xff1a;(原创)计算机图像处理入门基础知识——色域,色度图,色彩空间和色彩管理 - 固态二氧化碳的博客 - CSDN博客 来源&#xff1a;CSDN博客 发表时间&#xff1a;2020年06月03日 18:36:36 著作权归作者所有。商业转载请…

Photoshop CS6 实例之用色彩范围抠图并合成背景

素材 素材1 素材2 步骤 打开素材1&#xff0c;如下所示: 执行“选择>色彩范围”菜单命令&#xff0c;然后在弹出的“色彩范围”对话框中设置“选择”为“取样颜色”&#xff0c;然后勾选“本地化颜色簇”选项&#xff0c;并设置“颜色容差”为200&#xff0c;如下所示设置…

选择技术之颜色范围

许多人一直困惑不知道如何在PS中调色&#xff0c;殊不知&#xff0c;调色的前提条件是要选中要调色的对象。 色彩范围就是Photoshop中的一个非常好用的选择命令。 菜单&#xff1a;选择/色彩范围 色彩范围的主要用途 1、选择某个对象 2、选择某种颜色 3、选择人像皮肤 4、选择照…

Honeywell EPKS 系统通用备份维护手册

Document Name EPKS系统通用备份维护手册 Version 01 Date November 9, 2021 Reference System Backup 1. 介绍 本文档以EPKS R511为基础&#xff0c;根据Honeywell标准手册的…

惠普微型计算机怎么装机,详解hp如何安装系统

最近有位小伙伴在后台私信问小编说&#xff0c;惠普电脑怎么重装操作。其实不瞒大家说当我看到该问题时&#xff0c;是有略带吃惊的&#xff0c;因为小编也都不太清楚这个方面的内容&#xff0c;不过在经过我的一番了解后这才得知惠普电脑重装系统的方法。所以今天小编就来给大…

HP滤波

Hodrick Prescott Filter &#xff08;HP滤波&#xff09;

DCHP通讯协议

从通讯TCP/IP的构成传输&#xff0c;到IP地址的分类&#xff0c;再到局域网与广域网的设置。 通讯协议的构成 概述IPDHCP-设定动态IPDNS 数据的流动广域网 网关局域网 交换机NAT桥接模式实操 概述 前景知识&#xff1a;虚拟机与工艺库管理 扩展&#xff1a;NAT模式的实操。 1…

【网络编程(二)】NIO快速入门

NIO Java NIO 三大核心组件 Buffer&#xff08;缓冲区&#xff09;&#xff1a;每个客户端连接都会对应一个Buffer&#xff0c;读写数据通过缓冲区读写。Channel&#xff08;通道&#xff09;&#xff1a;每个channel用于连接Buffer和Selector&#xff0c;通道可以进行双向读…

Vue+SpringBoot后台管理系统:Vue3+TypeScript项目搭建(一)

写在开始:一个搬砖程序员的随缘记录文章目录 一、Node安装二、Vue CLI安装三、相关的版本四、创建Vue3TypeScript项目五、Vue项目初始化六、项目启动 一、Node安装 查看Note版本 node -v查看npm版本 npm -v然后将npm升级至最新版本 npm -g install npm将npm下载源换至http:…

docker安装Nacos的《小白专用》详细教程

1.CentOS安装docker 安装docker yum -y install docker 设置开机自启 systemctl enable docker 启动docker systemctl start docker 查看docker当前的版本 docker version做到这里呢基本上你的docker就安装了一大部分了&#xff0c;当然也有那些无法安装的人&#xff0c;那我建…

PHP最简单自定义自己的框架view使用引入smarty(8)--自定义的框架完成

1、实现效果。引入smarty&#xff0c; 实现assign和 display 2、下载smarty&#xff0c;创建缓存目录cache和扩展extend 点击下面查看具体下载使用&#xff0c;下载改名后放到extend PHP之Smarty使用以及框架display和assign原理_PHP隔壁老王邻居的博客-CSDN博客 3、当前控…