完整JavaWeb專案筆記 第七部分-JNDI資料來源配置及DBUtil封裝
文章目錄
一 何為JNDI
按百度百科的說法,是SUN公司提供的一種標準的Java命名系統介面。呃……再細點說我也不知道該說點啥了。因為我也只是在配置資料來源的時候才會用上,或許都不一定會用上。
那說說為什麼會用到JNDI來配置資料來源,如果不用JNDI我們在做Java開發的時候,自然而然的會選擇JDBC,然而JDBC配置有其天然的缺陷,因為資料來源的URL、資料來源型別或者其他配置引數都有可能隨環境變動而發生改變。
對於程式設計師來說,我們更為關心的應該是業務需求的實現,而非配置上的管理,這就有了配置透明的需求,而JNDI則很好的解決了這些問題,它把這些問題轉移到J2EE容器來管理,開發者僅僅需要根據需求來實現設計即可。
回憶一下假如我們使用的是如Mybatis這樣的ORM框架呢?似乎也只需要進行一些簡單的配置即可,給我一個使用JNDI的理由:針對不同的應用,或者不同型別的資料來源,或者其他更為複雜的叢集配置管理,我需要更為統一的、標準化的實現,JNDI是由J2EE容器提供的,是J2EE的規範之一。標準、規範、約定,這些詞是我考量技術選型的重要指標。
二 為單獨的專案JNDI配置
JNDI資料來源配置大致分為全域性配置及區域性配置,其配置方法略有不同,更為具體的介紹讀者可自行搜尋。這裡我選擇為Web專案單獨配置,這樣做可能更好的對配置進行管理,而且不會與Tomcat伺服器發生過多交集,解耦、擴充套件、維護,這三個詞也是我選擇方案時的重要參考。
配置上只要思路明確了,就比較好實現,這裡我簡單介紹下當前的專案配置:
- 資料庫為Mysql
- 資料庫連線池選用阿里的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&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目錄下放置這個配置檔案:
三 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();
}
}
}
}
注意,這裡有幾點需要留心:
- 對JNDI的名稱空間訪問,其完整訪問名為“java:comp/env/jdbc/MysqlDataSource”,而Conext.xml配置中的name節點屬性名為“jdbc/MysqlDataSource”,如果讀者發現例項化資料來源時報錯,可以先對訪問名進行檢查;
- 按網上的一些說法,需要對web.xml進行編輯,引入JDNI配置,講真,不需要;
- DBUtil中我使用了一個全域性上下文Constant.java,這是一個靜態引數配置類,在前幾部分我也沒有提到過,因為這裡放置了整個專案中涉及到的引數配置,包括靜態字串、狀態標誌位等等,因各人邏輯實現習慣不一樣,其內容可有可無,可多可少,所以我沒有細說。
四 DBUtil缺陷
雖然我們依著JNDI的配置封裝了DBUtil,但是這裡是有問題的,因為資料庫連線僅僅在應用部署啟動後才能獲取。這對開發過程中的測試、除錯是一種阻礙。
解決這個問題有很多方案可以實現,簡單提供一種,在本地及伺服器進行環境變數的配置,或者僅僅在Constans.java中進行引數配置,如果是開發模式則從JDBC獲取連線,如果是服務端模式則從JNDI獲取連線,其具體實現我不做介紹了。算了,以後有時間還是寫一寫吧……我總是覺得這些東西,說實在的有點low,自己都不是很能耐得住性子寫下去。