J2EE 开发工程师应该掌握的知识点

Posted on

J2EE 开发工程师应该掌握的知识点

J2EE 开发工程师应该掌握的知识点

1.Servlet 包括session的治理 采用Servlet Context访问resource jsp技术 web层的模式:Service-to-Worker, Dispatcher View, and Business Delegate patterns web应用的MVC Pattern Handling Errors in Web Applications 配置web Application的安全 web application的并发访问 2.事务处理 3.安全策略 4.需求分析 基本的架构设计方法 创建Use Case Diagram UML图 5.基本的设计模式把握 Composite pattern. Strategy pattern. Observer pattern. Abstract Factory pattern. 6.ejb 打包和部署EJB CMP BMP Message-Driven Beans CMP BMP 的事务实现 异常处理 定时服务 采用stateless bean实现webserive EJB架构的最佳实践 7.J2EE J2EE的安全架构实现 Fundamental Architectural Concepts和 five primary concerns of architecture J2EE中Inside the Tier ,Tier-to-Tier Communication的优化 8.Java编程语言 语法 控制语句 数据类型 异常 线程 I/O Networking

用连接池提高Servlet访问数据库的效率 (

Posted on

用连接池提高Servlet访问数据库的效率 (-).txt

作者:jeru

日期:2000-12-7 11:45:06 Java Servlet作为首选的服务器端数据处理技术,正在迅速取代CGI脚本。Servlet超越CGI的优势之一在于,不仅多个请求

可以共享公用资源,而且还可以在不同用户请求之间保留持续数据。本文介绍一种充分发挥该特色的实用技术,即数据库连 接池。

一、实现连接池的意义

动态Web站点往往用数据库存储的信息生成Web页面,每一个页面请求导致一次数据库访问。连接 数据库不仅要开销一定的通讯和内存资源,还必须完成用户验证、安全上下文配置这类任务,因而往往成为最为耗时的操

作。当然,实际的连接时间开销千变万化,但1到2秒延迟并非不常见。如果某个基于数据库的Web应用只需建立一次初始连 接,不同页面请求能够共享同一连接,就能获得显著的性能改善。

Servlet是一个Java类。Servlet引擎(它可能是Web服务软件的一部分,也可能是一个独立的附加模块)在系统启动或Servlet 第一次被请求时将该类装入Java虚拟机并创建它的一个实例。不同用户请求由同一Servlet实例的多个独立线程处理。那些要

求在不同请求之间持续有效的数据既可以用Servlet的实例变量来保存,也可以保存在独立的辅助对象中。 用JDBC访问数据库首先要创建与数据库之间的连接,获得一个连接对象(Connection),由连接对象提供执行SQL语句的方法。

本文介绍的数据库连接池包括一个管理类DBConnectionManager,负责提供与多个连接池对象(DBConnectionPool类)之间 的接口。每一个连接池对象管理一组JDBC连接对象,每一个连接对象可以被任意数量的Servlet共享。

类DBConnectionPool提供以下功能:

1) 从连接池获取(或创建)可用连接。 2) 把连接返回给连接池。

3) 在系统关闭时释放所有资源,关闭所有连接。

此外, DBConnectionPool类还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题) ,并能够限制连接池中的连接总数不超过某个预定值。

管理类DBConnectionManager用于管理多个连接池对象,它提供以下功能:

1) 装载和注册JDBC驱动程序。 2) 根据在属性文件中定义的属性创建连接池对象。

3) 实现连接池名字与其实例之间的映射。 4) 跟踪客户程序对连接池的引用,保证在最后一个客户程序结束时安全地关闭所有连接池。

本文余下部分将详细说明这两个类,最后给出一个示例演示Servlet使用连接池的一般过程。

二、具体实现

DBConnectionManager.java程序清单如下:

001 import java.io./; 002 import java.sql./;

003 import java.util./*; 004 import java.util.Date;

005 006 ///

007 / 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接 008 / 池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.

009 /*/ 010 public class DBConnectionManager {

011 static private DBConnectionManager instance; // 唯一实例 012 static private int clients;

013 014 private Vector drivers = new Vector();

015 private PrintWriter log; 016 private Hashtable pools = new Hashtable();

017 018 ///

019 / 返回唯一实例.如果是第一次调用此方法,则创建实例 020 /

021 / @return DBConnectionManager 唯一实例 022 //

023 static synchronized public DBConnectionManager getInstance() { 024 if (instance == null) {

025 instance = new DBConnectionManager(); 026 }

027 clients++; 028 return instance;

029 } 030

031 /// 032 /* 建构函数私有以防止其它对象创建本类实例

033 /*/ 034 private DBConnectionManager() {

035 init(); 036 }

037 038 ///

039 / 将连接对象返回给由名字指定的连接池 040 /

041 / @param name 在属性文件中定义的连接池名字 042 / @param con 连接对象

043 /*/ 044 public void freeConnection(String name, Connection con) {

045 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 046 if (pool != null) {

047 pool.freeConnection(con); 048 }

049 } 050

051 /// 052 /* 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数

053 / 限制,则创建并返回新连接 054 /

055 / @param name 在属性文件中定义的连接池名字 056 / @return Connection 可用连接或null

057 /*/ 058 public Connection getConnection(String name) {

059 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 060 if (pool != null) {

061 return pool.getConnection(); 062 }

063 return null; 064 }

065 066 ///

067 / 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 068 / 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.

069 / 070 / @param name 连接池名字

071 / @param time 以毫秒计的等待时间 072 / @return Connection 可用连接或null

073 /*/ 074 public Connection getConnection(String name, long time) {

075 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 076 if (pool != null) {

077 return pool.getConnection(time); 078 }

079 return null; 080 }

081 082 ///

083 / 关闭所有连接,撤销驱动程序的注册 084 //

085 public synchronized void release() { 086 // 等待直到最后一个客户程序调用

087 if (--clients != 0) { 088 return;

089 } 090

091 Enumeration allPools = pools.elements(); 092 while (allPools.hasMoreElements()) {

093 DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); 094 pool.release();

095 } 096 Enumeration allDrivers = drivers.elements();

097 while (allDrivers.hasMoreElements()) { 098 Driver driver = (Driver) allDrivers.nextElement();

099 try { 100 DriverManager.deregisterDriver(driver);

101 log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册"); 102 }

103 catch (SQLException e) { 104 log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());

105 } 106 }

107 } 108

109 /// 110 /* 根据指定属性创建连接池实例.

111 / 112 / @param props 连接池属性

113 /*/ 114 private void createPools(Properties props) {

115 Enumeration propNames = props.propertyNames(); 116 while (propNames.hasMoreElements()) {

117 String name = (String) propNames.nextElement(); 118 if (name.endsWith(".url")) {

119 String poolName = name.substring(0, name.lastIndexOf(".")); 120 String url = props.getProperty(poolName + ".url");

121 if (url == null) { 122 log("没有为连接池" + poolName + "指定URL");

123 continue; 124 }

125 String user = props.getProperty(poolName + ".user"); 126 String password = props.getProperty(poolName + ".password");

127 String maxconn = props.getProperty(poolName + ".maxconn", "0"); 128 int max;

129 try { 130 max = Integer.valueOf(maxconn).intValue();

131 } 132 catch (NumberFormatException e) {

133 log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName); 134 max = 0;

135 } 136 DBConnectionPool pool =

137 new DBConnectionPool(poolName, url, user, password, max); 138 pools.put(poolName, pool);

139 log("成功创建连接池" + poolName); 140 }

141 } 142 }

143 144 ///

145 / 读取属性完成初始化 146 //

147 private void init() { 148 InputStream is = getClass().getResourceAsStream("/db.properties");

149 Properties dbProps = new Properties(); 150 try {

151 dbProps.load(is); 152 }

153 catch (Exception e) { 154 System.err.println("不能读取属性文件. " +

155 "请确保db.properties在CLASSPATH指定的路径中"); 156 return;

157 } 158 String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log");

159 try { 160 log = new PrintWriter(new FileWriter(logFile, true), true);

161 } 162 catch (IOException e) {

163 System.err.println("无法打开日志文件: " + logFile); 164 log = new PrintWriter(System.err);

165 } 166 loadDrivers(dbProps);

167 createPools(dbProps); 168 }

169 170 ///

171 / 装载和注册所有JDBC驱动程序 172 /

173 / @param props 属性 174 //

175 private void loadDrivers(Properties props) { 176 String driverClasses = props.getProperty("drivers");

177 StringTokenizer st = new StringTokenizer(driverClasses); 178 while (st.hasMoreElements()) {

179 String driverClassName = st.nextToken().trim(); 180 try {

181 Driver driver = (Driver) 182 Class.forName(driverClassName).newInstance();

183 DriverManager.registerDriver(driver); 184 drivers.addElement(driver);

185 log("成功注册JDBC驱动程序" + driverClassName); 186 }

187 catch (Exception e) { 188 log("无法注册JDBC驱动程序: " +

189 driverClassName + ", 错误: " + e); 190 }

191 } 192 }

193 194 ///

195 / 将文本信息写入日志文件 196 //

197 private void log(String msg) { 198 log.println(new Date() + ": " + msg);

199 } 200

201 /// 202 /* 将文本信息与异常写入日志文件

203 /*/ 204 private void log(Throwable e, String msg) {

205 log.println(new Date() + ": " + msg); 206 e.printStackTrace(log);

207 } 208

209 /// 210 /* 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最

211 / 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性. 212 //

213 class DBConnectionPool { 214 private int checkedOut;

215 private Vector freeConnections = new Vector(); 216 private int maxConn;

217 private String name; 218 private String password;

219 private String URL; 220 private String user;

221 222 ///

223 / 创建新的连接池 224 /

225 / @param name 连接池名字 226 / @param URL 数据库的JDBC URL

227 / @param user 数据库帐号,或 null 228 / @param password 密码,或 null

229 / @param maxConn 此连接池允许建立的最大连接数 230 //

231 public DBConnectionPool(String name, String URL, String user, String password, 232 int maxConn) {

233 this.name = name; 234 this.URL = URL;

235 this.user = user; 236 this.password = password;

237 this.maxConn = maxConn; 238 }

239 240 ///

241 / 将不再使用的连接返回给连接池 242 /

243 / @param con 客户程序释放的连接 244 //

245 public synchronized void freeConnection(Connection con) { 246 // 将指定连接加入到向量末尾

247 freeConnections.addElement(con); 248 checkedOut--;

249 notifyAll(); 250 }

251 252 ///

253 / 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 254 / 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,

255 / 然后递归调用自己以尝试新的可用连接. 256 //

257 public synchronized Connection getConnection() { 258 Connection con = null;

259 if (freeConnections.size() > 0) { 260 // 获取向量中第一个可用连接

261 con = (Connection) freeConnections.firstElement(); 262 freeConnections.removeElementAt(0);

263 try { 264 if (con.isClosed()) {

265 log("从连接池" + name+"删除一个无效连接"); 266 // 递归调用自己,尝试再次获取可用连接

267 con = getConnection(); 268 }

269 } 270 catch (SQLException e) {

271 log("从连接池" + name+"删除一个无效连接"); 272 // 递归调用自己,尝试再次获取可用连接

273 con = getConnection(); 274 }

275 } 276 else if (maxConn == 0 || checkedOut < maxConn) {

277 con = newConnection(); 278 }

279 if (con != null) { 280 checkedOut++;

281 } 282 return con;

283 } 284

285 /// 286 /* 从连接池获取可用连接.可以指定客户程序能够等待的最长时间

287 / 参见前一个getConnection()方法. 288 /

289 / @param timeout 以毫秒计的等待时间限制 290 //

291 public synchronized Connection getConnection(long timeout) { 292 long startTime = new Date().getTime();

293 Connection con; 294 while ((con = getConnection()) == null) {

295 try { 296 wait(timeout);

297 } 298 catch (InterruptedException e) {}

299 if ((new Date().getTime() - startTime) >= timeout) { 300 // wait()返回的原因是超时

301 return null; 302 }

303 } 304 return con;

305 } 306

307 /// 308 /* 关闭所有连接

309 /*/ 310 public synchronized void release() {

311 Enumeration allConnections = freeConnections.elements(); 312 while (allConnections.hasMoreElements()) {

313 Connection con = (Connection) allConnections.nextElement(); 314 try {

315 con.close(); 316 log("关闭连接池" + name+"中的一个连接");

317 } 318 catch (SQLException e) {

319 log(e, "无法关闭连接池" + name+"中的连接"); 320 }

321 } 322 freeConnections.removeAllElements();

323 } 324

325 /// 326 /* 创建新的连接

327 /*/ 328 private Connection newConnection() {

329 Connection con = null; 330 try {

331 if (user == null) { 332 con = DriverManager.getConnection(URL);

333 } 334 else {

335 con = DriverManager.getConnection(URL, user, password); 336 }

337 log("连接池" + name+"创建一个新的连接"); 338 }

339 catch (SQLException e) { 340 log(e, "无法创建下列URL的连接: " + URL);

341 return null; 342 }

343 return con; 344 }

345 } 346 }

基于 Apache DBCP 的数据库连接获取类(原创)

Posted on

基于 Apache DBCP 的数据库连接获取类(原创) - BeanSoft's Java Blog - BlogJava

BeanSoft's Java Blog

MyEclipse 教程, Java EE 5, JSPWiki, Spring, Struts, Hibernate, JPA, SWT, Swing, AJAX, JavaScript, Netbeans

导航

随笔分类

最新随笔

搜索

*

积分与排名

  • 积分 - 632502
  • 排名 - 1

最新评论

阅读排行榜

60天内阅读排行

基于 Apache DBCP 的数据库连接获取类(原创)

2005年12月5日星期一

基于 Apache DBCP 的数据库连接获取类, 可以让你在 Tomcat 之外的 J2SE 程序或者其它应用服务器上使用 Apache 的数据库连接池.

TODO: 增加最大连接数和最小连接数的设置功能

配置文件:

ConnectionFactory.properties

/# 2004-12-30 /# 数据库连接工厂的配置文件, 类文件参见 util.ConnectionFactory /# 调试标志, 为 true 时使用 JDBC 直接连接(使用 url, driver, user, password 四个参数) /# 为 false 时使用内置数据库连接池(使用参数 jdbc.jndi), 配置文件位于 db.properties 中 debug=false /# JDBC的连接地址 URL jdbc.url=jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=yuelao /# JDBC 的驱动 jdbc.driver=com.microsoft.jdbc.sqlserver.SQLServerDriver /# JDBC 的连接用户名 jdbc.user=sa /# JDBC 的连接密码 jdbc.password= /#debug 为 false 时, 将根据连接池名获取数据库连接, 适用于程序在服务器运行的时候

.Java 文件:

// / @(/#)ConnectionFactory.java 1.2 2005-11-25 / / Copyright 2005 BeanSoft Studio. All rights reserved. / PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. //

package beansoft.util;

import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties;

import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource;

import beansoft.jsp.StringUtil; import beansoft.sql.DatabaseUtil;

/// / ConnectionFactory provide a factory class that produces all database / connections from here, and it provides methods for shutdown and restart / data sources as well as reading and saving configuration parameters from/to file. / / 数据库连接工厂类, 所有的数据库连接都从这里产生, 提供关闭和重启数据源的方法, 以及读取和保存 / 配置参数到文件的能力. / / 2005-08-19 / Using Apache DBCP as database connection pool provider. / 使用 Apache DBCP 作为连接池的提供类. / / @link http://jakarta.apache.org/commons/dbcp/ / / Dependency: / commons-collections.jar / commons-pool.jar / commons-dbcp.jar / j2ee.jar (for the javax.sql classes) / / If you using this class with Tomcat's web application, then all the above jars / not need to be added because the Tomcat it self has included these class libs. / 如果你在 Tomcat 的 Web Application 中调用这个类, 以上的 JAR 都不用单独 / 加入的, 因为 Tomcat 默认已经自带了这些类库. / / @author BeanSoft / @version 1.2 / 2005-11-25 // public class ConnectionFactory {

/// Database password /*/ private static String password;

/// Database username /*/ private static String user;

/// JDBC URL /*/ private static String url;

/// / JDBC driver class name // private static String driver;

/// / DEBUG flag, default value is true, returns a connection that directly fetched using / JDBC API; if falg is false, returns a connection returned by the connection pool, / if u want depoly the application, please make this flag be false. / 调试标记, 默认值为 true, 则返回直接使用 JDBC 获取的连接; 如果标记为 false, / 则从连接池中返回器连接, 发布程序时请将这个标志 设置为 false. // private static boolean DEBUG = true;

/// Connection properties value /*/ private static Properties props = new Properties();

/// The data source object, added at 2005-08-19 /*/ private static DataSource dataSource = null;

// Load configuration from resource /ConnectionFactory.properties static { loadConfiguration(); }

private ConnectionFactory() { }

/// / Factory method: obtain a database connection. / 工厂方法: 获取一个数据库连接. / / / @return Connection a java.sql.Connection object // public static Connection getConnection() { try { Connection conn = null;

// Debug mode, obtain connection directly through JDBC API if (DEBUG) {

Class.forName(driver);

conn = DriverManager.getConnection(url, user, password); } else { // TODO // // Looking data source through JNDI tree // DataSource dataSource = (DataSource) getInitialContext() // .lookup(jndi); // conn = dataSource.getConnection(); conn = setupDataSource().getConnection(); }

return conn; } catch (Exception ex) { System.err.println("Error: Unable to get a connection: " + ex); ex.printStackTrace(); }

return null; }

/// / Load and parse configuration. // public static void loadConfiguration() { try { props.load(new ByteArrayInputStream(readConfigurationString().getBytes()));

// Load DEBUG flag, default to true DEBUG = Boolean.valueOf(props.getProperty("debug", "true")) .booleanValue(); password = props.getProperty("jdbc.password", null); user = props.getProperty("jdbc.user", null); url = props.getProperty("jdbc.url", null); driver = props.getProperty("jdbc.driver"); } catch (Exception e) { e.printStackTrace(); } }

/// / Save the current configuration properties. // public static void saveConfiguration() { saveConfiguration(getProperties()); }

/// / Read content string from configuration file. Because Class.getResourceAsStream(String) / sometimes cache the contents, so here used this method. / 读取配置文件中的字符串. / 因为 Class 类的 getResourceAsStream(String) 方法有时候会出现缓存, 因此 / 不得已使用了这种办法. / @return String, null if failed /*/ public static String readConfigurationString() { try { java.io.FileInputStream fin = new java.io.FileInputStream( getConfigurationFilePath()); java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();

int data; while( (data = fin.read()) != -1) { bout.write(data); } bout.close(); fin.close();

return bout.toString(); } catch (Exception ex) { System.err.println("Unable to load ConnectionFactory.properties:" + ex.getMessage()); ex.printStackTrace(); } return null; }

/// / Get the configuration file's real physical path. // private static String getConfigurationFilePath() { return StringUtil.getRealFilePath("/ConnectionFactory.properties"); }

/// / Save string content of a java.util.Properties object. / 保存配置文件中的字符串. / / @param props configuration string / @return operation result // protected static boolean saveConfigurationString(String props) { if(props == null || props.length() <= 0) return false; try { FileWriter out = new FileWriter(getConfigurationFilePath()); out.write(props); out.close();

return true; } catch (Exception ex) { System.err.println("Unable save configuration string to ConnectionFactory.properties:"

  • ex); ex.printStackTrace(); }

return false; }

/// / Returns the current database connection properties. / @return Properties object /*/ public static Properties getProperties() { return props; }

/// / Save configuration properties. / / @param props Properties / @return operation result /*/ public static boolean saveConfiguration(Properties props) { if(props == null || props.size() <= 0) return false;

try { FileOutputStream out = new FileOutputStream(getConfigurationFilePath()); props.store(out, ""); out.close();

return true; } catch (Exception ex) { System.err.println("Unable to save ConnectionFactory.properties:" + ex.getMessage()); ex.printStackTrace(); }

return false; }

/// / Create a DataSource instance based on the Apache DBCP. / 创建基于 Apache DBCP 的 DataSource. / / @return a poolable DataSource /*/ public static DataSource setupDataSource() { if(dataSource == null) { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName(driver); ds.setUsername(user); ds.setPassword(password); ds.setUrl(url);

dataSource = ds; }

return dataSource; }

/// / Display connection status of current data source. / / 显示当前数据源的状态. // public static String getDataSourceStats() { BasicDataSource bds = (BasicDataSource) setupDataSource(); StringBuffer info = new StringBuffer();

info.append("Active connection numbers: " + bds.getNumActive()); info.append("\n"); info.append("Idle connection numbers: " + bds.getNumIdle());

return info.toString(); }

/// / Shut down the data source, if want use it again, / please call setupDataSource(). /*/ public static void shutdownDataSource() { BasicDataSource bds = (BasicDataSource) setupDataSource(); try { bds.close(); } catch (SQLException e) { // TODO auto generated try-catch e.printStackTrace(); } }

/// / Restart the data source. / 重新启动数据源. /*/ public static void restartDataSource() { shutdownDataSource(); setupDataSource(); }

/// Test method /*/ public static void main(String[] args) { Connection conn = ConnectionFactory.getConnection(); DatabaseUtil dbUtil = new DatabaseUtil(); dbUtil.setConnection(conn); // try { // java.sql.ResultSet rs = conn.createStatement().executeQuery( // "SELECT MAX(ID) FROM items"); // // while(rs.next()) { // System.out.println(rs.getString(1)); // } // // rs.close(); // // } catch (Exception ex) { // ex.printStackTrace(); // } System.out.println(dbUtil.getAllCount("SELECT MAX(ID) FROM items"));

System.out.println(conn);

try { conn.close(); } catch (Exception ex) { // ex.printStackTrace(); }

conn = ConnectionFactory.getConnection();

System.out.println(conn);

try { conn.close(); } catch (Exception ex) { // ex.printStackTrace(); }

System.exit(0); }

} posted on 2007-01-19 11:04 BeanSoft 阅读(2136) 评论(1) 编辑 收藏 所属分类: Database

[Comments

  • /# re: 基于 Apache DBCP 的数据库连接获取类(原创)小车马 Posted @ 2007-01-23 23:38 恩,以前也用过,apache的很多东西都非常不错, 楼主,潜力贴论坛(http://content.uu1001.com/)是我个人的一个设想,如果你对java非常的专注,并且愿意交我这个朋友,可以发邮件给我(lbw070105@gmail.com),希望我们可以一起发展它。 回复 更多评论 ]() 刷新评论列表

标题 请输入标题 姓名 请输入你的姓名 主页 请输入验证码 验证码 /* 内容(请不要发表任何与政治相关的内容) 请输入评论内容 Remember Me? 登录 使用高级评论 新用户注册 返回页首 恢复上次提交 [使用Ctrl+Enter键可以直接提交] 该文被作者在 2007-09-22 12:56 编辑过 相关文章:

Powered by: BlogJava Copyright © BeanSoft

连接池与使用Tomcat的连接池 _ Jacken_zone

Posted on

连接池与使用Tomcat的连接池 _ Jacken_zone

连接池与使用Tomcat的连接池

Filed under: AppServ, IT Technology, JDBC |

Posted on 12月 13th, 2007 由 Jacken What is Connection Pool?看图~~

1)存放Connection对象的容器; 2)减少连接数据库的开销; 3)程序请求连接时,在Connection Pool中取连接; 4)连接使用完后,放回Connection Pool,不释放; 5)Connection Pool对连接进行管理:计数、监控连接状态;

ConnectionPool-JPool

自己写个连接池? ?一般情况下不要使用自己写的连接池,很多应用提供连接池,它们的更好更安全更专业…

DbConfig.java 下载: DbConfig.java

package cn.com.jacken.JPool.javabeans; public class DbConfig { private String jdbcDriver; private String url; private String userName; private String password; public String getJdbcDriver() { return jdbcDriver; } public void setJdbcDriver(String jdbcDriver) { this.jdbcDriver = jdbcDriver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

IJConnectionPool.java 下载: IJConnectionPool.java

package cn.com.jacken.JPool; import java.sql.Connection; import java.util.Hashtable; import cn.com.jacken.JPool.javabeans.DbConfig; public abstract class IJConnectionPool{ protected Hashtable connectionContainer = newHashtable(); public abstract void init(int count, DbConfig config) throws Exception; public abstract Connection getConnection() throws Exception; public abstract void returnConnection(Connection conn); }

JConnectionPoolImpl.java 下载: JConnectionPoolImpl.java

package cn.com.jacken.JPool; import java.sql.Connection; import java.sql.DriverManager; import cn.com.jacken.JPool.javabeans.DbConfig; public class JConnectionPoolImplextendsIJConnectionPool { public JConnectionPoolImpl(int count, DbConfig config) throws Exception { this.init(count, config); } @Override publicConnectiongetConnection() throws Exception { Connection conn = null; Object[] objList = this.connectionContainer.keySet().toArray(); for (Object obj : objList) { String value = this.connectionContainer.get("obj"); // 判断状态是否为FREE if (true == value.equals("FREE")) { // 如果当前Connection状态确实为FREE conn = (Connection) obj; // 将实例的状态置为BUSY this.connectionContainer.put(conn, "BUSY"); break; } } if (null == conn) { Exception e = new Exception("没有空闲的Connection,请稍候再试!"); throwe; } // 返回实例给客户代码 return conn; } @Override publicvoid init(int count, DbConfig config) throws Exception { // 循环的添加Connection实例到Hashtable中 for (int i = 0; i < count; i++) { // 产生Connection实例 Class.forName(config.getJdbcDriver()); Connection conn = DriverManager.getConnection(config.getUrl(), config.getUserName(), config.getPassword()); // 将Connection实例添加到Hashtable中 this.connectionContainer.put(conn, "FREE"); } } @Override publicvoid returnConnection(Connection conn) { // 将实例的状态置为FREE this.connectionContainer.put(conn, "FREE"); } }

使用Tomcat的连接池

1,配置连接池:在conf目录下的context.xml中,添加一项(可以配置多项): 下载: context.xml

WEB-INF/web.xml

2,将数据库驱动添加到Tomcat的classPath中或者复制到%TomcatHome%/common/lib下.

3,在代码中使用连接池,获得Connection 实例. //...... Connection conn = null; // 获得连接池环境 Contextctx = newInitialContext(); // 获得数据源 DataSource ds = (DataSource) ctx.lookup("java:comp/env/jacken"); // 从数据源中 获得Connection实例 conn = ds.getConnection(); // 执行SQL Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); //......

druid 教程

Posted on

druid 教程

 java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,有不得不使用数据库连接池。数据库连接池有很多选择,c3p、dhcp、proxool等,druid作为一名后起之秀,凭借其出色的性能,也逐渐印入了大家的眼帘。接下来本教程就说一下druid的简单使用。

首先从http://repo1.maven.org/maven2/com/alibaba/druid/ 下载最新的jar包。如果想使用最新的源码编译,可以从https://github.com/alibaba/druid 下载源码,然后使用maven命令行,或者导入到eclipse中进行编译。

1 配置

和dbcp类似,druid的配置项如下

配置 缺省值 说明 name 配置这个属性的意义在于,如果存在多个数据源,监控的时候 可以通过名字来区分开来。如果没有配置,将会生成一个名字, 格式是:"DataSource-" + System.identityHashCode(this) jdbcUrl 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto username 连接数据库的用户名 password 连接数据库的密码。如果你不希望密码直接写在配置文件中, 可以使用ConfigFilter。详细看这里: https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter driverClassName 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType, 然后选择相应的driverClassName initialSize 0 初始化时建立物理连接的个数。初始化发生在显示调用init方法, 或者第一次getConnection时 maxActive 8 最大连接池数量 maxIdle 8 已经不再使用,配置了也没效果 minIdle 最小连接池数量 maxWait 获取连接时最大等待时间,单位毫秒。配置了maxWait之后, 缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 poolPreparedStatements false 是否缓存preparedStatement,也就是PSCache。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 在mysql下建议关闭。 maxOpenPreparedStatements -1 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true。 在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100 validationQuery 用来检测连接是否有效的sql,要求是一个查询语句。 如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。 testOnBorrow true 申请连接时执行validationQuery检测连接是否有效, 做了这个配置会降低性能。 testOnReturn false 归还连接时执行validationQuery检测连接是否有效, 做了这个配置会降低性能 testWhileIdle false 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。 timeBetweenEvictionRunsMillis 有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 numTestsPerEvictionRun 不再使用,一个DruidDataSource只支持一个EvictionRun minEvictableIdleTimeMillis connectionInitSqls 物理连接初始化的时候执行的sql exceptionSorter 根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接 filters 属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall proxyFilters 类型是List, 如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系表1.1 配置属性

根据常用的配置属性,首先给出一个如下的配置文件,放置于src目录下。

[plain] view plaincopy

  1. url:jdbc:mysql://localhost:3306/dragoon_v25_masterdb
  2. driverClassName:com.mysql.jdbc.Driver
  3. username:root
  4. password:aaaaaaaa
  5. filters:stat
  6. maxActive:20
  7. initialSize:1
  8. maxWait:60000
  9. minIdle:10
  10. /#maxIdle:15
  11. timeBetweenEvictionRunsMillis:60000
  12. minEvictableIdleTimeMillis:300000
  13. validationQuery:SELECT 'x'
  14. testWhileIdle:true
  15. testOnBorrow:false
  16. testOnReturn:false
  17. /#poolPreparedStatements:true
  18. maxOpenPreparedStatements:20
  19. /#对于长时间不使用的连接强制关闭
  20. removeAbandoned:true
  21. /#超过30分钟开始关闭空闲连接
  22. removeAbandonedTimeout:1800
  23. /#将当前关闭动作记录到日志
  24. logAbandoned:true

配置文件1.1

配置项中指定了各个参数后,在连接池内部是这么使用这些参数的。数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

同时连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),不过这样会影响性能。

2 代码编写

2.1 使用spring

首先给出spring配置文件

[html] view plaincopy

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  6. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  7. <bean id="propertyConfigurer"
  8. class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  9. /WEB-INF/classes/dbconfig.properties
  10. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
  11. destroy-method="close">
  12. <property name="maxOpenPreparedStatements"
  13. value="${maxOpenPreparedStatements}" />
  14. <bean id="dataSourceDbcp" class="org.apache.commons.dbcp.BasicDataSource"
  15. destroy-method="close">
  16. <property name="maxOpenPreparedStatements"
  17. value="${maxOpenPreparedStatements}" />
  18. <bean id="SpringTableOperatorBean" class="com.whyun.druid.model.TableOperator"
  19. scope="prototype">

配置文件2.1

其中第一个bean中给出的配置文件/WEB-INF/classes/dbconfig.properties就是第1节中给出的配置文件。我这里还特地给出dbcp的spring配置项,目的就是将两者进行对比,方便大家进行迁移。这里没有使用JdbcTemplate,所以jdbc那个bean没有使用到。下面给出com.whyun.druid.model.TableOperator类的代码。

[java] view plaincopy

  1. package com.whyun.druid.model;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.SQLException;
  5. import java.sql.Statement;
  6. import javax.sql.DataSource;
  7. public class TableOperator {
  8. private DataSource dataSource;
  9. public void setDataSource(DataSource dataSource) {
  10. this.dataSource = dataSource;
  11. }
  12. private static final int COUNT = 800;
  13. public TableOperator() {
  14. }
  15. public void tearDown() throws Exception {
  16. try {
  17. dropTable();
  18. } catch (SQLException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. public void insert() throws Exception {
  23. StringBuffer ddl = new StringBuffer();
  24. ddl.append("INSERT INTO t_big (");
  25. for (int i = 0; i < COUNT; ++i) {
  26. if (i != 0) {
  27. ddl.append(", ");
  28. }
  29. ddl.append("F" + i);
  30. }
  31. ddl.append(") VALUES (");
  32. for (int i = 0; i < COUNT; ++i) {
  33. if (i != 0) {
  34. ddl.append(", ");
  35. }
  36. ddl.append("?");
  37. }
  38. ddl.append(")");
  39. Connection conn = dataSource.getConnection();
  40. // System.out.println(ddl.toString());
  41. PreparedStatement stmt = conn.prepareStatement(ddl.toString());
  42. for (int i = 0; i < COUNT; ++i) {
  43. stmt.setInt(i + 1, i);
  44. }
  45. stmt.execute();
  46. stmt.close();
  47. conn.close();
  48. }
  49. private void dropTable() throws SQLException {
  50. Connection conn = dataSource.getConnection();
  51. Statement stmt = conn.createStatement();
  52. stmt.execute("DROP TABLE t_big");
  53. stmt.close();
  54. conn.close();
  55. }
  56. public void createTable() throws SQLException {
  57. StringBuffer ddl = new StringBuffer();
  58. ddl.append("CREATE TABLE t_big (FID INT AUTO_INCREMENT PRIMARY KEY ");
  59. for (int i = 0; i < COUNT; ++i) {
  60. ddl.append(", ");
  61. ddl.append("F" + i);
  62. ddl.append(" BIGINT NULL");
  63. }
  64. ddl.append(")");
  65. Connection conn = dataSource.getConnection();
  66. Statement stmt = conn.createStatement();
  67. stmt.execute(ddl.toString());
  68. stmt.close();
  69. conn.close();
  70. }
  71. }

代码片段2.1

注意:在使用的时候,通过获取完Connection对象,在使用完之后,要将其close掉,这样其实是将用完的连接放入到连接池中,如果你不close的话,会造成连接泄露。 然后我们写一个servlet来测试他.

[java] view plaincopy

  1. package com.whyun.druid.servelt;
  2. import java.io.IOException;
  3. import java.io.PrintWriter;
  4. import java.sql.SQLException;
  5. import javax.servlet.ServletContext;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import org.springframework.web.context.WebApplicationContext;
  11. import org.springframework.web.context.support.WebApplicationContextUtils;
  12. import com.whyun.druid.model.TableOperator;
  13. public class TestServlet extends HttpServlet {
  14. private TableOperator operator;
  15. @Override
  16. public void init() throws ServletException {
  17. super.init();
  18. ServletContext servletContext = this.getServletContext();
  19. WebApplicationContext ctx
  20. = WebApplicationContextUtils.getWebApplicationContext(servletContext);
  21. operator = (TableOperator)ctx.getBean("SpringTableOperatorBean");
  22. }
  23. ///
  24. /* The doGet method of the servlet.
  25. /*
  26. /* This method is called when a form has its tag value method equals to get.
  27. /*
  28. /* @param request the request send by the client to the server
  29. /* @param response the response send by the server to the client
  30. /* @throws ServletException if an error occurred
  31. /* @throws IOException if an error occurred
  32. /*/
  33. public void doGet(HttpServletRequest request, HttpServletResponse response)
  34. throws ServletException, IOException {
  35. response.setContentType("text/html");
  36. PrintWriter out = response.getWriter();
  37. boolean createResult = false;
  38. boolean insertResult = false;
  39. boolean dropResult = false;
  40. try {
  41. operator.createTable();
  42. createResult = true;
  43. } catch (SQLException e) {
  44. e.printStackTrace();
  45. }
  46. if (createResult) {
  47. try {
  48. operator.insert();
  49. insertResult = true;
  50. } catch (Exception e) {
  51. e.printStackTrace();
  52. }
  53. try {
  54. operator.tearDown();
  55. dropResult = true;
  56. } catch (Exception e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. out.println("{'createResult':"+createResult+",'insertResult':"
  61. +insertResult+",'dropResult':"+dropResult+"}");
  62. out.flush();
  63. out.close();
  64. }
  65. }
    代码片段2.2

这里没有用到struts2或者springmvc,虽然大部分开发者用的是这两种框架。

2.2 不使用spring

类似于dbcp,druid也提供了原生态的支持。先看下面这段代码:

[java] view plaincopy

  1. package com.whyun.util.db;
  2. import javax.sql.DataSource;
  3. import org.apache.commons.dbcp.BasicDataSourceFactory;
  4. import com.alibaba.druid.pool.DruidDataSourceFactory;
  5. import com.whyun.util.config.MySqlConfigProperty;
  6. import com.whyun.util.config.MySqlConfigProperty2;
  7. ///
  8. /* The Class DataSourceUtil.
  9. /*/
  10. public class DataSourceUtil {
  11. /// 使用配置文件dbconfig.properties构建Druid数据源. /*/
  12. public static final int DRUID_MYSQL_SOURCE = 0;
  13. /// 使用配置文件dbconfig2.properties构建Druid数据源. /*/
  14. public static final int DRUID_MYSQL_SOURCE2 = 1;
  15. /// 使用配置文件dbconfig.properties构建Dbcp数据源. /*/
  16. public static final int DBCP_SOURCE = 4;
  17. ///
  18. /* 根据类型获取数据源
  19. /*
  20. /* @param sourceType 数据源类型
  21. /* @return druid或者dbcp数据源
  22. /* @throws Exception the exception
  23. /*/
  24. public static final DataSource getDataSource(int sourceType)
  25. throws Exception {
  26. DataSource dataSource = null;
  27. switch(sourceType) {
  28. case DRUID_MYSQL_SOURCE:
  29. dataSource = DruidDataSourceFactory.createDataSource(
  30. MySqlConfigProperty.getInstance().getProperties());
  31. break;
  32. case DRUID_MYSQL_SOURCE2:
  33. dataSource = DruidDataSourceFactory.createDataSource(
  34. MySqlConfigProperty2.getInstance().getProperties());
  35. break;
  36. case DBCP_SOURCE:
  37. dataSource = BasicDataSourceFactory.createDataSource(
  38. MySqlConfigProperty.getInstance().getProperties());
  39. break;
  40. }
  41. return dataSource;
  42. }
  43. }

代码片段2.3 手动读取配置文件初始化连接池

第37行中调用了类com.alibaba.druid.pool.DruidDataSourceFactory中createDataSource方法来初始化一个连接池。对比dbcp的使用方法,两者很相似。

下面给出一个多线程的测试程序。运行后可以比较druid和dbcp的性能差别。

[java] view plaincopy

  1. package com.whyun.druid.test;
  2. import java.sql.SQLException;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.Future;
  9. import java.util.concurrent.TimeUnit;
  10. import com.whyun.druid.model.TableOperator;
  11. import com.whyun.util.db.DataSourceUtil;
  12. public class MutilThreadTest {
  13. public static void test(int dbType, int times)
  14. throws Exception {
  15. int numOfThreads =Runtime.getRuntime().availableProcessors()/*2;
  16. ExecutorService executor = Executors.newFixedThreadPool(numOfThreads);
  17. final TableOperator test = new TableOperator();
  18. // int dbType = DataSourceUtil.DRUID_MYSQL_SOURCE;
  19. // dbType = DataSourceUtil.DBCP_SOURCE;
  20. test.setDataSource(DataSourceUtil.getDataSource(dbType));
  21. boolean createResult = false;
  22. try {
  23. test.createTable();
  24. createResult = true;
  25. } catch (SQLException e) {
  26. e.printStackTrace();
  27. }
  28. if (createResult) {
  29. List> results = new ArrayList>();
  30. for (int i = 0; i < times; i++) {
  31. results.add(executor.submit(new Callable() {
  32. @Override
  33. public Long call() throws Exception {
  34. long begin = System.currentTimeMillis();
  35. try {
  36. test.insert();
  37. //insertResult = true;
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. }
  41. long end = System.currentTimeMillis();
  42. return end - begin;
  43. }
  44. }));
  45. }
  46. executor.shutdown();
  47. while(!executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS));
  48. long sum = 0;
  49. for (Future result : results) {
  50. sum += result.get();
  51. }
  52. System.out.println("---------------db type "+dbType+"------------------");
  53. System.out.println("number of threads :" + numOfThreads + " times:" + times);
  54. System.out.println("running time: " + sum + "ms");
  55. System.out.println("TPS: " + (double)(100000 /* 1000) / (double)(sum));
  56. System.out.println();
  57. try {
  58. test.tearDown();
  59. //dropResult = true;
  60. } catch (Exception e) {
  61. e.printStackTrace();
  62. }
  63. } else {
  64. System.out.println("初始化数据库失败");
  65. }
  66. }
  67. public static void main (String argc[])
  68. throws Exception {
  69. test(DataSourceUtil.DBCP_SOURCE,50);
  70. test(DataSourceUtil.DRUID_MYSQL_SOURCE,50);
  71. }
  72. }

代码片段2.4 连接池多线程测试程序


3 监控

3.1 web监控

druid提供了sql语句查询时间等信息的监控功能。为了让数据库查询一直运行,下面特地写了一个ajax进行轮询。同时,还要保证在web.xml中配置如下信息

[html] view plaincopy

  1. DruidStatView
  2. com.alibaba.druid.support.http.StatViewServlet
  3. DruidStatView
  4. /druid//*

  5. 配置文件3.1 在web.xml中添加druid监控

**同时将ajax代码提供如下

[javascript] view plaincopy

  1. function showTime() {
  2. var myDate = new Date();
  3. var timeStr = '';
  4. timeStr += myDate.getFullYear()+'-'; //获取完整的年份(4位,1970-????)
  5. timeStr += myDate.getMonth()+'-'; //获取当前月份(0-11,0代表1月)
  6. timeStr += myDate.getDate() + ' '; //获取当前日(1-31)
  7. timeStr += myDate.getHours()+':'; //获取当前小时数(0-23)
  8. timeStr += myDate.getMinutes()+':'; //获取当前分钟数(0-59)
  9. timeStr += myDate.getSeconds(); //获取当前秒数(0-59)
  10. return timeStr
  11. }
  12. $(document).ready(function() {
  13. function loadDBTestMessage() {
  14. $.get('servlet/MysqlTestServlet',function(data) {
  15. if (typeof(data) != 'object') {
  16. data = eval('(' + data + ')');
  17. }
  18. var html = '['+showTime()+']';
  19. html += '创建:' + data['createResult'];
  20. html += '插入:' + data['insertResult'];
  21. html += '销毁:' + data['dropResult'];
  22. html +=
  23. $('/#message').html(html);
  24. });
  25. }
  26. setInterval(function() {
  27. loadDBTestMessage();
  28. }, 10000);
  29. });
    代码片段3.1 ajax轮询

这时打开http://localhost/druid-web/druid/ 地址,会看到监控界面,点击其中的sql标签。

图3.1 监控界面查看sql查询时间

注意:在写配置文件1.1时,要保证filter配置项中含有stat属性,否则这个地方看不到sql语句的监控数据。

表格中各项含义如下


名称

解释

备注 ExecuteCount

当前sql已执行次数 ExecTime

当前sql已执行时间 ExecMax

当前sql最大执行时间 Txn

当前运行的事务数量 Error

当前sql执行出错的数目 Update

当前sql更新或者删除操作中已经影响的行数 FetchRow

当前sql操作中已经读取的行数 Running

当前sql正在运行的数目 Concurrent

当前sql最大并发执行数 ExecHisto

当前sql做execute操作的时间分布数组

分为0-1,1-10,10-100,100-1000,>1000,5个时间分布区域,单位为ms ExecRsHisto

当前sql做execute操作和resultSet

打开至关闭的时间总和分布数组

同上 FetchRowHisto

当前sql查询时间分布数组

同上 UpdateHisto

当前sql更新、删除时间分布数组

同上表3.1 监控字段含义

老版本的druid的jar包中不支持通过web界面进行远程监控,从0.2.14开始可以通过配置jmx地址来获取远程运行druid的服务器的监控信息。具体配置方法如下:

[html] view plaincopy

  1. DruidStatView
  2. com.alibaba.druid.support.http.StatViewServlet
  3. jmxUrl
  4. service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi
  5. DruidStatView
  6. /druid//*

  7. 配置文件3.2 远程监控web

这里连接的配置参数中多了一个jmxUrl,里面配置一个jmx连接地址。jmx连接中也可以指定用户名、密码,在上面的servlet中添加两个init-param,其param-name分别为jmxUsername和jmxPassword,分别对应连接jmx的用户名和密码。对于jmx在服务器端的配置,可以参考3.2节中的介绍。

3.2 jconsole监控

同时druid提供了jconsole监控的功能,因为界面做的不是很好,所以官方中没有对其的相关介绍。如果是纯java程序的话,上面提到的web监控就无法使用了,jconsole的作用就体现出来了。不过我在下面做教程的时候,依然使用的是刚才用的web项目。

首先在catalina.bat(或者catalina.sh)中加入java的启动选项,放置于if "%OS%" == "Windows_NT" setlocal这句之后。

set JAVA_OPTS=%JAVA_OPTS% -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port="9004" -Dcom.sun.management.jmxremote.authenticate="false" -Dcom.sun.management.jmxremote.ssl="false"

保存完之后,启动startup.bat(或者startup.sh)来运行tomcat(上面设置java启动项的配置,按理来说在eclipse中也能适用,但是笔者在其下没有试验成功)。然后在远程的某台电脑的命令行中运行如下命令

jconsole -pluginpath E:\kuaipan\workspace6\druid-web\WebRoot\WEB-INF\lib\druid-0.2.11.jar

这里的最后一个参数就是你的druid的jar包的路径。

图3.2 jconsole连接界面

在远程进程的输入框里面输入ip:端口号,然后点击连接(上面的配置中没有指定用户名、密码,所以这里不用填写)。打开的界面如下:

图3.3 jconsole 连接成功界面

可以看到和web监控界面类似的数据了。 来源: [http://blog.csdn.net/yunnysunny/article/details/8657095](http://blog.csdn.net/yunnysunny/article/details/8657095)