【转】DataSource高级应用

摘要:
因为获取Connect的bean需要引用DataSource,所以只有在第一次调用ConnectionFactory时才会搜索DataSource。在其他情况下,只要不发生意外(目前,我想不出任何事情会使不为null的DataSource突然变为null),它就不再需要搜索和直接引用。如果不将DataSource声明为静态,

我们知道 DataSource能提供最高性能的对数据库的并发访问,
但是,对DataSource的引用,也还有很多知识要弄清楚,获取Connection的方式是数据库性能最相
关的技术,而对DataSource的调用对数据库性能起着很大的决定作用。
    一般对于DataSource的引用是通过以下流程来进行:

 Context ct = new InitialContext();
 DataSource ds = (DataSource) ct.lookup(sourceUrl);

    就这么简单的两行,但其调用条件不同却可以产生性能上巨大的差别。因为一个取得
Connect的封装类(Bean)要对DataSource的引用,会有着多种方式。如果是作为一个普通的封
装类,我们可以在构造方法中调用,而作为javaBean可以在init方法中调用,但无论要哪儿调用,
当我们对这个类或Bean进行调用时,都要对DataSource进行查找。其实DataSource的查找过程也
是一个相当消耗资源的过程,所以我们应该把DataSource声明为静态资源,因为即使你对封装类
或Bean中每次调用都进行一次查找,事实上你得到的DataSource还是那个不变的唯一的资源。那
么为什么不把它声明为static呢?这样只在需要的时候才去查找,而更多的时候就可以直接对已
经查找到的DataSource进行直接引用:

public class ConnectionFactory{
     static DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(source);
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

我们看到,一般情况下,只有当第一次调用ConnectionFactory时才会对DataSource进行查找,而
其它时候只要不发生意外(目前我还想不出有什么情况会使原来不是null的DataSource突然null)
就不再需要查找而直接引用了.而如果你不把DataSource声明为静态的,那么每次对调用
ConnectionFactory都要产生一次jndi的查找:

public class ConnectionFactory{
     DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            Context ct = new InitialContext();
            dsCache = (DataSource) ct.lookup(source);
        }
        Connection conn = dsCache.getConnection();
    }
}

因为dsCache不是静态资源,所以每次调用,if(dsCache==null)都成立.
有人说那Connection如果也是静态的那不也节省资源了吗?注意Connection不是工场,如果多个用
户同时对同一Connection访问,那么任何人都不能关闭Connection,而最后变成谁也没有关闭
Connection,因为最后一次使用的用户根本不知道后面到底是否有人要使用.另一方面,一个
Connection处理能力很低,不可能同时满足很多用户同时对数据库存取数据.而DataSource虽然是
多个用户对同一资源的引用,但它是工厂,不同用户访问同一DataSource得到的是不同的Connection
资源.

为了对特定DataSource进行查找,我们要对jndi的引用进行配置,一般来说,如果一个封装类或Bean
不可能将jndi引用字符串写死要代码中,可以放在配置文件中然后读取:

    Properties properties = new Properties();
    properties.load(new FileInputStream("配置文件"));
    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));

这样在我们要修改DataSource时就可以难过修改"配置文件"而不要重新编译ConnectionFactory,但
是如果是对一个容器下的多个应用同时配置了多个DataSource,我们根本无法指定到底查打哪个数据
源,所以最好能重载一个方法,无论是构造方法还是其它方法都应该重载一个根据参数查找的方法:

public class ConnectionFactory{
     static DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Properties properties = new Properties();
                    properties.load(new FileInputStream("配置文件"));
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
    aMethodForGetConnectio(String source){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(source);
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

另外对于默认的查找字符串,我们仍然可以做进一步的优化,不过即使每次读取属性,性能也没有太大的影响:

public class ConnectionFactory{
     static DataSource dsCache = null;
     static Properties properties = new Properties();
    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    if(!properties.containsKey("key"))
                        properties.load(new FileInputStream("配置文件"));
                    //只有在没有找到属性时才去再读配置文件
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

通过以上优化,可以使你的封装类以最低的资源消耗来获取最大的性能.我们可以这样来进行测试:
把if(dsCache == null){}发生时的情况记录到日志中,看看什么时候发生了这种异常,我对我的数据库进行了
跟踪,我们给青岛日报社做的一台邮件系统主机上有6万多用户,同时并发的访问量很大,但日记记录,只有每次
重启动应用的时候才产生一条记录,也就是ConnectionFactory第一次调用时才产生日志,其它情况非常正常:

public class ConnectionFactory{
     static DataSource dsCache = null;
     static Properties properties = new Properties();
    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    if(!properties.containsKey("key"))
                        properties.load(new FileInputStream("配置文件"));
                    //只有在没有找到属性时才去再读配置文件
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
            //当发生dsCache == null时,记录下发生对该方法的调用者:
            PrintWriter pw = new PrintWriter(new FileWriter("connection.log",true));
            pw.println(new java.util.Date() + ":当前方法名如aMethodForGetConnectio():"
                    + sun.reflect.Reflection.getCallerClass(2));
            pw.close();
        }
        Connection conn = dsCache.getConnection();
    }
}

主要记录当前日期,当前方法名称和是哪个类调用了该方法.sun.reflect.Reflection.getCallerClass(int i)
方法中,i为0是Reflection本身,1是Bean或封装类,就是ConnectionFactory,2就是调用它的类,3以上不确定.这样
你可以把你的封装类或Bean进行一段时间(至少几天以上)跟踪,如果应用一直没有重启动,那就应该只产生一条
记录.这样你就有了一个顶级性能的封装类了

转自:

DataSource高级应用

免责声明:文章转载自《【转】DataSource高级应用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇.NET Core 如何部署到Docker(菜鸟篇)mount 命令总结下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JBoss配置连接池

         什么是数据库连接池?          配置连接池为的是解决效率问题.由于每创建一个连接都是非常耗时的,有了连接池,就能够提前放一些连接进去.以后我们再用连接就去连接池里面取而不是每次都创建.可是我们知道连接池是有上限的,假设仅仅同意我们放10个,那么当这10个连接都被占用的时候,下一个用户再来请求连接将不能得到,仅仅好等待,假设等的时...

JAVA学习总结(四)

1.接口 interface 1.1语法:   修饰符 interface 接口名{     常量     都是抽象方法  } 修饰符:默认 | public接口名:自定义,规则与类名相同,一般I字母打头:wifi接口(Iwifi) //示例: public interface Iwifi{ int COUNT=1;...

vim命令删除后重新安装

个人原创博客,转载请注明,否则追究法律责任 2017-09-30-09:51:20 1,删除vim命令。模拟错误 [root@localhost ~]# which vim/usr/bin/vim[root@localhost ~]# rpm -qf /usr/bin/vimvim-enhanced-7.4.160-1.el7.x86_64[root@lo...

java final .static修饰符

static静态修饰符(使用static修饰符修饰的成员变量、常量、和成员方法成为静态变量、常量和方法,他们统称为静态成员,归整个类所有,不依赖于类的特定实例,被类的所有实例共享,只要这个类被加载,JVM就可以根据类名在运行时数据区的方法区找到他们) 静态变量 对于静态变量,运行时,JVM只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配。在...

RxJava学习(一)

注意:文字和图片转载自抛物线博客 参考:http://gank.io/post/560e15be2dca930e00da1083 RxJava 到底是什么 一个词:异步。 RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs usin...

设计模式之禅之设计模式-建造者模式

一:建造者模式的定义        --->建造者模式(Builder Pattern)也叫做生成器模式,其定义如下:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示        ● Product产品类                通常是实现了模板方法模式,也就是有模板方法和基本方法,这个参考模板方法模式。例子中的Ben...