嵌入式數據庫H2學習總結(三)——在Web應用中嵌入H2數據庫

1、搭建測試環境和項目

1.一、搭建JavaWeb測試項目

  建立一個【H2DBTest】JavaWeb項目,找到H2數據庫的jar文件,以下圖所示:java

  

  H2數據庫就一個jar文件,這個Jar文件裏面包含了使用JDBC方式鏈接H2數據庫時使用的驅動類,將"h2-1.4.183.jar"加入到【H2DBTest】項目中,以下圖所示:web

  

2、啓動H2數據庫

  既然是要將H2數據庫做爲咱們Web應用的一部分嵌入進來,那麼咱們就要在Web應用中啓動H2數據庫的服務,這樣咱們纔可以鏈接到H2數據庫,所以咱們能夠編寫一個專門用於啓動H2數據庫服務的監聽器(Listener),監聽器示例代碼以下:sql

package me.gacl.web.listener;

import java.sql.SQLException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.h2.tools.Server;

/**
* @ClassName: H2DBServerStartListener
* @Description: 用於啓動H2數據庫服務的監聽器,在應用系統初始化時就啓動H2數據庫的服務
* @author: 孤傲蒼狼
* @date: 2014-12-20 下午11:43:39
*
*/ 
public class H2DBServerStartListener implements ServletContextListener {

    //H2數據庫服務器啓動實例
    private Server server;
    /* 
     * Web應用初始化時啓動H2數據庫
     */
    public void contextInitialized(ServletContextEvent sce) {
        try {  
            System.out.println("正在啓動h2數據庫...");
            //使用org.h2.tools.Server這個類建立一個H2數據庫的服務並啓動服務,因爲沒有指定任何參數,那麼H2數據庫啓動時默認佔用的端口就是8082
            server = Server.createTcpServer().start(); 
            System.out.println("h2數據庫啓動成功...");
        } catch (SQLException e) {  
            System.out.println("啓動h2數據庫出錯:" + e.toString());  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }

    /* 
     * Web應用銷燬時中止H2數據庫
     */
    public void contextDestroyed(ServletContextEvent sce) {
        if (this.server != null) {
            // 中止H2數據庫
            this.server.stop();
            this.server = null;
        }
    }
}

 

  監聽器寫好以後,咱們在Web.xml文件中註冊這個監聽器,另外,由於咱們要將H2數據庫嵌入到咱們的Web應用當中,爲了可以方便訪問H2數據庫提供的Console,咱們能夠在Web.xml文件中配置用於訪問H2數據庫Console的Servlet。數據庫

Web.xml文件的配置以下:服務器

<!-- 使用監聽器啓動和中止數據庫 -->
      <listener>
        <listener-class>me.gacl.web.listener.H2DBServerStartListener</listener-class>
    </listener>
    
    <!-- 使用H2控制檯的Servlet H2控制檯是一個獨立的應用程序,包括它本身的Web服務器,但它能夠做爲一個servlet做爲-->
    <servlet>
        <servlet-name>H2Console</servlet-name>
        <servlet-class>org.h2.server.web.WebServlet</servlet-class>
         <init-param>
            <param-name>webAllowOthers</param-name>
            <param-value></param-value>
        </init-param>
        <init-param>
            <param-name>trace</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 映射H2控制檯的訪問路徑 -->
    <servlet-mapping>
        <servlet-name>H2Console</servlet-name>
        <url-pattern>/console/*</url-pattern>
    </servlet-mapping>

 配置好Listener和訪問Console的Servlet以後,咱們就能夠把H2數據庫看成是咱們Web應用中的一部分來使用了。app

  將Web應用部署到Tomcat服務器,當啓動Tomcat服務器時,在控制檯就能夠看到H2數據庫啓動成功的消息,以下圖所示:dom

  

  爲了進一步驗證H2數據庫是否真的是經過監聽器正常啓動了,咱們能夠訪問一下H2數據庫的Console,輸入訪問地址:"http://localhost:8080/H2DBTest/console/"進行訪問,以下圖所示:tcp

  

  可以看到H2數據庫Console的登陸頁面,說明了H2數據庫已經正常啓動了。函數

3、向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方法,代碼以下:

package h2db.function.ext;

import java.util.UUID;

/**
* @ClassName: H2DBFunctionExt
* @Description: 針對H2數據庫函數的擴展
* @author: 孤傲蒼狼
* @date: 2014-12-20 下午11:20:34
*
*/ 
public class H2DBFunctionExt {

    /**
    * 用法:SELECT uuid();
    * H2數據庫註冊uuid函數:CREATE ALIAS uuid FOR "h2db.function.ext.H2DBFunctionExt.uuid";
    * @Method: uuid
    * @Description: 實現MySQL數據庫的uuid函數,用於生成UUID
    * @Anthor:孤傲蒼狼
    *
    * @return
    */ 
    public static String uuid(){
        return UUID.randomUUID().toString();
    }
}

  這樣,咱們的uuid函數就算是編寫好了,須要注意的是,類和方法必須是公共(Public)的,且方法需爲靜態(static)的,如方法中使用了Connection對象需將其關閉。

  接下來咱們要將其註冊到H2數據庫中,須執行"CREATE ALIAS"語句,SQL語法以下:

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數據庫的擴展函數,代碼以下:

package h2db.function.ext;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
* @ClassName: H2DBFunctionExt
* @Description: 針對H2數據庫函數的擴展
* @author: 孤傲蒼狼
* @date: 2014-12-20 下午11:20:34
*
*/ 
public class H2DBFunctionExt {

    /**
    * 用法:SELECT uuid();
    * H2數據庫註冊uuid函數:CREATE ALIAS IF NOT EXISTS uuid FOR "h2db.function.ext.H2DBFunctionExt.uuid";
    * @Method: uuid
    * @Description: 實現MySQL數據庫的uuid函數,用於生成UUID
    * @Anthor:孤傲蒼狼
    *
    * @return
    */ 
    public static String uuid(){
        return UUID.randomUUID().toString();
    }

    /**
    * H2數據庫註冊currentTime函數:CREATE ALIAS IF NOT EXISTS currentTime FOR "h2db.function.ext.H2DBFunctionExt.now";
    * @Method: now
    * @Description: 實現MySQL數據庫的now()函數,用於生成當前系統時間
    * @Anthor:孤傲蒼狼
    *
    * @return
    */ 
    public static String now(){
        return new Date().toLocaleString();
    }
    
    /**
     * H2數據庫註冊IP函數:CREATE ALIAS IF NOT EXISTS IP FOR "h2db.function.ext.H2DBFunctionExt.getIp";
    * @Method: getIp
    * @Description: 
    * @Anthor:孤傲蒼狼
    *
    * @return
    */ 
    public static String getIp(){
        try {
            InetAddress addr = InetAddress.getLocalHost();
            //得到本機IP
            return addr.getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return "未知的IP地址";
        } 
    }
    
    /**
    * H2數據庫註冊date_format函數:CREATE ALIAS IF NOT EXISTS date_format FOR "h2db.function.ext.H2DBFunctionExt.date_format";
    * @Method: date_format
    * @Description: 實現MySQL數據庫的date_format()函數,用於格式化日期
    * @Anthor:孤傲蒼狼
    * @param date
    * @param pattern
    * @return
    */ 
    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 "";
    }
}

  爲了實現批量註冊H2數據庫的擴展函數,咱們能夠編寫一個Servlet,專門用於註冊擴展函數,代碼以下:

package me.gacl.sys.init;


import java.sql.Connection;
import java.sql.Statement;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import me.gacl.util.JdbcUtil;

/**
* @ClassName: RegisterH2ExtFuncServlet
* @Description:註冊H2數據庫的擴展函數
* @author: 孤傲蒼狼
* @date: 2014-12-20 下午11:47:03
*
*/ 
public class RegisterH2ExtFuncServlet extends HttpServlet {

    /**
    * @Field: serialVersionUID
    */ 
    private static final long serialVersionUID = 4379248469825545593L;

    public void init() throws ServletException {
        //一、註冊uuid函數的SQL語句
        String sql1 = "CREATE ALIAS IF NOT EXISTS uuid FOR \"h2db.function.ext.H2DBFunctionExt.uuid\"";
        //二、註冊currentTime函數的SQL語句
        String sql2 = "CREATE ALIAS IF NOT EXISTS currentTime FOR \"h2db.function.ext.H2DBFunctionExt.now\"";
        //三、註冊IP函數的SQL語句
        String sql3 = "CREATE ALIAS IF NOT EXISTS IP FOR \"h2db.function.ext.H2DBFunctionExt.getIp\"";
        //四、註冊date_format函數的SQL語句
        String sql4 = "CREATE ALIAS IF NOT EXISTS date_format FOR \"h2db.function.ext.H2DBFunctionExt.date_format\"";
        Connection connection = null;
        Statement stmt = null;
        try {
            //獲取數據庫鏈接
            connection = JdbcUtil.getConnection();
            //獲取Statement對象
            stmt = connection.createStatement();
            //添加要執行的SQL
            stmt.addBatch(sql1);
            stmt.addBatch(sql2);
            stmt.addBatch(sql3);
            stmt.addBatch(sql4);
            //批量執行上述的4條SQL
            stmt.executeBatch();
            System.out.println("H2數據庫擴展函數註冊成功!");
            stmt.clearBatch();
        } catch (Exception e) {
            System.out.println("H2數據庫擴展函數註冊失敗!");
            e.printStackTrace();
        }finally{
            try {
                stmt.close();
                connection.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}

  在Web.xml中註冊RegisterH2ExtFuncServlet

<servlet>
    <description>註冊H2數據庫的擴展函數</description>
    <servlet-name>RegisterH2DBExtFunction</servlet-name>
    <servlet-class>me.gacl.sys.init.RegisterH2ExtFuncServlet</servlet-class>
    <!-- 
    一、load-on-startup元素標記容器是否在啓動的時候就加載這個servlet(實例化並調用其init()方法)。
    二、它的值必須是一個整數,表示servlet應該被載入的順序
    三、當值爲0或者大於0時,表示容器在應用啓動時就加載並初始化這個servlet;
    四、當值小於0或者沒有指定時,則表示容器在該servlet被選擇時纔會去加載。
    五、正數的值越小,該servlet的優先級越高,應用啓動時就越先加載。
    六、當值相同時,容器就會本身選擇順序來加載。
    因此,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5表明的是優先級,而非啓動延遲時間。
     -->
     <load-on-startup>1</load-on-startup>
</servlet>

  RegisterH2ExtFuncServlet要批量執行SQL語句,所以須要鏈接上H2數據庫纔可以執行,工具類JdbcUtil提供了獲取數據庫鏈接的方法,JdbcUtil的代碼以下:

/**
 * 
 */
package me.gacl.util;

import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
import org.h2.jdbcx.JdbcConnectionPool;

public class JdbcUtil {

    /**
     * H2數據庫自帶的鏈接池
     */
    private static JdbcConnectionPool cp = null;
    
    static{
        try {
            //加載src目錄下的h2config.properties
            InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("h2config.properties");
            Properties prop = new Properties();
            prop.load(in);
            //建立數據庫鏈接池
            cp = JdbcConnectionPool.create(prop.getProperty("JDBC_URL"), prop.getProperty("USER"), prop.getProperty("PASSWORD"));
        } catch (Exception e) {
            System.out.println("鏈接池初始化異常");
            e.printStackTrace();
        }
    }
    
    /**
    * @Method: getConnection
    * @Description:獲取數據庫鏈接
    * @Anthor:孤傲蒼狼
    * @return
    * @throws Exception
    */ 
    public static Connection getConnection() throws Exception{
        return cp.getConnection();
    }

    public static JdbcConnectionPool getCp() {
        return cp;
    }
}

  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數據庫函數的擴展的內容就講解這麼多了。

相關文章
相關標籤/搜索