Java嵌入式数据库H2学习总结(三)——在Web应用中嵌入H2数据库

  H2作为一个嵌入型的数据库,它最大的好处就是可以嵌入到我们的Web应用中,和我们的Web应用绑定在一起,成为我们Web应用的一部分。下面来演示一下如何将H2数据库嵌入到我们的Web应用中。

一、搭建测试环境和项目

1.1、搭建JavaWeb测试项目

  创建一个【H2DBTest】JavaWeb项目,找到H2数据库的jar文件,如下图所示:

  

  H2数据库就一个jar文件,这个Jar文件里面包含了使用JDBC方式连接H2数据库时使用的驱动类,将"h2-1.4.183.jar"加入到【H2DBTest】项目中,如下图所示:

  

二、启动H2数据库

  既然是要将H2数据库作为我们Web应用的一部分嵌入进来,那么我们就要在Web应用中启动H2数据库的服务,这样我们才能够连接到H2数据库,因此我们可以编写一个专门用于启动H2数据库服务的监听器(Listener),监听器示例代码如下:

 1 package me.gacl.web.listener;
 2
 3 import java.sql.SQLException;
 4 import javax.servlet.ServletContextEvent;
 5 import javax.servlet.ServletContextListener;
 6 import org.h2.tools.Server;
 7
 8 /**
 9 * @ClassName: H2DBServerStartListener
10 * @Description: 用于启动H2数据库服务的监听器,在应用系统初始化时就启动H2数据库的服务
11 * @author: 孤傲苍狼
12 * @date: 2014-12-20 下午11:43:39
13 *
14 */
15 public class H2DBServerStartListener implements ServletContextListener {
16
17     //H2数据库服务器启动实例
18     private Server server;
19     /*
20      * Web应用初始化时启动H2数据库
21      */
22     public void contextInitialized(ServletContextEvent sce) {
23         try {
24             System.out.println("正在启动h2数据库...");
25             //使用org.h2.tools.Server这个类创建一个H2数据库的服务并启动服务,由于没有指定任何参数,那么H2数据库启动时默认占用的端口就是8082
26             server = Server.createTcpServer().start();
27             System.out.println("h2数据库启动成功...");
28         } catch (SQLException e) {
29             System.out.println("启动h2数据库出错:" + e.toString());
30             e.printStackTrace();
31             throw new RuntimeException(e);
32         }
33     }
34
35     /*
36      * Web应用销毁时停止H2数据库
37      */
38     public void contextDestroyed(ServletContextEvent sce) {
39         if (this.server != null) {
40             // 停止H2数据库
41             this.server.stop();
42             this.server = null;
43         }
44     }
45 }

  监听器写好之后,我们在Web.xml文件中注册这个监听器,另外,因为我们要将H2数据库嵌入到我们的Web应用当中,为了能够方便访问H2数据库提供的Console,我们可以在Web.xml文件中配置用于访问H2数据库Console的Servlet。

Web.xml文件的配置如下:

 1 <!-- 使用监听器启动和停止数据库 -->
 2       <listener>
 3         <listener-class>me.gacl.web.listener.H2DBServerStartListener</listener-class>
 4     </listener>
 5
 6     <!-- 使用H2控制台的Servlet H2控制台是一个独立的应用程序,包括它自己的Web服务器,但它可以作为一个servlet作为-->
 7     <servlet>
 8         <servlet-name>H2Console</servlet-name>
 9         <servlet-class>org.h2.server.web.WebServlet</servlet-class>
10          <init-param>
11             <param-name>webAllowOthers</param-name>
12             <param-value></param-value>
13         </init-param>
14         <init-param>
15             <param-name>trace</param-name>
16             <param-value></param-value>
17         </init-param>
18         <load-on-startup>1</load-on-startup>
19     </servlet>
20     <!-- 映射H2控制台的访问路径 -->
21     <servlet-mapping>
22         <servlet-name>H2Console</servlet-name>
23         <url-pattern>/console/*</url-pattern>
24     </servlet-mapping>

  配置好Listener和访问Console的Servlet之后,我们就可以把H2数据库当作是我们Web应用中的一部分来使用了。

  将Web应用部署到Tomcat服务器,当启动Tomcat服务器时,在控制台就可以看到H2数据库启动成功的消息,如下图所示:

  

  为了进一步验证H2数据库是否真的是通过监听器正常启动了,我们可以访问一下H2数据库的Console,输入访问地址:"http://localhost:8080/H2DBTest/console/"进行访问,如下图所示:

  

  能够看到H2数据库Console的登录页面,说明了H2数据库已经正常启动了。

三、向H2数据库注册自定义的数据库函数

  H2作为一个数据库,和其他类型的数据库一样,会自带有一些数据库函数给我们使用,但是H2数据库提供的数据库函数有限,无法满足我们开发中的需求,幸运的是,H2数据库支持自定义数据库函数的,因此我们可以根据开发中的实际应用场景编写满足我们需求的数据库函数。

  下面就来说一下如何实现H2数据库的自定义函数

  在MySQL数据库中有一个UUID函数是用来生成UUID的,执行"SELECT UUID()"就可以看到UUID函数生成的UUID,如下图所示:

  

  而默认情况下,H2数据库是没有提供有UUID这个函数给我们使用的,如下图所示:

  

  那么我们现在就来实现一个UUID函数,然后注册到H2数据库当中,这样H2数据库就支持UUID函数了,具体做法分为两个步骤:

  (1) 使用Java实现自定义函数的方法。

     (2) 将Java的自定义函数注册到H2数据库中。

  首先我们来实现这个UUID函数,在java中,生成一个UUID的方法是使用java.util.UUID这个类里面的一个randomUUID()方法生成的,封装成一个uuid方法,代码如下:

 1 package h2db.function.ext;
 2
 3 import java.util.UUID;
 4
 5 /**
 6 * @ClassName: H2DBFunctionExt
 7 * @Description: 针对H2数据库函数的扩展
 8 * @author: 孤傲苍狼
 9 * @date: 2014-12-20 下午11:20:34
10 *
11 */
12 public class H2DBFunctionExt {
13
14     /**
15     * 用法:SELECT uuid();
16     * H2数据库注册uuid函数:CREATE ALIAS uuid FOR "h2db.function.ext.H2DBFunctionExt.uuid";
17     * @Method: uuid
18     * @Description: 实现MySQL数据库的uuid函数,用于生成UUID
19     * @Anthor:孤傲苍狼
20     *
21     * @return
22     */
23     public static String uuid(){
24         return UUID.randomUUID().toString();
25     }
26 }

  这样,我们的uuid函数就算是编写好了,需要注意的是,类和方法必须是公共(Public)的,且方法需为静态(static)的,如方法中使用了Connection对象需将其关闭。

  接下来我们要将其注册到H2数据库中,须执行"CREATE ALIAS"语句,SQL语法如下:

1 CREATE ALIAS [IF NOT EXISTS] newFunctionAliasName [DETERMINISTIC] FOR classAndMethodName

  其中[]括起来的部分是可选的,本例须执行的语句为:  CREATE ALIAS UUID FOR "h2db.function.ext.H2DBFunctionExt.uuid" ,执行结果如下图所示:

  

  这样H2数据库中就多了一个UUID函数可以使用了,我们再次执行"SELECT UUID()"语句就可以被H2数据库正常解析了,执行结果如下图所示:

  

  以上就是针对H2数据库函数的一个扩展,我们向H2数据库新增加了一个UUID函数用于生成uuid。因此当H2数据库提供的函数不满足我们开发中的实际需求时,就可以使用这种方式来扩展H2数据库的函数了。接下来演示一下一次性向H2数据库扩展多个函数,我们编写一个H2DBFunctionExt类,在类中编写针对H2数据库的扩展函数,代码如下:

 1 package h2db.function.ext;
 2
 3 import java.net.InetAddress;
 4 import java.net.UnknownHostException;
 5 import java.text.ParseException;
 6 import java.text.SimpleDateFormat;
 7 import java.util.Date;
 8 import java.util.UUID;
 9
10 /**
11 * @ClassName: H2DBFunctionExt
12 * @Description: 针对H2数据库函数的扩展
13 * @author: 孤傲苍狼
14 * @date: 2014-12-20 下午11:20:34
15 *
16 */
17 public class H2DBFunctionExt {
18
19     /**
20     * 用法:SELECT uuid();
21     * H2数据库注册uuid函数:CREATE ALIAS IF NOT EXISTS uuid FOR "h2db.function.ext.H2DBFunctionExt.uuid";
22     * @Method: uuid
23     * @Description: 实现MySQL数据库的uuid函数,用于生成UUID
24     * @Anthor:孤傲苍狼
25     *
26     * @return
27     */
28     public static String uuid(){
29         return UUID.randomUUID().toString();
30     }
31
32     /**
33     * H2数据库注册currentTime函数:CREATE ALIAS IF NOT EXISTS currentTime FOR "h2db.function.ext.H2DBFunctionExt.now";
34     * @Method: now
35     * @Description: 实现MySQL数据库的now()函数,用于生成当前系统时间
36     * @Anthor:孤傲苍狼
37     *
38     * @return
39     */
40     public static String now(){
41         return new Date().toLocaleString();
42     }
43
44     /**
45      * H2数据库注册IP函数:CREATE ALIAS IF NOT EXISTS IP FOR "h2db.function.ext.H2DBFunctionExt.getIp";
46     * @Method: getIp
47     * @Description:
48     * @Anthor:孤傲苍狼
49     *
50     * @return
51     */
52     public static String getIp(){
53         try {
54             InetAddress addr = InetAddress.getLocalHost();
55             //获得本机IP
56             return addr.getHostAddress();
57         } catch (UnknownHostException e) {
58             e.printStackTrace();
59             return "未知的IP地址";
60         }
61     }
62
63     /**
64     * H2数据库注册date_format函数:CREATE ALIAS IF NOT EXISTS date_format FOR "h2db.function.ext.H2DBFunctionExt.date_format";
65     * @Method: date_format
66     * @Description: 实现MySQL数据库的date_format()函数,用于格式化日期
67     * @Anthor:孤傲苍狼
68     * @param date
69     * @param pattern
70     * @return
71     */
72     public static String date_format(String date,String pattern){
73         if (date != null) {
74             SimpleDateFormat sdf = new SimpleDateFormat(pattern);
75             try {
76                 Date temp = sdf.parse(date);
77                 return sdf.format(temp);
78             } catch (ParseException e) {
79                 e.printStackTrace();
80             }
81         }
82         return "";
83     }
84 }

  为了实现批量注册H2数据库的扩展函数,我们可以编写一个Servlet,专门用于注册扩展函数,代码如下:

 1 package me.gacl.sys.init;
 2
 3
 4 import java.sql.Connection;
 5 import java.sql.Statement;
 6
 7 import javax.servlet.ServletException;
 8 import javax.servlet.http.HttpServlet;
 9
10 import me.gacl.util.JdbcUtil;
11
12 /**
13 * @ClassName: RegisterH2ExtFuncServlet
14 * @Description:注册H2数据库的扩展函数
15 * @author: 孤傲苍狼
16 * @date: 2014-12-20 下午11:47:03
17 *
18 */
19 public class RegisterH2ExtFuncServlet extends HttpServlet {
20
21     /**
22     * @Field: serialVersionUID
23     */
24     private static final long serialVersionUID = 4379248469825545593L;
25
26     public void init() throws ServletException {
27         //1、注册uuid函数的SQL语句
28         String sql1 = "CREATE ALIAS IF NOT EXISTS uuid FOR \"h2db.function.ext.H2DBFunctionExt.uuid\"";
29         //2、注册currentTime函数的SQL语句
30         String sql2 = "CREATE ALIAS IF NOT EXISTS currentTime FOR \"h2db.function.ext.H2DBFunctionExt.now\"";
31         //3、注册IP函数的SQL语句
32         String sql3 = "CREATE ALIAS IF NOT EXISTS IP FOR \"h2db.function.ext.H2DBFunctionExt.getIp\"";
33         //4、注册date_format函数的SQL语句
34         String sql4 = "CREATE ALIAS IF NOT EXISTS date_format FOR \"h2db.function.ext.H2DBFunctionExt.date_format\"";
35         Connection connection = null;
36         Statement stmt = null;
37         try {
38             //获取数据库连接
39             connection = JdbcUtil.getConnection();
40             //获取Statement对象
41             stmt = connection.createStatement();
42             //添加要执行的SQL
43             stmt.addBatch(sql1);
44             stmt.addBatch(sql2);
45             stmt.addBatch(sql3);
46             stmt.addBatch(sql4);
47             //批量执行上述的4条SQL
48             stmt.executeBatch();
49             System.out.println("H2数据库扩展函数注册成功!");
50             stmt.clearBatch();
51         } catch (Exception e) {
52             System.out.println("H2数据库扩展函数注册失败!");
53             e.printStackTrace();
54         }finally{
55             try {
56                 stmt.close();
57                 connection.close();
58             } catch (Exception e2) {
59                 e2.printStackTrace();
60             }
61         }
62     }
63 }

  在Web.xml中注册RegisterH2ExtFuncServlet

 1 <servlet>
 2     <description>注册H2数据库的扩展函数</description>
 3     <servlet-name>RegisterH2DBExtFunction</servlet-name>
 4     <servlet-class>me.gacl.sys.init.RegisterH2ExtFuncServlet</servlet-class>
 5     <!--
 6     1、load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。
 7     2、它的值必须是一个整数,表示servlet应该被载入的顺序
 8     3、当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
 9     4、当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。
10     5、正数的值越小,该servlet的优先级越高,应用启动时就越先加载。
11     6、当值相同时,容器就会自己选择顺序来加载。
12     所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是优先级,而非启动延迟时间。
13      -->
14      <load-on-startup>1</load-on-startup>
15 </servlet>

  RegisterH2ExtFuncServlet要批量执行SQL语句,因此需要连接上H2数据库才能够执行,工具类JdbcUtil提供了获取数据库连接的方法,JdbcUtil的代码如下:

 1 /**
 2  *
 3  */
 4 package me.gacl.util;
 5
 6 import java.io.InputStream;
 7 import java.sql.Connection;
 8 import java.util.Properties;
 9 import org.h2.jdbcx.JdbcConnectionPool;
10
11 public class JdbcUtil {
12
13     /**
14      * H2数据库自带的连接池
15      */
16     private static JdbcConnectionPool cp = null;
17
18     static{
19         try {
20             //加载src目录下的h2config.properties
21             InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("h2config.properties");
22             Properties prop = new Properties();
23             prop.load(in);
24             //创建数据库连接池
25             cp = JdbcConnectionPool.create(prop.getProperty("JDBC_URL"), prop.getProperty("USER"), prop.getProperty("PASSWORD"));
26         } catch (Exception e) {
27             System.out.println("连接池初始化异常");
28             e.printStackTrace();
29         }
30     }
31
32     /**
33     * @Method: getConnection
34     * @Description:获取数据库连接
35     * @Anthor:孤傲苍狼
36     * @return
37     * @throws Exception
38     */
39     public static Connection getConnection() throws Exception{
40         return cp.getConnection();
41     }
42
43     public static JdbcConnectionPool getCp() {
44         return cp;
45     }
46 }

  h2config.properties的配置信息如下:

JDBC_URL=jdbc:h2:tcp://localhost/~/h2db
USER=gacl
PASSWORD=123

  当web应用启动时,就会执行RegisterH2ExtFuncServlet这个Servlet中的init方法,init方法内部的处理就是通过JdbcUtil工具类获取一个H2的数据库连接,然后创建Statement对象,再由Statement对象批量执行SQL向H2数据库注册扩展函数。

  RegisterH2ExtFuncServlet执行的过程中如果没有出现任何错误,那就说明所有的针对H2数据库的扩展函数都注册成功了,我们可以到H2的Console去验证一下上述的4个扩展函数,如下图所示:

  

  关于在Web应用中嵌入使用H2数据库,以及针对H2数据库函数的扩展的内容就讲解这么多了。

时间: 2024-11-07 04:32:10

Java嵌入式数据库H2学习总结(三)——在Web应用中嵌入H2数据库的相关文章

MyBatis学习总结(三)——优化MyBatis配置文件中的配置(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(三)--优化MyBatis配置文件中的配置 一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中,如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org

【转】MyBatis学习总结(三)——优化MyBatis配置文件中的配置

[转]MyBatis学习总结(三)——优化MyBatis配置文件中的配置 一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中,如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//E

Java嵌入式数据库H2学习总结(二)——在Web应用程序中使用H2数据库

一.搭建测试环境和项目 1.1.搭建JavaWeb测试项目 创建一个[H2DBTest]JavaWeb项目,找到H2数据库的jar文件,如下图所示: H2数据库就一个jar文件,这个Jar文件里面包含了使用JDBC方式连接H2数据库时使用的驱动类,将"h2-1.4.183.jar"加入到[H2DBTest]项目中,如下图所示: 1.2.开启H2数据库 进入到h2\bin目录,如下图所示: 确保H2数据库使用的8082端口没有被其他应用程序占用,正常启动之后输入"http://

java网络爬虫基础学习(三)

尝试直接请求URL获取资源 豆瓣电影 https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=time&page_limit=20&page_start=0 浏览器打开该地址: 发现是这样的 在这里我们需要用java抓取电影的信息,首先要找到资源链接,浏览器右键->检查打开谷歌调试工具 我们可以看到下图 有很多的资源请求,在这里我是一个个搜索,看那个是电影信息的Headers 发

Java Web项目中连接Access数据库的配置方法

本文是对前几天的"JDBC连接Access数据库的几种方式"这篇的升级.因为在做一些小项目的时候遇到的问题,因此才决定写这篇博客的.昨天已经将博客公布了.可是后来经过一些验证有点问题,所以今天改了一下又一次的公布了 老师决定期末考试採用access数据库实现增删改查.我觉得如今的我已经没有问题了.可是曾经都是在JSP页面中连接access数据库,不管是下面的那种方式都进行了连接的练习,可是如今我想让我的项目中的訪问access数据库的java代码,封装到DAO中,在DAO中连接数据库,

Jfinal数据库操作在WebService或非web项目中的使用

接触上jfinal后就基本不使用其它框架了,一直在web开发中使用,最近做了个小的WebService应用,还是使用jfinal操作数据库,在这里分享下使用经验. 我的环境是三个oracle数据库,一个数据库接收数据,然后分发数据到另外两个数据库,使用jfinal的多数据源功能刚好满足要求. 编写数据库初始化类: 直接上代码 package ynitil.pekk.ws.common; import java.util.List; import ynitil.pekk.ws.model.Cltx

Java框架spring Boot学习笔记(十六):操作MySQL数据库

新建一个工程,添加对数据库的支持 下载mysql驱动包 mysql-connector-java-5.1.7-bin.jar,快捷键ctrl+alt+shift+s,添加jar包到工程 编写测试文JdbcTemplateDemo.java 1 package com.jdbc; 2 3 import org.junit.Test; 4 import org.springframework.jdbc.core.JdbcTemplate; 5 import org.springframework.j

Java序列化与反序列化学习(三):序列化机制与原理

Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的 过程.Java序列化API提供一种处理对象序列化的标准机制.在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用 一个实例来示范序列化以后的字节是如何描述一个对象的信息的. 序列化的必要性 Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端.这就需要有一种

Java多线程高并发学习笔记(三)——深入理解线程池

线程池最核心的一个类:ThreadPoolExecutor. 看一下该类的构造器: public ThreadPoolExecutor(int paramInt1, int paramInt2, long paramLong, TimeUnit paramTimeUnit, BlockingQueue<Runnable> paramBlockingQueue) { this(paramInt1, paramInt2, paramLong, paramTimeUnit, paramBlockin