数据连接学习(一):JNDI入门及数据源配置


0.学习原因

因为学习Spring时涉及到了很多关于JNDI的知识,卧槽,压根没听说过呀,所以特地来学习一下。
参考博客:
JNDI学习总结(一)——JNDI数据源的配置


1.JNDI的诞生及简介简介

1)服务器数据源配置的诞生

  1. JDBC阶段:
    一开始是使用JDBC来连接操作数据库的:
    在Java开发中,使用JDBC操作数据库的四个步骤如下:

    ①加载数据库驱动程序(Class.forName("数据库驱动类");)
    ②连接数据库(Connection con = DriverManager.getConnection();)
    ③操作数据库(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)
    ④关闭数据库,释放连接(con.close();)

  2. 所有的用户都需要经过此四步进行操作,但是这四步之中有三步(①加载数据库驱动程序、②连接数据库、④关闭数据库,释放连接)对所有人都是一样的,而所有人只有在操作数据库上是不一样,那么这就造成了性能的损耗。
    那么最好的做法是,准备出一个空间,此空间里专门保存着全部的数据库连接,以后用户用数据库操作的时候不用再重新加载驱动、连接数据库之类的,而直接从此空间中取走连接,关闭的时候直接把连接放回到此空间之中。
    而这个空间就是连接池

  3. 但是连接池的是有会有以下疑虑:

    1、 如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。
    2、 如果连接已经满了,则必须打开新的连接,供更多用户使用。
    3、 如果一个服务器就只能有100个连接,那么如果有第101个人过来呢?应该等待其他用户释放连接
    4、 如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。

  4. 如果直接用程序实现以上功能,则会比较麻烦。
    所以在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项,直接在服务器上配置好数据源连接池即可。在J2EE服务器上保存着一个数据库的多个连接。每一个连接通过DataSource可以找到。DataSource被绑定在了JNDI树上(为每一个DataSource提供一个名字)客户端通过名称找到在JNDI树上绑定的DataSource,再由DataSource找到一个连接。

  5. 示意图如下:


    00042JNDI学习1-01.jpg
  6. 网上流传的图:


    00042JNDI学习1-02.jpg
  7. 那么在以后的操作中,除了数据库的连接方式不一样之外,其他的所有操作都一样,只是关闭的时候不是彻底地关闭数据库,而是把数据库的连接放回到连接池中去。

2)JNDI的简介及优点:

  1. JNDI的定义:
    上面知道了JNDI的作用,JNDI的定义也就很容易理解了:
    JNDI是Java命名与文件夹接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之中的一个。
    简单的理解,区别于JDBC,就是:
    jdbc是java去找数据库驱动,jndi是通过你的服务器配置(如Tomcat)的配置文件context来找数据库驱动~
  2. 现在JNDI已经成为J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务。(web容器就是Tomcat等服务器充当的)
  3. 为什么使用了连接池还要用JNDI:

    为了数据库资源的管理,在容器中配置一个数据库连接池,使用JNDI 来管理
    这样容器中运行多个服务的时候,每个服务只需添加一个jndi的名称就可以连接到数据库了
    如果不使用jndi的方式,直接在项目中配置数据库连接池,那么每个项目需要配置一次,如果更改数据库地址时,
    每个项目的数据库连接方式都要更改,比较麻烦,使用jndi的话,直接更改一下jndi里面的数据库连接池的配置就可以了,方便一些。

  4. 一般来说如果目标客户有专业的应用服务器,比如 WebSphere,WebLogic,我们就不需要在代码中配置使用特定的 dbcp 或其它的连接池了。只使用JNDI就可以了。

2.JNDI+Tomcat配置数据源(全局配置)

1)Tomcat全局配置:

  1. 需要在tomcat中的server.xml中配置数据源:


    00042JNDI学习1-03.jpg
  2. 在Tomcat的lib目录下添加驱动包:


    00042JNDI学习1-04.jpg
  3. 打开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>
  1. 在默认的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&amp;characterEncoding=utf-8"/>
    

各项配置的含义后面介绍。

  1. 以上两步(导包+配置server.xml)全局配置就已经配置好了。
    这一步并非必须的,可以不写,亲测没有失败
    在需要使用的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,否则会报错。

  1. 查看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>
  1. 这一步可以替换第6步(写了这个则不用配置第六步):
    在项目的META-INF下面建立context.xml文件,在里面写上:

     <?xml version="1.0" encoding="UTF-8"?> 
     <Context> 
         <ResourceLink name="mysqlData" global="jdbc/mysql type="javax.sql.DataSource"/> 
     </Context>
    
  2. 第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)创建测试类代码:

  1. 创建测试类:(最简单的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); 
     %> 
    
  2. 测试结果:


    00042JNDI学习1-07.jpg

成功获取到数据源(javax.sql.datasource对象)。

  1. 注意事项:
    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,现在配置的是一个jdbc的关于oracle的命名服务。
    |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效
    |- type:此名称所代表的类型,现在为javax.sql.DataSource
    |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数
    |- maxIdle:表示一个数据库在此服务器上维持的最小连接数
    |- maxWait:最大等待时间。10000毫秒
    |- username:数据库连接的用户名
    |- password:数据库连接的密码
    |- driverClassName:数据库连接的驱动程序
    |- url:数据库连接的地址
    -->
    
    <!--配置Oracle数据库的JNDI数据源-->
    <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数据库的JNDI数据源-->
    <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&amp;characterEncoding=utf-8"/>
    
    <!--配置SQLServer数据库的JNDI数据源-->
    <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配置数据源(局部配置)

1)简单思路

  1. 非全局JNDI数据源是针对某一个Web项目配置的数据源,具体的配置步骤如下:
    1、在tomcat服务器的lib目录下加入数据库连接的驱动jar包
    2、针对具体的web项目映射虚拟目录,然后在虚拟目录映射的配置文件中配置JNDI数据源
  2. 还有一个更简单的思路:
    就是将上述引用全局配置的地方改为和全局配置相同的那样的配置,并将全局配置删除。
    所以共有三种方法(conf/context.xml中配置的可能是全局的)
  3. 正常使用的话还是用全局配置吧。

2)配置过程及几种方法:
配置模板和全局配置的相同。

  1. 方法一:修改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>
    
  2. 方法二:在项目的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> 
    
  3. 方法三:配置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标签中的路径改为项目路径就是局部配置了。

  1. 测试类和全局配置的相同,我也不测试了。

4.关于配置JNDI的总结

  1. 全局配置的思路图(虚线为非必须):


    00042JNDI学习1-09.jpg
  2. 局部配置就不画了,差不多。

  3. 以上步骤就能配置数据源了,至于获取了DataSource怎么操作数据,那就是javax.sql.DataSource的事情了,以后再学。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容