0.學習原因
因為學習Spring時涉及到了很多關于JNDI的知識,臥槽肋乍,壓根沒聽說過呀,所以特地來學習一下煌往。
參考博客:
JNDI學習總結(一)——JNDI數(shù)據(jù)源的配置
1.JNDI的誕生及簡介簡介
1)服務器數(shù)據(jù)源配置的誕生
-
JDBC階段:
一開始是使用JDBC來連接操作數(shù)據(jù)庫的:
在Java開發(fā)中,使用JDBC操作數(shù)據(jù)庫的四個步驟如下:①加載數(shù)據(jù)庫驅動程序(Class.forName("數(shù)據(jù)庫驅動類");)
②連接數(shù)據(jù)庫(Connection con = DriverManager.getConnection();)
③操作數(shù)據(jù)庫(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)
④關閉數(shù)據(jù)庫力穗,釋放連接(con.close();) 所有的用戶都需要經(jīng)過此四步進行操作电爹,但是這四步之中有三步(①加載數(shù)據(jù)庫驅動程序须鼎、②連接數(shù)據(jù)庫诞外、④關閉數(shù)據(jù)庫澜沟,釋放連接)對所有人都是一樣的,而所有人只有在操作數(shù)據(jù)庫上是不一樣峡谊,那么這就造成了性能的損耗茫虽。
那么最好的做法是,準備出一個空間既们,此空間里專門保存著全部的數(shù)據(jù)庫連接濒析,以后用戶用數(shù)據(jù)庫操作的時候不用再重新加載驅動、連接數(shù)據(jù)庫之類的啥纸,而直接從此空間中取走連接号杏,關閉的時候直接把連接放回到此空間之中。
而這個空間就是連接池斯棒。-
但是連接池的是有會有以下疑慮:
1盾致、 如果沒有任何一個用戶使用連接莹妒,那么那么應該維持一定數(shù)量的連接,等待用戶使用绰上。
2、 如果連接已經(jīng)滿了渠驼,則必須打開新的連接蜈块,供更多用戶使用。
3迷扇、 如果一個服務器就只能有100個連接百揭,那么如果有第101個人過來呢?應該等待其他用戶釋放連接
4蜓席、 如果一個用戶等待時間太長了器一,則應該告訴用戶,操作是失敗的厨内。 如果直接用程序實現(xiàn)以上功能祈秕,則會比較麻煩。
所以在Tomcat 4.1.27之后雏胃,在服務器上就直接增加了數(shù)據(jù)源的配置選項请毛,直接在服務器上配置好數(shù)據(jù)源連接池即可。在J2EE服務器上保存著一個數(shù)據(jù)庫的多個連接瞭亮。每一個連接通過DataSource可以找到方仿。DataSource被綁定在了JNDI樹上(為每一個DataSource提供一個名字)客戶端通過名稱找到在JNDI樹上綁定的DataSource,再由DataSource找到一個連接统翩。-
示意圖如下:
00042JNDI學習1-01.jpg -
網(wǎng)上流傳的圖:
00042JNDI學習1-02.jpg 那么在以后的操作中仙蚜,除了數(shù)據(jù)庫的連接方式不一樣之外,其他的所有操作都一樣厂汗,只是關閉的時候不是徹底地關閉數(shù)據(jù)庫委粉,而是把數(shù)據(jù)庫的連接放回到連接池中去。
2)JNDI的簡介及優(yōu)點:
- JNDI的定義:
上面知道了JNDI的作用面徽,JNDI的定義也就很容易理解了:
JNDI是Java命名與文件夾接口(Java Naming and Directory Interface)艳丛,在J2EE規(guī)范中是重要的規(guī)范之中的一個。
簡單的理解趟紊,區(qū)別于JDBC,就是:
jdbc是java去找數(shù)據(jù)庫驅動氮双,jndi是通過你的服務器配置(如Tomcat)的配置文件context來找數(shù)據(jù)庫驅動~ - 現(xiàn)在JNDI已經(jīng)成為J2EE的標準之一,所有的J2EE容器都必須提供一個JNDI的服務霎匈。(web容器就是Tomcat等服務器充當?shù)?
- 為什么使用了連接池還要用JNDI:
為了數(shù)據(jù)庫資源的管理戴差,在容器中配置一個數(shù)據(jù)庫連接池,使用JNDI 來管理
這樣容器中運行多個服務的時候铛嘱,每個服務只需添加一個jndi的名稱就可以連接到數(shù)據(jù)庫了
如果不使用jndi的方式暖释,直接在項目中配置數(shù)據(jù)庫連接池袭厂,那么每個項目需要配置一次,如果更改數(shù)據(jù)庫地址時球匕,
每個項目的數(shù)據(jù)庫連接方式都要更改纹磺,比較麻煩,使用jndi的話亮曹,直接更改一下jndi里面的數(shù)據(jù)庫連接池的配置就可以了橄杨,方便一些。 - 一般來說如果目標客戶有專業(yè)的應用服務器照卦,比如 WebSphere式矫,WebLogic,我們就不需要在代碼中配置使用特定的 dbcp 或其它的連接池了役耕。只使用JNDI就可以了采转。
2.JNDI+Tomcat配置數(shù)據(jù)源(全局配置)
1)Tomcat全局配置:
-
需要在tomcat中的server.xml中配置數(shù)據(jù)源:
00042JNDI學習1-03.jpg -
在Tomcat的lib目錄下添加驅動包:
00042JNDI學習1-04.jpg -
打開server.xml,一般都有一個默認的全局配置(Resource)標簽:
00042JNDI學習1-05.jpg
代碼如下:
<GlobalNamingResources>
<Resource auth="Container" description="User databasethat can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
name="UserDatabase"
pathname="conf/tomcat-users.xml"
type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
-
在默認的Resource下添加配置如下:
<Resource name="jdbc/mysql" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/springtest?useUnicode=true&characterEncoding=utf-8"/>
各項配置的含義后面介紹瞬痘。
-
以上兩步(導包+配置server.xml)全局配置就已經(jīng)配置好了故慈。
這一步并非必須的,可以不寫框全,親測沒有失敗
在需要使用的JNDI的項目中的web.xml中引用該配置:<resource-ref> <res-ref-name>jdbc/mysql</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
屬于可選配置惯悠,如果在web.xml中加入了上面的配置,則需要在Tomcat中一定要配置對應的Resource竣况,否則會報錯克婶。
-
查看Service的最下面,可以看到有當前工程的上下文:
00042JNDI學習1-06.jpg
在該上下文中增加對全局配置的引用:
<Context docBase="JNDITest" path="/JNDITest" reloadable="true" source="org.eclipse.jst.jee.server:JNDITest">
<ResourceLink global="mysqlData" name="jdbc/mysql" type="javax.sql.DataSource" />
</Context>
配置模板:
<?xml version="1.0" encoding="UTF-8"?>
<!--
jndi配置方法(tomcat):
-->
<!--映射JNDITest項目的虛擬目錄-->
<Context docBase="D:/MyEclipse8.5/workspace/JNDITest/WebRoot" debug="0" reloadable="false">
<!--global指的是全局配置的name,
name指的是這個DataSourse的名字-->
<!--引用全局配置-->
<ResourceLink name="mysqlData" global="jdbc/mysql" type="javax.sql.DataSource"/>
</Context>
-
這一步可以替換第6步(寫了這個則不用配置第六步):
在項目的META-INF下面建立context.xml文件丹泉,在里面寫上:<?xml version="1.0" encoding="UTF-8"?> <Context> <ResourceLink name="mysqlData" global="jdbc/mysql type="javax.sql.DataSource"/> </Context>
-
第6步替換策略二(自認為最簡單的方式):
找到Tomcat下的conf/context.xml文件:
00042JNDI學習1-08.jpg
配置上:
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<ResourceLink name="mysqlData" global="jdbc/mysql" type="javax.sql.DataSource"/>
</Context>
這句話就可以了情萤。
所以第六步可以有三種策略(我只測試了一種)。
2)創(chuàng)建測試類代碼:
-
創(chuàng)建測試類:(最簡單的jsp測試)
<%@page import="javax.naming.InitialContext"%> <%@page import="javax.naming.Context"%> <%@page import="javax.sql.DataSource"%> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% Context initContext = new InitialContext(); //上轉型摹恨,也可以不用上轉型 DataSource ds = (DataSource)initContext.lookup("java:/comp/env/mysqlData"); out.print(ds); %>
-
測試結果:
00042JNDI學習1-07.jpg
成功獲取到數(shù)據(jù)源(javax.sql.datasource對象)筋岛。
- 注意事項:
java:/comp/env/
,這是j2ee的命名空間晒哄,其他地方可能會變
context.lookup(“XXX”)
睁宰,在任何時候都是有效的,只要XXX確實是一個存在的JNDI名寝凌。
Tomcat的全局JNDI資源不能直接訪問柒傻,必須有java:comp/env/前綴。
這樣子配置好的工程默認使用的是Tomcat自帶的dbcp連接池较木。
3)JNDI的配置模板:
<GlobalNamingResources>
<!--默認的這個配置不要刪除-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
<!--
|- name:表示以后要查找的名稱红符。通過此名稱可以找到DataSource,此名稱任意更換,但是程序中最終要查找的就是此名稱预侯,
為了不與其他的名稱混淆致开,所以使用jdbc/oracle,現(xiàn)在配置的是一個jdbc的關于oracle的命名服務萎馅。
|- auth:由容器進行授權及管理双戳,指的用戶名和密碼是否可以在容器上生效
|- type:此名稱所代表的類型,現(xiàn)在為javax.sql.DataSource
|- maxActive:表示一個數(shù)據(jù)庫在此服務器上所能打開的最大連接數(shù)
|- maxIdle:表示一個數(shù)據(jù)庫在此服務器上維持的最小連接數(shù)
|- maxWait:最大等待時間糜芳。10000毫秒
|- username:數(shù)據(jù)庫連接的用戶名
|- password:數(shù)據(jù)庫連接的密碼
|- driverClassName:數(shù)據(jù)庫連接的驅動程序
|- url:數(shù)據(jù)庫連接的地址
-->
<!--配置Oracle數(shù)據(jù)庫的JNDI數(shù)據(jù)源-->
<Resource
name="jdbc/oracle"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="lead_oams"
password="p"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:lead"/>
<!--配置MySQL數(shù)據(jù)庫的JNDI數(shù)據(jù)源-->
<Resource
name="jdbc/mysql"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/leadtest?useUnicode=true&characterEncoding=utf-8"/>
<!--配置SQLServer數(shù)據(jù)庫的JNDI數(shù)據(jù)源-->
<Resource
name="jdbc/sqlserver"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="sa"
password="p@ssw0rd"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=demo"/>
</GlobalNamingResources>
3.JNDI+Tomcat配置數(shù)據(jù)源(局部配置)
1)簡單思路
- 非全局JNDI數(shù)據(jù)源是針對某一個Web項目配置的數(shù)據(jù)源拣技,具體的配置步驟如下:
1、在tomcat服務器的lib目錄下加入數(shù)據(jù)庫連接的驅動jar包
2耍目、針對具體的web項目映射虛擬目錄,然后在虛擬目錄映射的配置文件中配置JNDI數(shù)據(jù)源 - 還有一個更簡單的思路:
就是將上述引用全局配置的地方改為和全局配置相同的那樣的配置,并將全局配置刪除徐绑。
所以共有三種方法(conf/context.xml中配置的可能是全局的) - 正常使用的話還是用全局配置吧邪驮。
2)配置過程及幾種方法:
配置模板和全局配置的相同。
-
方法一:修改server.xml中的context(對應全局配置步驟6)
<Context docBase="JNDITest" path="/JNDITest" reloadable="true" source="org.eclipse.jst.jee.server:JNDITest"> <Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1/test" username="root" password="root" maxActive="20" maxIdle="10" maxWait="-1"/> </Context>
-
方法二:在項目的META-INF下面建立context.xml文件(對應全局配置步驟7)傲茄,在里面配置上:
<?xml version="1.0" encoding="UTF-8"?> <Context> <Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1/test" username="root" password="root" maxActive="20" maxIdle="10" maxWait="-1"/> </Context>
-
方法三:配置conf/context.xml(對應步驟8)
(這步極有可能是全局的配置):<Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1/test" username="root" password="root" maxActive="20" maxIdle="10" maxWait="-1"/> <\Context>
將上述WatchedResource標簽中的路徑改為項目路徑就是局部配置了毅访。
- 測試類和全局配置的相同,我也不測試了盘榨。
4.關于配置JNDI的總結
-
全局配置的思路圖(虛線為非必須):
00042JNDI學習1-09.jpg 局部配置就不畫了喻粹,差不多。
以上步驟就能配置數(shù)據(jù)源了草巡,至于獲取了DataSource怎么操作數(shù)據(jù)守呜,那就是javax.sql.DataSource的事情了,以后再學。