1. 程式人生 > >完整JavaWeb專案筆記 第七部分-JNDI資料來源配置及DBUtil封裝

完整JavaWeb專案筆記 第七部分-JNDI資料來源配置及DBUtil封裝

文章目錄

一 何為JNDI

  按百度百科的說法,是SUN公司提供的一種標準的Java命名系統介面。呃……再細點說我也不知道該說點啥了。因為我也只是在配置資料來源的時候才會用上,或許都不一定會用上。

  那說說為什麼會用到JNDI來配置資料來源,如果不用JNDI我們在做Java開發的時候,自然而然的會選擇JDBC,然而JDBC配置有其天然的缺陷,因為資料來源的URL、資料來源型別或者其他配置引數都有可能隨環境變動而發生改變。

  對於程式設計師來說,我們更為關心的應該是業務需求的實現,而非配置上的管理,這就有了配置透明的需求,而JNDI則很好的解決了這些問題,它把這些問題轉移到J2EE容器來管理,開發者僅僅需要根據需求來實現設計即可。

  回憶一下假如我們使用的是如Mybatis這樣的ORM框架呢?似乎也只需要進行一些簡單的配置即可,給我一個使用JNDI的理由:針對不同的應用,或者不同型別的資料來源,或者其他更為複雜的叢集配置管理,我需要更為統一的、標準化的實現,JNDI是由J2EE容器提供的,是J2EE的規範之一。標準、規範、約定,這些詞是我考量技術選型的重要指標。

二 為單獨的專案JNDI配置

  JNDI資料來源配置大致分為全域性配置及區域性配置,其配置方法略有不同,更為具體的介紹讀者可自行搜尋。這裡我選擇為Web專案單獨配置,這樣做可能更好的對配置進行管理,而且不會與Tomcat伺服器發生過多交集,解耦、擴充套件、維護,這三個詞也是我選擇方案時的重要參考。

  配置上只要思路明確了,就比較好實現,這裡我簡單介紹下當前的專案配置:

  1. 資料庫為Mysql
  2. 資料庫連線池選用阿里的Druid

  首先進行單專案的JNDI資料來源配置,需要編輯一份Context.xml配置檔案,雖然我僅使用了Mysql資料庫,但是為了以後的擴充套件需要,我依然配置了Oracle、SqlServer資料庫配置,簡單貼上配置檔案,涉及敏感資訊的部分我使用*來替代:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
     <!-- 使用阿里巴巴的DruidDataSource配置針對Oracle資料庫的JNDI資料來源 -->
<Resource name="jdbc/OracleDataSource" factory="com.alibaba.druid.pool.DruidDataSourceFactory" auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@*(IP):*(PORT):*(DBNAME)" username="*" password="*" maxActive="50" maxWait="10000" removeabandoned="true" removeabandonedtimeout="60" logabandoned="false" filters="stat"/> <!-- 使用阿里巴巴的DruidDataSource配置針對MySQL資料庫的JNDI資料來源 --> <Resource name="jdbc/MysqlDataSource" factory="com.alibaba.druid.pool.DruidDataSourceFactory" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/*(DBNAME)?useUnicode=true&amp;characterEncoding=utf-8" username="*" password="*" maxActive="50" maxWait="10000" removeabandoned="true" removeabandonedtimeout="60" logabandoned="false" filters="stat"/> <!--使用阿里巴巴的DruidDataSource配置針對SQLServer資料庫的JNDI資料來源--> <Resource name="jdbc/SqlServerDataSource" auth="Container" factory="com.alibaba.druid.pool.DruidDataSourceFactory" type="javax.sql.DataSource" driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://*(IP):*(PORT);DatabaseName=*" username="*" password="*" maxActive="50" maxWait="10000" removeabandoned="true" removeabandonedtimeout="60" logabandoned="false" filters="stat"/> </Context>

  因為是單獨為當前專案所作的配置,所以我們需要在META-INF目錄下放置這個配置檔案:

context配置檔案位置

三 DBUtil封裝

  配置完資料來源,我們需要獲取資料來源,並從其獲取資料庫連線,JNDI對外提供的訪問方法如下:

Context ctx = new InitialContext();
ctx.lookup("NAME");

  這裡的NAME指的就是Context.xml中配置的Resource.name節點屬性值, 我們需要封裝一個工具類來獲取資料來源,並且從資料來源獲取資料庫連線,為便於程式編寫,還需提供對連線的關閉等管理方法,綜上實現如下:

package com.bubbling.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.alibaba.druid.pool.DruidDataSource;
import com.bubbling.common.Constant;

/**
 * 資料來源操作工具,實現資料來源物件的初始化操作,對外提供資料庫連線,及關閉連線等公共訪問方法
 * 
 * @author 胡楠
 *
 */
public class DBUtil
{
	private static final String STR_MYSQL_DATASOURCE_NAME = "java:comp/env/jdbc/MysqlDataSource";
	private static final String STR_ORACLE_DATASOURCE_NAME = "java:comp/env/jdbc/OracleDataSource";
	private static final String STR_SQLSERVER_DATASOURCE_NAME = "java:comp/env/jdbc/SqlServerDataSource";

	private static DruidDataSource dsMySql = null;
	private static DruidDataSource dsOracle = null;
	private static DruidDataSource dsSqlServer = null;

	static
	{
		try
		{
			Context ctx = new InitialContext();
			if (Constant.B_IS_MYSQL)
			{
				dsMySql = (DruidDataSource) ctx.lookup(STR_MYSQL_DATASOURCE_NAME);
			}
			if (Constant.B_IS_ORACLE)
			{
				dsOracle = (DruidDataSource) ctx.lookup(STR_ORACLE_DATASOURCE_NAME);
			}
			if (Constant.B_IS_SQLSERVER)
			{
				dsSqlServer = (DruidDataSource) ctx.lookup(STR_SQLSERVER_DATASOURCE_NAME);
			}
		}
		catch (NamingException e)
		{
			e.printStackTrace();
		}
	}

	public static Connection getConnection() throws SQLException
	{
		if (Constant.B_IS_MYSQL)
		{
			return getMySqlConnection();
		}
		if (Constant.B_IS_ORACLE)
		{
			return getOracleConnection();
		}
		if (Constant.B_IS_SQLSERVER)
		{
			return getSqlServerConnection();
		}

		throw new SQLException("無可用資料連線,檢查資料來源配置!");
	}

	private static Connection getMySqlConnection() throws SQLException
	{
		return dsMySql.getConnection();
	}

	private static Connection getOracleConnection() throws SQLException
	{
		return dsOracle.getConnection();
	}

	private static Connection getSqlServerConnection() throws SQLException
	{
		return dsSqlServer.getConnection();
	}

	public static void close(Connection conn)
	{
		close(conn, null, null);
	}

	public static void close(Connection conn, Statement st)
	{
		close(conn, st, null);
	}

	public static void close(Connection conn, Statement st, ResultSet rs)
	{
		if (rs != null)
		{
			try
			{
				rs.close();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
			rs = null;
		}
		if (st != null)
		{
			try
			{
				st.close();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}

		if (conn != null)
		{
			try
			{
				conn.close();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	}
}

  注意,這裡有幾點需要留心:

  1. 對JNDI的名稱空間訪問,其完整訪問名為“java:comp/env/jdbc/MysqlDataSource”,而Conext.xml配置中的name節點屬性名為“jdbc/MysqlDataSource”,如果讀者發現例項化資料來源時報錯,可以先對訪問名進行檢查;
  2. 按網上的一些說法,需要對web.xml進行編輯,引入JDNI配置,講真,不需要;
  3. DBUtil中我使用了一個全域性上下文Constant.java,這是一個靜態引數配置類,在前幾部分我也沒有提到過,因為這裡放置了整個專案中涉及到的引數配置,包括靜態字串、狀態標誌位等等,因各人邏輯實現習慣不一樣,其內容可有可無,可多可少,所以我沒有細說。

四 DBUtil缺陷

  雖然我們依著JNDI的配置封裝了DBUtil,但是這裡是有問題的,因為資料庫連線僅僅在應用部署啟動後才能獲取。這對開發過程中的測試、除錯是一種阻礙。

  解決這個問題有很多方案可以實現,簡單提供一種,在本地及伺服器進行環境變數的配置,或者僅僅在Constans.java中進行引數配置,如果是開發模式則從JDBC獲取連線,如果是服務端模式則從JNDI獲取連線,其具體實現我不做介紹了。算了,以後有時間還是寫一寫吧……我總是覺得這些東西,說實在的有點low,自己都不是很能耐得住性子寫下去。