8.java程序员必知必会类库之嵌入式SQL数据库

news2024/11/16 23:37:38

前言

嵌入式内存数据库,作为嵌入到应用内部的数据库,在正常生产业务流程中使用不多。现在一般公司通用架构都是应用和数据分离,解耦数据和应用。但是,在某些特殊场景中,这种嵌入式数据库是比较好的选择。

  1. 在某些单元测试的时候,如果需要一个数据库验证你的SQL脚本,此时H2就是一个很好的选择
  2. 应用需要通过SQL计算大批量指标,这些指标如果放在mysql这种可能会很慢,通过内存计算管理会极大提高效率
  3. 开发的程序里面包含很多指标计算逻辑(通过SQL计算),当需要导出作为依赖包运行的时候,此时内存数据库就是一个很好的选择

1. H2

1.1 简介

  1. h2采用纯Java编写,因此不受平台的限制。
  2. h2只有一个jar文件,十分适合作为嵌入式数据库试用。
  3. h2提供了一个十分方便的web控制台用于操作和管理数据库内容。
  4. 开源代码,方便修改,自定义函数等需求

1.2 使用

1.2.1 pom坐标导入

<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.210</version>
    <scope>test</scope>
</dependency>

1.2.2 demo

1.2.2.1 H2连接工具类

public class H2DbUtil {
    private static final ArrayBlockingQueue<Connection> CONNECTION_POOL = new ArrayBlockingQueue<>(50);

    static {
        try {
            synchronized (CONNECTION_POOL) {
                Class.forName("org.h2.Driver");
                //String url = "jdbc:h2:mem:pbocdb;MODE=MySQL;DB_CLOSE_DELAY=-1;MULTI_THREADED=1;MV_STORE=FALSE;LOG=0;REDO_LOG_BINARY=0;UNDO_LOG=0";
                String url = "jdbc:h2:~/H2Database/h2/bin/test";

                for (int i = 0; i < 10; i++) {
                    CONNECTION_POOL.add(DriverManager.getConnection(url, "sa", ""));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static List<Map<String, Object>> execute(String sql, String reportNo) throws Exception {
        List<Map<String, Object>> records = new ArrayList<>();
        Connection connection = null;
        try {
            connection = CONNECTION_POOL.take();
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            int count = preparedStatement.getParameterMetaData().getParameterCount();
            for (int i = 1; i <= count; i++) {
                preparedStatement.setString(i, reportNo);
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            ResultSetMetaData md = resultSet.getMetaData();
            int columnCount = md.getColumnCount();

            // 数据
            Map<String, Object> rowData;
            while (resultSet.next()) {
                rowData = new HashMap<>(columnCount);
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = md.getColumnLabel(i).toLowerCase().replaceAll("[ ()'`\r\n\t]","");
                    columnName = columnName.replaceAll("public\\.", "");
                    rowData.put(columnName, resultSet.getObject(i));
                }
                records.add(rowData);
            }
        } finally {
            if (connection != null) {
                release(connection);
            }
        }
        return records;
    }

    public static Connection getConnection() throws Exception {
        return CONNECTION_POOL.take();
    }

    public static void release(Connection connection){
        if (connection != null) {
            try {
                CONNECTION_POOL.put(connection);
            } catch (Exception ignored) {
            }
        }
    }

}

1.2.2.2 测试类

通过H2执行脚本示例如下:

@Test
public void testH2() throws Exception{

    Connection connection = H2DbUtil.getConnection();
    Statement stmt = connection.createStatement();
    // 如果存在USERS表就先删除USERS表
    stmt.execute("DROP TABLE IF EXISTS USERS");
    // 创建users表
    stmt.execute("create table users("
            + "    id int primary key,"
            + "    name varchar(40),"
            + "    password varchar(40))");
    // 新增
    stmt.executeUpdate("INSERT INTO users VALUES(1,'张三','12')");
    stmt.executeUpdate("INSERT INTO users VALUES(2,'李四','34')");
    stmt.executeUpdate("INSERT INTO users VALUES(3,'王五','56')");
    stmt.executeUpdate("INSERT INTO users VALUES(4,'麻六','78')");
    stmt.executeUpdate("INSERT INTO users VALUES(5,'邹七','90')");
    List<Map<String, Object>> execute = H2DbUtil.execute("select * from  users where  id = ?", "1");
    //遍历结果集
    for (Map<String, Object> objectMap : execute) {
        System.out.println(objectMap.toString());
    }
    H2DbUtil.release(connection);
}

代码输出结果:

{name=张三, password=12, id=1}

1.3 界面展示

1.3.1 新建一个空的springboot web项目

pom文件如下:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1.3.2 springboot配置文件添加如下内容

server.port=8080
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.web-allow-others=true

1.3.3 访问页面

启动项目,访问地址 : http://localhost:8080/h2-console/login.jsp
可以看到如下界面:
在这里插入图片描述
点击连接,进入展示如下,可以看到界面类似我们常用的数据库连接客户端navicat。可以在窗口执行数据的增删改查,但是注意这数据都是在内存中,应用重启,数据会丢失。
在这里插入图片描述

1.4 注意事项

  1. H2 维护的数据都是在内存中,应用重启数据会丢失
  2. H2 SQL语法和mysql上面极度相似,但是在具体的函数处理上面,两边处理的结果可能会有一些细微的差异,如果你想在H2上面跑MySql的脚本,要提前感知可能的差异性
  3. 如果比对出来不一致,可以将源码拉下来调整相关源码,做兼容处理,但是这只能查漏补缺,只有发现不一致,针对性调整。比如发现日期函数处理和mysql有差异,那可以调整源码对应函数做兼容,但是这没法发现所有不一致性。
  4. 在界面上,可能会误删除连接配置项,然后项目重启,浏览器重启还是无法连接H2,这是因为删除信息会写到本地磁盘里面, 需要删除window用户目录下面的h2.server.properties文件,liunx 是home文件下。

1.5 进阶

1.5.1 自定义函数

1.5.1.1 自定义函数类

public class CustomFunction {

    public static String hi() {
        return "hello";
    }

    public static String my_uuid() {
        return "test" + UUID.randomUUID().toString();
    }

    public static String now() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        String dateStr = simpleDateFormat.format(date);
        return dateStr;
    }

    public static String getIp() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            // 获得本机IP
            return addr.getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return "未知的IP地址";
        }
    }

    public static String date_format(String date, String pattern) {
        if (date != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            try {
                Date temp = sdf.parse(date);
                return sdf.format(temp);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return "";
    }
}

1.5.1.2 测试类

@BeforeClass
public static void testH2Function() throws Exception {

    Connection connection = H2DbUtil.getConnection();
    // 0、注册hi函数的SQL语句
    String sql0 = "CREATE ALIAS IF NOT EXISTS hello FOR \"com.wanlong.memoryDB.h2.CustomFunction.hi\"";
    // 1、注册uuid函数的SQL语句
    String sql1 = "CREATE ALIAS IF NOT EXISTS my_uuid FOR \"com.wanlong.memoryDB.h2.CustomFunction.my_uuid\"";
    // 2、注册currentTime函数的SQL语句
    String sql2 = "CREATE ALIAS IF NOT EXISTS currentTime FOR \"com.wanlong.memoryDB.h2.CustomFunction.now\"";
    // 3、注册IP函数的SQL语句
    String sql3 = "CREATE ALIAS IF NOT EXISTS IP FOR \"com.wanlong.memoryDB.h2.CustomFunction.getIp\"";
    // 4、注册date_format函数的SQL语句
    String sql4 = "CREATE ALIAS IF NOT EXISTS date_format FOR \"com.wanlong.memoryDB.h2.CustomFunction.date_format\"";

    Statement stmt = null;

    // 获取Statement对象
    stmt = connection.createStatement();
    // 添加要执行的SQL
    stmt.addBatch(sql0);
    stmt.addBatch(sql1);
    stmt.addBatch(sql2);
    stmt.addBatch(sql3);
    stmt.addBatch(sql4);
    // 批量执行
    stmt.executeBatch();
    System.out.println("H2数据库扩展函数注册成功!");
    H2DbUtil.release(connection);
}


@Test
public void testCustomeFuntion() throws Exception {
    Connection connection = H2DbUtil.getConnection();
    Statement stmt = connection.createStatement();
    // 如果存在USERS表就先删除USERS表
    List<Map<String, Object>> execute = H2DbUtil.execute("select my_uuid()", "1");
    for (Map<String, Object> objectMap : execute) {
        System.out.println(objectMap.toString());
    }
    H2DbUtil.release(connection);
}

1.5.2.3 代码运行结果

可以看到,自定义函数执行了

 H2数据库扩展函数注册成功!
{my_uuid=test90899962-93e2-4f5e-be16-d6ca52c3a98c}

2 参考文献:

H2官网
H2参考博客

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

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

相关文章

如何在开发阶段保证软件工程质量 (程序员要做些什么)

前言 大家常说&#xff1a;“代码和人&#xff0c;有一个能跑就行”&#xff0c;但这并不意味着我们可以放弃职业道德。与土木工程一样&#xff0c;软件工程也需要一些可度量的指标来衡量产品的交付质量。一个高质量的软件绝对不能只靠测试人员来保证&#xff0c;更不能相信程…

在SaleSmartly(ss客服)中为Messenger 提供无缝支持体验

客户希望您在他们所在的地方与他们见面&#xff0c;这意味着打开多个沟通渠道。但是&#xff0c;当您通过电子邮件、实时聊天、社交等方式进行通信时&#xff0c;对话很容易丢失、被忽视和杂乱无章。 而Messenger的受欢迎程度&#xff0c;以及Meta的无所不在&#xff0c;使Face…

每日学术速递4.18

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Inpaint Anything: Segment Anything Meets Image Inpainting 标题&#xff1a;Inpaint Anything&#xff1a;分割任何东西满足图像修复 作者&#xff1a;Tao Yu, Runseng Feng, R…

企业用户如何选择合适的服务器配置方法教程

随着互联网信息的飞速发展&#xff0c;任何企业都脱离不了互联网&#xff0c;越来越多的企业都通过互联网实施无纸化的办公&#xff0c;互联网推广一体化整体型推广、互联网电子商务。中小型企业网站如何选购云服务器配置呢&#xff1f;但是&#xff0c;实现这些的最最基础的条…

ai改写句子软件-ai改写

AI免费伪原创&#xff1a;助力网站内容升级 您是否曾经为网站优化而烦恼&#xff0c;无论是内容更新还是SEO优化&#xff0c;都需要大量的时间和精力。但是&#xff0c;您是否知道&#xff0c;现在有一款能够使用AI技术来帮助您完成这些任务&#xff0c;而且还是免费的呢&…

【Git 学习】

Git 学习 一、Git的使用1. Git下载安装2. Git 命令3. Git推送代码步骤4. Git基本工作流程5. Git历史版本切换6. Git分支管理6.1 创建新分支6.2 切换分支6.3 合并分支6.4 删除分支 7. 远程仓库的工作流程7.1 具体流程 8.推送到远程仓库9. 代码冲突问题10. IDEA 集成Git10.1 版本…

说说webpack的构建流程?

① 初始化流程 从配置文件和 Shell 语句中读取与合并参数&#xff0c;并初始化需要使用的插件和配置插件等执行环境所需要的参数。 配置文件默认下为 webpack.config.js&#xff0c;也可以通过命令的形式指定配置文件&#xff1b; 主要作用是用于激活webpack的加载项和插件&am…

手写axios源码系列一:axios核心知识点

文章目录 axios的核心功能1、axios 函数对象2、dispatchRequest 发送请求3、interceptors 拦截器4、cancelToken 取消请求 最近从头搭建了一个vue小项目&#xff0c;想使用 axios 作为请求接口的第三方库。结果使用了 axios 这么长时间&#xff0c;想封装一下 axios &#xff0…

Nacos2.2.2开启鉴权配置

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、更改application.properties中的配置二、修改配置 前言 最近公司开启了一个新的电商项目&#xff0c;项目中用到了Naocs作为注册中心和配置中心&#xff0…

WindowsUbuntu下python程序打包

Python程序的运行必须要有Python的环境&#xff0c;但是程序编出来是用的&#xff0c;如果是给别人用&#xff0c;而他/她的电脑上又没有Python程序运行的环境怎么办呢&#xff1f;总不能让他/她去安装一个吧&#xff1f;这时我们就要将Python程序打包为exe可执行文件&#xff…

【文章学习系列之模型】PatchTST

本章内容 文章概况模型结构实验结果长期预测表征学习 消融实验分块和通道独立性不同的回顾窗口 总结 文章概况 《A Time Series is Worth 64 Words: Long-term Forecasting with Transformers》是2023年发表于ICLR的一篇文章。该文章借鉴了计算机视觉领域的Vision Transformer…

树形DP分析

树形dp 简单来说树形 d p 就是在树上做 d p 罢了 简单来说树形dp就是在树上做dp罢了 简单来说树形dp就是在树上做dp罢了 树嘛&#xff0c;就要符合除了根节点外每个节点只有一个父节点 树嘛&#xff0c;就要符合除了根节点外每个节点只有一个父节点 树嘛&#xff0c;就要符合除…

# 从车灯模组的角度聊聊信息安全需求

文章目录 1. 前言2.信息安全需求2.1 硬件安全2.1.1 接口安全2.1.2 主板安全2.1.3 芯片安全 2.3 系统安全2.3.1 代码安全2.3.2 软件读保护2.3.3 安全启动2.3.4 安全升级2.3.5 安全诊断 2.4 通信安全2.5 数据安全 3. 安全启动流程3.1 基于签名技术的安全启动方案3.2 基于对称签名…

netty源码阅读--处理客户端请求

背景 netty是一个非常成熟的NIO框架&#xff0c;众多apache的顶级项目底层通信框架都是用的是netty,本系列博客主要是记录自己复习netty源码的过程&#xff0c;重在理解netty的关键如&#xff1a;如何启动&#xff0c;如何接受网络数据、netty的内存管理机制以及编解码器等&am…

Python学习笔记--面向对象

未完待续。。。。。 &#xff08;一&#xff09;面向对象的基本概念 我们之前学习的编程方式就是面向过程的 面相过程和面相对象&#xff0c;是两种不同的编程方式 对比面向过程的特点&#xff0c;可以更好地了解什么是面向对象 1.1过程和函数 过程是早期的一个编程概念 过程…

4.3 分段低次插值

学习目标&#xff1a; 如果我要学习分段低次插值&#xff0c;我可能会采取以下几个步骤&#xff1a; 学习插值的基本概念和方法 在学习分段低次插值之前&#xff0c;我需要先掌握插值的基本概念和方法&#xff0c;例如拉格朗日插值、牛顿插值和内维尔方法等。这些基础知识可…

C#调用C++封装的SDK库(dll动态库)——上

C#调用C封装的SDK库(dll动态库)——上 一、C封装库 通过前几篇文章&#xff0c;我们封装了C的动态DLL库&#xff0c;有Qt版的&#xff0c;有C版的&#xff0c;当然还有介绍了Pimpl模式在SDK封装中的使用&#xff1a; Qt创建SDK VS创建SDK Pimple在SDK封装中的应用 但是&a…

关于逻辑回归的几个函数

写作业时重新理了下&#xff0c;如果有问题欢迎指正&#xff01; 说是回归&#xff0c;其实就是个分类&#xff0c;用【0&#xff0c;1】标记结果y是录取还是录取&#xff0c;而影响结果y的就是X(x0,x1,…xn-1)。怎么判断结果y是0还是1用到的是逻辑回归函数&#xff08;也叫假…

java企业级信息系统开发学习笔记05 初探Spring AOP

文章目录 一、学习目标二、Spring AOP&#xff08;一&#xff09;AOP基本含义&#xff08;二&#xff09;AOP基本作用&#xff08;三&#xff09;AOP和OOP对比&#xff08;四&#xff09;AOP使用方式&#xff08;五&#xff09;AOP基本概念 三、采用配置方法使用AOP&#xff08…

windows下Tomcat安装

目录 1.安装java环境 2.配置Tomcat环境变量 3.安装服务 4.启动前修改配置文件 &#xff08;1&#xff09;设置tomcat端口 &#xff08;2&#xff09;设置临时日志等文件夹的位置 5.放入应用 6.启动Tomcat服务 1.安装java环境 安装tomcat版本对应的JDK 比如&#xff1a;…