我们知道 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高级应用的更多相关文章

  1. JAVA高级编程数据源datasource

    原文链接 数据源 通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: ...

  2. JAVA高级编程(数据源datasource)

    数据源:通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: comm ...

  3. Mybatis高级查询之关联查询

    learn from:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps 关联查询 准备 关联结果查询(一对一) resul ...

  4. Webform(Linq高级查、分页、组合查询)

    一.linq高级查 1.模糊查(包含) 1 public List<User> Select(string name) 2 { 3 return con.User.Where(r => ...

  5. 如何轻松实现iOS9多任务管理器效果(iCarousel高级教程)

    前言 iOS9系统下 为了我司APP的兼容性问题 特意把手上的iOS Mac XCode都升级到了最新的beta版 然后发现iOS9的多任务管理器风格大变 变成了下面这种样子 我忽然想起来之前的文章提 ...

  6. 六 mybatis高级映射(一对一,一对多,多对多)

    1  订单商品数据模型 以订单商品数据为模型,来对mybaits高级关系映射进行学习.

  7. sp.net2.0中的新增控件BulletedList的一些高级用法

    asp.net2.0新增了一个BulletedList控件,通过它可以以列表形式显示数据,而不必再用Repeater,Datalist等实现相同的效果.今天做程序的时候正好用到了这个控件,就把它的一些 ...

  8. Java数据库连接——JDBC调用存储过程,事务管理和高级应用

    一.JDBC常用的API深入详解及存储过程的调用 相关链接:Jdbc调用存储过程 1.存储过程(Stored Procedure)的介绍 我们常用的操作数据库语言SQL语句在执行的时候需要先编译,然后 ...

  9. iOS开发——高级UI&带你玩转UITableView

    带你玩装UITableView 在实际iOS开发中UITableView是使用最多,也是最重要的一个控件,如果你不会用它,那别说什么大神了,菜鸟都不如. 其实关于UItableView事非常简单的,实 ...

随机推荐

  1. C# Xml文件操作,解释见注释

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. ICON文件保存

    这两天想做一下windows系统下图标的修改,让程序有更新的时候能够更新图标的外观,达到提醒的作用,360,QQ经常采用这种方式进行更新的提示,也有采用弹框的方式来提示,用新版QVOD的同事可能见到过 ...

  3. wflag

    http://stackoverflow.com/questions/41312622/how-to-echo-an-alert-in-php-a-string-some-confusion-with ...

  4. kuaisupaixu

    #include<stdio.h> void quiksort(int a[],int low,int high) {  int i = low;     int j = high;    ...

  5. linux指定目录安装软件后,程序找不到共享库问题

    以svn为例,64位centos yum install subversion --installroot=/usr/svn/后 执行svn命令,报错svn: error while loading ...

  6. 【转】最简单的CI框架入门示例--数据库取数据

    1.下载CI框架(自己找) 2.配置 database.php配置:    为数据库服务器设置 connection 参数: $db['default']['hostname'] = "yo ...

  7. 应用github pages创建自己的个人博客

    首先你需要注册自己的github账号 1.登录或者注册github,登录之后点击右上角的“+”号,选择“New repository”菜单,创建仓库,用于存储和博客相关的源文件. 2.跳转页面将填写域 ...

  8. Mongo中的数据类型

    一.null null用于表示空值或者不存在的字段 {"X" : null} 二.布尔型 布尔类型有两个值true和false {"x" : true} 三.数 ...

  9. ubuntu下交叉编译windows c程序

    简介 采用mingw32可以在linux下直接编译c程序输出为windows下的exe程序或dll链接库. 个人编译的纯c程序(不含winapi),主要是c99程序,通常采用gcc/cc编译调试后,再 ...

  10. Bulk Insert & BCP执行效率对比(续)

    上回由于磁盘空间(约70G)不足,导致Bulk Insert和BCP导入中途失败:今次统一一些操作,以得到Bulk insert与BCP分别执行效率: 1. 15435390笔数据,21.7G csv ...