1. 程式人生 > >JNDI數據源(在Tomcat下配置JNDI多數據源實例)

JNDI數據源(在Tomcat下配置JNDI多數據源實例)

更新 urn post sele define 網上 def pack finally

一,添加數據庫驅動包加入classpath。

這裏我用到了oracle和mysql。
所以由兩個jar包:ojdbc14.jar和mysql-connector-java-5.1.13-bin.jar。


(有的也說需要添加commons-dbcp-1.4.jar,commons-pool-1.5.4.jar和commons-collections.jar,
我做了測試,不用的。
網上查了下,DBCP使用Jakarta-Commons Database Connection Pool,它依賴以下三個包:
Jakarta-Commons DBCP,Jakarta-Commons Collections,Jakarta-Commons Pool。
在Tomcat的安裝目錄提供了一個集成的jar包 $CATALINA_HOME/lib/tomcat-dbcp.jar。
所以有這個tomcat-dbcp.jar就可以了。

二,修改Tomcat_Home/conf/server.xml,在GlobalNamingResources中加入:

<Resource name="jdbc/cdbank" auth="Container" 
     type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"  
     url="jdbc:oracle:thin:@10.55.15.66:1521:cdbank"  
     username="ccdb" password="ccdb" maxActive="10" maxIdle="5"  
     maxWait="-1"/>

<Resource name="jdbc/mydb" auth="Container" 
     type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"  
     url="jdbc:mysql://127.0.0.1:3306/mydb"  
     username="root" password="root" maxActive="10" maxIdle="5"  
     maxWait="-1"/>


屬性說明:
name:數據源的名稱。


auth:指定管理Resource的Manager,由兩個可選值:Container和Application。
Container表示由容器來創建和管理Resource。
Application表示由WEB應用來創建和管理Resource。
如果在web application deployment descriptor中使用<resource-ref>,這個屬性是必需的。
如果使用<resource-env-ref>,這個屬性是可選的。


type:指定Resource所屬的java類名:javax.sql.DataSource。

maxActive: 指定數據庫連接池中處於活動狀態的數據庫連接最大數目,0表示不受限制

maxIdle: 指定數據庫連接池中處於空閑狀態的數據庫連接的最大數目,0表示不受限制

maxWait: 指定數據庫連接池中的數據庫連接處於空閑狀態的最長時間(單位為毫秒),超過這一事件,
將會拋出異常。-1表示可以無限期等待。

username: 連接數據庫的用戶名

password: 連接數據庫的密碼

driverClassName: 指定連接數據庫的JDBC驅動程序。
(oracle驅動:oracle.jdbc.OracleDriver
mysql驅動: com.mysql.jdbc.Driver)

url:連接數據庫的URL


完整server.xml如下:

<?xml version=‘1.0‘ encoding=‘utf-8‘?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
 -->
<Server port="8006" shutdown="SHUTDOWN">

  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users-->
    
    <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" />

	<Resource name="jdbc/cdbank" auth="Container" 
     type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"  
     url="jdbc:oracle:thin:@10.55.15.66:1521:cdbank"  
     username="ccdb" password="ccdb" maxActive="10" maxIdle="5"  
     maxWait="-1"/>

	 <Resource name="jdbc/mydb" auth="Container" 
     type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"  
     url="jdbc:mysql://127.0.0.1:3306/mydb"  
     username="root" password="root" maxActive="10" maxIdle="5"  
     maxWait="-1"/>

  </GlobalNamingResources>

  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container", 
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">
  
    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" 
        maxThreads="150" minSpareThreads="4"/>
    -->
    
    
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8453" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
    -->           
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the 
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->
    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8089" protocol="AJP/1.3" redirectPort="8453" />


    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->

    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">         
    --> 
    <Engine name="Catalina" defaultHost="localhost">

      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->        

      <!-- The request dumper valve dumps useful debugging information about
           the request and response data received and sent by Tomcat.
           Documentation at: /docs/config/valve.html -->
      <!--
      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
      -->

      <!-- This Realm uses the UserDatabase configured in the global JNDI
           resources under the key "UserDatabase".  Any edits
           that are performed against this UserDatabase are immediately
           available for use by the Realm.  -->


	
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

      <!-- Define the default virtual host
           Note: XML Schema validation will not work with Xerces 2.2.
       -->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"  
               prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
        -->

      </Host>
    </Engine>
  </Service>
</Server>

三,再在context.xml中加入引用:

<ResourceLink name="jdbc/cdbank" global="jdbc/cdbank"  
      type="javax.sql.DataSource"/> 

<ResourceLink name="jdbc/mydb" global="jdbc/mydb"  
      type="javax.sql.DataSource"/> 


在這裏要說明一下,我用的項目發布方式是一個xml文件發布一個工程。
所以我把ResourceLink寫在context.xml中。
其實還可以配置到項目xml文件的context標簽裏。
如果你用的是server.xml方式發布的話,還可以在server.xml裏面的host下的context標簽裏
配置。例如:
<Host appBase="webapps" name="localhost">
<Context docBase="D:\ChinaDevelopmentBankJBPM\workSpace\dataSourceApp\WebContent"
path="/dataSourceApp" reloadable="true" debug="0" crossContext="true">
<Resource name="jdbc/mysql" type="javax.sql.DataSource" password="123456" maxIdle="2"
maxWait="5000" username="root" maxActive="4" />
</Context>
</Host>
總之都是要配置到context標簽裏,並且能被Tomcat讀取到就可以。至於那種方式更方便
那就要根據自己的選擇了,實質其實都一樣,即context.xml文件對應<Context>標簽裏的內容。
只要裏面能被Tomcat讀取到就可以。




完整context.xml如下:

<?xml version=‘1.0‘ encoding=‘utf-8‘?>

<!-- The contents of this file will be loaded for each web application -->
<Context>

    <ResourceLink name="jdbc/cdbank" global="jdbc/cdbank"  
      type="javax.sql.DataSource"/> 
	<ResourceLink name="jdbc/mydb" global="jdbc/mydb"  
      type="javax.sql.DataSource"/> 


    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
	
	
</Context>

四,在web.xml中加入<resource-ref>。

<resource-ref>  
        <description>tomcat datasource test,one oracle datasource</description>  
        <res-ref-name>jdbc/cdbank</res-ref-name>  
        <res-type>javax.sql.DataSource</res-type>  
        <res-auth>Container</res-auth>  
    </resource-ref>
    
    <resource-ref>  
        <description>tomcat datasource test,one mysql datasource</description>  
        <res-ref-name>jdbc/mydb</res-ref-name>  
        <res-type>javax.sql.DataSource</res-type>  
        <res-auth>Container</res-auth>  
    </resource-ref>

關於這一步,我做過測試,其實是不用的!
寫上也不會報錯。為什麽會有這一步,大概是網上都是這麽說的吧。
或者還有更深的意義。反正我這裏做的實際測試結果就是沒必要。
寫上也不會起什麽作用,也不報錯。


我的完整web.xml如下;
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  
   <!-- tomcat數據源start -->
   <!--
   <resource-ref>  
        <description>tomcat datasource test,one oracle datasource</description>  
        <res-ref-name>jdbc/cdbank</res-ref-name>  
        <res-type>javax.sql.DataSource</res-type>  
        <res-auth>Container</res-auth>  
    </resource-ref>
    
    <resource-ref>  
        <description>tomcat datasource test,one mysql datasource</description>  
        <res-ref-name>jdbc/mydb</res-ref-name>  
        <res-type>javax.sql.DataSource</res-type>  
        <res-auth>Container</res-auth>  
    </resource-ref>
    -->
  
    <servlet>
		<servlet-name>TestServlet</servlet-name>
		<servlet-class>
			 org.test.TestServlet
		</servlet-class>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>TestServlet</servlet-name>
		<url-pattern>/TestServlet</url-pattern>
	</servlet-mapping>
    <!-- tomcat數據源 end -->
    
</web-app>

#############################################################


寫一個servlet來做測試TestServlet:
package org.test;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.test.util.DataSourceUtil;

public class TestServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	
	public void init() throws ServletException {
		System.out.println(TestServlet.class.getName() + " is inited");
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("doGet");
		doPost(req, resp);
	}

	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("doPost");

		// 編碼設置
		resp.setContentType("text/html");
		resp.setHeader("Cache-Control", "no-cache");
		resp.setCharacterEncoding("UTF-8");
		
		oneEditCase(req,resp);//業務開始
		resp.getWriter().println("success!");
	}

	public void oneEditCase(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("oneEditCase start");
		
		//oracle數據庫對象
        Connection conn=null;
        PreparedStatement pstmt=null;
        ResultSet rs =null;
        
        //mysql數據庫對象
        Connection conn_mysql=null;
        PreparedStatement pstmt_mysql=null;
        ResultSet rs_mysql =null;
        
		try {
//			conn = DataSourceUtil.getJNDIOracleDataSourceConnection();
			conn = DataSourceUtil.getDataSourceOracleCdbankConnection();
			conn_mysql=DataSourceUtil.getDataSourceMysqlMydbConnection();
			
			conn.setAutoCommit(false);// 更改事務的提交方式
			conn_mysql.setAutoCommit(false);
			
			String sql_select2 = " select t.dep_name,t.company  from LSY_DEPARTMENT  t where t.dep_id=‘11‘ ";
			pstmt = conn.prepareStatement(sql_select2);//查詢
			rs = pstmt.executeQuery();
			
			while(rs.next()){
				System.out.println("查到數據。。。");
				String dep_name=rs.getString("dep_name");
				String company=rs.getString("company");
				System.out.println(dep_name+"--"+company);
				
				company+="haha";
				String sql_update2 = " update LSY_DEPARTMENT a set a.company=‘"+company+"‘  where a.dep_id=‘11‘ ";
				
				pstmt = conn.prepareStatement(sql_update2);//更新oracle數據庫字段
				pstmt.execute();
				
				//一下開始對另外的mysql數據庫進行同步更新
				String sql_mysql_select="select DEP_ID	from  lsy_department where dep_id=‘11‘ ";
				pstmt_mysql = conn_mysql.prepareStatement(sql_mysql_select);//查詢是否存在該數據
				rs_mysql = pstmt_mysql.executeQuery();
				
				if(rs_mysql.next()){
					System.out.println("存在相同的數據,就更新相關字段");
					String sql_mysql_update="update mydb.lsy_department set " +
							"  DEP_NAME = ‘"+dep_name+"‘ , " +
							" COMPANY = ‘"+company+"‘ " +
							" where DEP_ID = ‘11‘ ";
					pstmt_mysql = conn_mysql.prepareStatement(sql_mysql_update);
					pstmt_mysql.execute();
				}else{
					System.out.println("不存在相同的數據,就作為新數據插入");
					String sql_mysql_insert="insert into lsy_department (DEP_ID, DEP_NAME, COMPANY) values(‘11‘, ‘"+dep_name+"‘, ‘"+company+"‘) ";
					pstmt_mysql = conn_mysql.prepareStatement(sql_mysql_insert);
					pstmt_mysql.execute();
				}
				conn_mysql.commit();
				conn_mysql.setAutoCommit(true);
			}
			conn.commit();//提交事務
			conn.setAutoCommit(true);// 恢復事務的默認提交方式
			
		}catch (SQLException e) {
			try {
				System.out.println("提交發生錯誤,開始回滾事務...");
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally{
			try {
				if(rs != null){
					rs.close();
				}
				if(pstmt != null){
					pstmt.close();
				}
				if(conn != null){
					conn.close();
				}
				if(rs_mysql != null){
					rs_mysql.close();
				}
				if(pstmt_mysql != null){
					pstmt_mysql.close();
				}
				if(conn_mysql != null){
					conn_mysql.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
		
	}

}


裏面需要一個工具類來管理連接DataSourceUtil:
package org.test.util;

import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DataSourceUtil {
	
	private static DataSource dataSource_oracle_cdbank=null;//一個oracle數據源
	private static DataSource dataSource_mysql_mydb=null;//一個mysql數據源
	
	//若果只需要從一個數據源獲取鏈接就可以向下面這樣寫。否則,把DataSource單獨提出。
//	public static Connection getJNDIOracleDataSourceConnection(){
//		Connection conn=null;
//		InitialContext ctx=null;
//		try {
//			ctx = new InitialContext();
//			if(dataSource_oracle_cdbank == null){
//				System.out.println("dataSource_oracle_cdbank start connnectiong...");
//				
//				//獲取數據源,其中java:comp/env是Tomcat規定的,Tomcat提供的JNDI綁定都必須加該前綴。後面就是Resource的name屬性
//				dataSource_oracle_cdbank = (DataSource)ctx.lookup("java:comp/env/jdbc/cdbank");//context.xml 文件裏 Resource 項下 name 的值 "jdbc/qwe"
//				
//				if(dataSource_oracle_cdbank != null){
//					//獲取鏈接(根據需要可以獲取多個)
//					conn= dataSource_oracle_cdbank.getConnection();
//				}else{
//					System.out.println("連接發生異常...");
//				}
//			}
//		}catch(NamingException e) {
//			e.printStackTrace();
//		}catch (SQLException e) {
//			e.printStackTrace();
//		}
//		
//		return conn;
//	}
	
	//獲取oracle的DataSource
	public static DataSource getDataSourceOracleCdbank(){
		InitialContext ctx=null;
		try {
			ctx = new InitialContext();
			if(dataSource_oracle_cdbank == null){
				System.out.println("dataSource_oracle_cdbank start connnectiong...");
				//獲取數據源,其中java:comp/env是Tomcat規定的,Tomcat提供的JNDI綁定都必須加該前綴。後面就是Resource的name屬性
				dataSource_oracle_cdbank = (DataSource)ctx.lookup("java:comp/env/jdbc/cdbank");//context.xml 文件裏 Resource 項下 name 的值 "jdbc/qwe"
				
			}
		}catch(NamingException e) {
			e.printStackTrace();
		}
		
		return dataSource_oracle_cdbank;
	
	}
	//獲取DataSource對象
	public static DataSource getDataSourceOracleCdbankInstance(){
		if(dataSource_oracle_cdbank==null){
			dataSource_oracle_cdbank=getDataSourceOracleCdbank();
		}
		return dataSource_oracle_cdbank;
	}
	//獲取Connection
	public static Connection getDataSourceOracleCdbankConnection(){
		Connection conn=null;
		try {
			if(getDataSourceOracleCdbankInstance() != null){
				//獲取鏈接(根據需要可以獲取多個)
				conn= getDataSourceOracleCdbankInstance().getConnection();
			}else{
				System.out.println("連接發生異常...");
			}
		}catch (SQLException e) {
			e.printStackTrace();
		}
		
		return conn;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	//獲取mysql的DataSource
	public static DataSource getDataSourceMysqlMydb(){
		InitialContext ctx=null;
		try {
			ctx = new InitialContext();
			if(dataSource_mysql_mydb == null){
				System.out.println("dataSource_mysql_mydb start connnectiong...");
				//獲取數據源,其中java:comp/env是Tomcat規定的,Tomcat提供的JNDI綁定都必須加該前綴。後面就是Resource的name屬性
				dataSource_mysql_mydb = (DataSource)ctx.lookup("java:comp/env/jdbc/mydb");
				
			}
		}catch(NamingException e) {
			e.printStackTrace();
		}
		
		return dataSource_mysql_mydb;
	
	}
	//獲取DataSource對象
	public static DataSource getDataSourceMysqlMydbInstance(){
		if(dataSource_mysql_mydb==null){
			dataSource_mysql_mydb=getDataSourceMysqlMydb();
		}
		return dataSource_mysql_mydb;
	}
	//獲取Connection
	public static Connection getDataSourceMysqlMydbConnection(){
		Connection conn=null;
		try {
			if(getDataSourceMysqlMydbInstance() != null){
				//獲取鏈接(根據需要可以獲取多個)
				conn= getDataSourceMysqlMydbInstance().getConnection();
			}else{
				System.out.println("連接發生異常...");
			}
		}catch (SQLException e) {
			e.printStackTrace();
		}
		
		return conn;
	}
	
}


第一次訪問http://localhost:8080/dataSourceApp/TestServlet


打印:
org.test.TestServlet is inited
doGet
doPost
oneEditCase start
dataSource_oracle_cdbank start connnectiong...
dataSource_mysql_mydb start connnectiong...
查到數據。。。
研發部--百度
不存在相同的數據,就作為新數據插入



第二次訪問http://localhost:8080/dataSourceApp/TestServlet


打印:
doGet
doPost
oneEditCase start
查到數據。。。
研發部--百度haha
存在相同的數據,就更新相關字段


同時兩個數據庫的值都已經正確修改。

再說些廢話,jndi的數據源對象也可以在spring註冊。
大多數情況,應該不會用到。
為什麽呢?如果你用到了spring,你完全可以把新的數據源配置到spring裏,
當然不會是使用jndi了,完全可以使用c3p0,dbcp,或者jdbc。
同時遷移服務器的時候也好遷移。
如果已經使用了spring,再去配置JNDI數據源,感覺像殺雞用牛刀。
JNDI的方式,我覺得大多數情況使用小型的應用,或者做數據處理,比如兩個數據庫
之間的數據傳遞(不是簡簡單單的倒庫)。我的例子就是這種情況。
小型的應用,功能很少,這樣配置數據源還是很方便的(jdbc也不錯)

JNDI數據源(在Tomcat下配置JNDI多數據源實例)