首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

JDBC DataSource Example – Oracle, MySQL and Apache DBCP Tutorial

2023-11-09 来源:华拓网
 

We have already seen that JDBC DriverManager can be used to get relational database connections. But when it comes to actual programming, we want more than just connections.

Most of the times we are looking for loose coupling for connectivity so that we can switch databases easily, connection pooling for transaction management and distributed systems support. JDBC DataSource is the preferred approach if you are looking for any of these features in your application. JDBC DataSource interface is present in javax.sql package and it only declare two overloaded methods getConnection() andgetConnection(String str1,String str2).

It is the responsibility of different Database vendors to provide different kinds of implementation of DataSource interface. For example MySQL JDBC Driver provides basic implementation of DataSource interface with com.mysql.jdbc.jdbc2.optional.MysqlDataSource class and Oracle database driver implements it with oracle.jdbc.pool.OracleDataSource class.

These implementation classes provide methods through which we can provide database server details with user credentials. Some of the other common features provided by these DataSource implementation classes are;

 
  • Caching of PreparedStatement for faster processing
  • Connection timeout settings
  • Logging features
  • ResultSet maximum size threshold
  • Let’s create a simple JDBC project and learn how to use MySQL and Oracle DataSource basic implementation classes to get the database connection. Our final project will look like below image.

    技术分享

    Database Setup

    Before we get into our example programs, we need some database setup with table and sample data. Installation of MySQL or Oracle database is out of scope of this tutorial, so I will just go ahead and setup table with sample data.

    MySQLSetup.sql--Create Employee tableCREATE TABLE `Employee` ( `empId` int(10) unsigned NOT NULL, `name` varchar(10) DEFAULT NULL, PRIMARY KEY (`empId`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- insert some sample dataINSERT INTO `Employee` (`empId`, `name`)VALUES (1, ‘Pankaj‘), (2, ‘David‘); commit;

    OracleSetup.sqlCREATE TABLE "EMPLOYEE" ( "EMPID" NUMBER NOT NULL ENABLE, "NAME" VARCHAR2(10 BYTE) DEFAULT NULL, PRIMARY KEY ("EMPID") ); Insert into EMPLOYEE (EMPID,NAME) values (10,‘Pankaj‘);Insert into EMPLOYEE (EMPID,NAME) values (5,‘Kumar‘);Insert into EMPLOYEE (EMPID,NAME) values (1,‘Pankaj‘);commit;

    Now let’s move on to our java programs. For having database configuration loosely coupled, I will read them from property file.

    db.properties#mysql DB propertiesMYSQL_DB_DRIVER_CLASS=com.mysql.jdbc.DriverMYSQL_DB_URL=jdbc:mysql://localhost:3306/UserDBMYSQL_DB_USERNAME=pankajMYSQL_DB_PASSWORD=pankaj123 #Oracle DB PropertiesORACLE_DB_DRIVER_CLASS=oracle.jdbc.driver.OracleDriverORACLE_DB_URL=jdbc:oracle:thin:@localhost:1521:orclORACLE_DB_USERNAME=hrORACLE_DB_PASSWORD=oracle

    Make sure that above configurations match with your local setup. Also make sure you have MySQL and Oracle DB JDBC jars included in the build path of the project.

    JDBC MySQL and Oracle DataSource Example

    Let’s write a factory class that we can use to get MySQL or Oracle DataSource.

    MyDataSourceFactory.javapackage com.journaldev.jdbc.datasource; import java.io.FileInputStream;import java.io.IOException;import java.sql.SQLException;import java.util.Properties; import javax.sql.DataSource; import oracle.jdbc.pool.OracleDataSource; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; public class MyDataSourceFactory { public static DataSource getMySQLDataSource() { Properties props = new Properties(); FileInputStream fis = null; MysqlDataSource mysqlDS = null; try { fis = new FileInputStream("db.properties"); props.load(fis); mysqlDS = new MysqlDataSource(); mysqlDS.setURL(props.getProperty("MYSQL_DB_URL")); mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME")); mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD")); } catch (IOException e) { e.printStackTrace(); } return mysqlDS; } public static DataSource getOracleDataSource(){ Properties props = new Properties(); FileInputStream fis = null; OracleDataSource oracleDS = null; try { fis = new FileInputStream("db.properties"); props.load(fis); oracleDS = new OracleDataSource(); oracleDS.setURL(props.getProperty("ORACLE_DB_URL")); oracleDS.setUser(props.getProperty("ORACLE_DB_USERNAME")); oracleDS.setPassword(props.getProperty("ORACLE_DB_PASSWORD")); } catch (IOException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return oracleDS; } }

    Notice that both Oracle and MySQL DataSource implementation classes are very similar, let’s write a simple test program to use these methods and run some test.

     
    DataSourceTest.javapackage com.journaldev.jdbc.datasource; import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement; import javax.sql.DataSource; public class DataSourceTest { public static void main(String[] args) { testDataSource("mysql"); System.out.println("**********"); testDataSource("oracle"); } private static void testDataSource(String dbType) { DataSource ds = null; if("mysql".equals(dbType)){ ds = MyDataSourceFactory.getMySQLDataSource(); }else if("oracle".equals(dbType)){ ds = MyDataSourceFactory.getOracleDataSource(); }else{ System.out.println("invalid db type"); return; } Connection con = null; Statement stmt = null; ResultSet rs = null; try { con = ds.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery("select empid, name from Employee"); while(rs.next()){ System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name")); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(stmt != null) stmt.close(); if(con != null) con.close(); } catch (SQLException e) { e.printStackTrace(); } } } }

    Notice that the client class is totally independent of any Database specific classes. This helps us in hiding the underlying implementation details from client program and achieve loose coupling and abstraction benefits.

    When we run above test program, we will get below output.

    Employee ID=1, Name=PankajEmployee ID=2, Name=David**********Employee ID=10, Name=PankajEmployee ID=5, Name=KumarEmployee ID=1, Name=Pankaj

    Apache Commons DBCP Example

    If you look at above DataSource factory class, there are two major issues with it.

    1. The factory class methods to create the MySQL and Oracle DataSource are tightly coupled with respective driver API. If we want to remove support for Oracle database in future or want to add some other database support, it will require code change.
    2. Most of the code to get the MySQL and Oracle DataSource is similar, the only different is the implementation class that we are using.

    Apache Commons DBCP API helps us in getting rid of these issues by providing DataSource implementation that works as an abstraction layer between our program and different JDBC drivers.

    Apache DBCP library depends on Commons Pool library, so make sure they both are in the build path as shown in the image.

    Here is the DataSource factory class using BasicDataSource that is the simple implementation of DataSource.

    DBCPDataSourceFactory.javapackage com.journaldev.jdbc.datasource; import java.io.FileInputStream;import java.io.IOException;import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; public class DBCPDataSourceFactory { public static DataSource getDataSource(String dbType){ Properties props = new Properties(); FileInputStream fis = null; BasicDataSource ds = new BasicDataSource(); try { fis = new FileInputStream("db.properties"); props.load(fis); }catch(IOException e){ e.printStackTrace(); return null; } if("mysql".equals(dbType)){ ds.setDriverClassName(props.getProperty("MYSQL_DB_DRIVER_CLASS")); ds.setUrl(props.getProperty("MYSQL_DB_URL")); ds.setUsername(props.getProperty("MYSQL_DB_USERNAME")); ds.setPassword(props.getProperty("MYSQL_DB_PASSWORD")); }else if("oracle".equals(dbType)){ ds.setDriverClassName(props.getProperty("ORACLE_DB_DRIVER_CLASS")); ds.setUrl(props.getProperty("ORACLE_DB_URL")); ds.setUsername(props.getProperty("ORACLE_DB_USERNAME")); ds.setPassword(props.getProperty("ORACLE_DB_PASSWORD")); }else{ return null; } return ds; }}

    As you can see that depending on user input, either MySQL or Oracle datasource is created. If you are supporting only one database in the application then you don’t even need these logic. Just change the properties and you can switch from one database server to another. The key point through which Apache DBCP provide abstraction is setDriverClassName() method.

    Here is the client program using above factory method to get different types of connection.

    ApacheCommonsDBCPTest.javapackage com.journaldev.jdbc.datasource; import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement; import javax.sql.DataSource; public class ApacheCommonsDBCPTest { public static void main(String[] args) { testDBCPDataSource("mysql"); System.out.println("**********"); testDBCPDataSource("oracle"); } private static void testDBCPDataSource(String dbType) { DataSource ds = DBCPDataSourceFactory.getDataSource(dbType); Connection con = null; Statement stmt = null; ResultSet rs = null; try { con = ds.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery("select empid, name from Employee"); while(rs.next()){ System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name")); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(stmt != null) stmt.close(); if(con != null) con.close(); } catch (SQLException e) { e.printStackTrace(); } } } }

    When you run above program, the output will be same as earlier program.

    If you look at the DataSource and above usage, it can be done with normal DriverManager too. The major benefit of DataSource is when it’s used within a Context and with JNDI.

    With simple configurations we can create a Database Connection Pool that is maintained by the Container itself. Most of the servlet containers such as Tomcat and JBoss provide it’s own DataSource implementation and all we need is to configure it through simple XML based configurations and then use JNDI context lookup to get the DataSource and work with it. This helps us by taking care of connection pooling and management from our application side to server side and thus giving us more time to write business logic for the application.

    In next tutorial, we will learn how we can configure DataSource in Tomcat Container and use it in Web Application.

    JDBC DataSource Example – Oracle, MySQL and Apache DBCP Tutorial

    标签:

    小编还为您整理了以下内容,可能对您也有帮助:

    高分 java连接SQL server 2000 详细步骤

    试试吧,

    在JSP中访问Oracle ,SqlServer ,DB2, Informix ,Access 数据库

    2007-1-13

    在JSP中访问Oracle ,SqlServer ,DB2, Informix ,Access 数据库

    现在有好多初学jsp的网友经常会问数据库怎么连接啊,怎么老出错啊?所以我集中的在这写篇文章供大家参考,其实这种把数据库逻辑全部放在jsp里未必是好的做法,但是有利于初学者学习,所以我就这样做了,当大家学到一定程度的时候,可以考虑用MVC的模式开发。在练习这些代码的时候,你一定将jdbc的驱动程序放到服务器的类路径里,然后要在数据库里建一个表test,有两个字段比如为test1,test2,可以用下面SQL建 create table test(test1 varchar(20),test2 varchar(20),然后向这个表写入一条测试纪录,那么现在开始我们的jsp和数据库之旅吧。

    一、jsp连接Oracle8/8i/9i数据库(用thin模式)

    testoracle.jsp如下:

    <%@ page contentType="text/html;charset=gb2312"%>

    <%@ page import="java.sql.*"%>

    <html>

    <body>

    <%Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

    String url="jdbc:oracle:thin:@localhost:1521:orcl";

    //orcl为你的数据库的SID

    String user="scott";

    String password="tiger";

    Connection conn= DriverManager.getConnection(url,user,password);

    Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

    String sql="select * from test";

    ResultSet rs=stmt.executeQuery(sql);

    while(rs.next()) {%>

    您的第一个字段内容为:<%=rs.getString(1)%>

    您的第二个字段内容为:<%=rs.getString(2)%>

    <%}%>

    <%out.print("数据库操作成功,恭喜你");%>

    <%rs.close();

    stmt.close();

    conn.close();

    %>

    </body>

    </html>

    二、jsp连接Sql Server7.0/2000数据库

    testsqlserver.jsp如下:

    <%@ page contentType="text/html;charset=gb2312"%>

    <%@ page import="java.sql.*"%>

    <html>

    <body>

    <%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();

    String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs";

    //pubs为你的数据库的

    String user="sa";

    String password="";

    Connection conn= DriverManager.getConnection(url,user,password);

    Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

    String sql="select * from test";

    ResultSet rs=stmt.executeQuery(sql);

    while(rs.next()) {%>

    您的第一个字段内容为:<%=rs.getString(1)%>

    您的第二个字段内容为:<%=rs.getString(2)%>

    <%}%>

    <%out.print("数据库操作成功,恭喜你");%>

    <%rs.close();

    stmt.close();

    conn.close();

    %>

    </body>

    </html>

    三、jsp连接DB2数据库

    testdb2.jsp如下:

    <%@ page contentType="text/html;charset=gb2312"%>

    <%@ page import="java.sql.*"%>

    <html>

    <body>

    <%Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();

    String url="jdbc:db2://localhost:5000/sample";

    //sample为你的数据库名

    String user="admin";

    String password="";

    Connection conn= DriverManager.getConnection(url,user,password);

    Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

    ResultSet.CONCUR_UPDATABLE);

    String sql="select * from test";

    ResultSet rs=stmt.executeQuery(sql);

    while(rs.next()) {%>

    您的第一个字段内容为:<%=rs.getString(1)%>

    您的第二个字段内容为:<%=rs.getString(2)%>

    <%}%>

    <%out.print("数据库操作成功,恭喜你");%>

    <%rs.close();

    stmt.close();

    conn.close();

    %>

    </body>

    </html>

    四、jsp连接Informix数据库

    testinformix.jsp如下:

    <%@ page contentType="text/html;charset=gb2312"%>

    <%@ page import="java.sql.*"%>

    <html>

    <body>

    <%Class.forName("com.informix.jdbc.IfxDriver").newInstance();

    String url =

    "jdbc:informix-sqli://123.45.67.89:1533/testDB:INFORMIXSERVER=myserver;

    user=testuser;password=testpassword";

    //testDB为你的数据库名

    Connection conn= DriverManager.getConnection(url);

    Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

    String sql="select * from test";

    ResultSet rs=stmt.executeQuery(sql);

    while(rs.next()) {%>

    您的第一个字段内容为:<%=rs.getString(1)%>

    您的第二个字段内容为:<%=rs.getString(2)%>

    <%}%>

    <%out.print("数据库操作成功,恭喜你");%>

    <%rs.close();

    stmt.close();

    conn.close();

    %>

    </body>

    </html>

    五、jsp连接Access数据库

    <%@page import="java.sql.*"

    import ="java.util.*"

    import ="java.io.*"

    import="java.text.*"

    contentType="text/html; charset=gb2312"

    buffer="20kb"

    %><%! int all,i,m_count;

    String odbcQuery;

    Connection odbcconn;

    Statement odbcstmt;

    ResultSet odbcrs;

    String username,title,content,work,email,url,time,date;

    String datetime;

    %>

    <%

    try{

    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    }catch (ClassNotFoundException e)

    { out.print ("驱动程序不存在");

    }

    try{

    odbcconn = DriverManager.getConnection("jdbc:odbc:db1");

    odbcstmt = odbcconn.createStatement();

    odbcQuery="Select * From book where datetime>2001-4-26 Order By datetime DESC";

    odbcrs=odbcstmt.executeQuery(odbcQuery);

    int i=0;

    while (i<130) odbcrs.next();

    while (odbcrs.next())

    {

    //*/////////////////////////显示数据库的内容用于调试程序是用//

    int ii;

    try{

    try{

    for (ii=1;;ii++)

    out.print ("<br>Cloumn "+ii+" is: "+odbcrs.getString(ii));

    }catch (NullPointerException e) {

    out.print ("有空的指针");

    }

    }catch (SQLException e){

    }

    }

    odbcrs.close();

    odbcstmt.close();

    odbcconn.close();

    }catch (SQLException e)

    { out.print (e);

    }

    %>

    查看(24) 评论(0)

    Hibernate快速入门

    2006-11-10

    其实Hibernate本身是个的框架,它不需要任何web server或application server的支持。然而,大多数的Hibernate入门介绍都加入了很多非Hibernate的东西,比如: Tomcat, Eclipse, Log4J,Struts, XDoclet, 甚至JBoss。这容易让人产生Hibernate复杂难懂的误解,特别是打击了初学者的积极性。

    在这篇文章将不涉及Eclipse, log4j, Struts, Tomcat, XDoclet,和JBoss。本文的目的是演示一下Hibernate的安装过程以及最基本的功能,从而给初学者一个低得不能再低的入门门槛。

    下载文件

    你需要Java SDK、 Hibernate包、Ant包、和JDBC Driver。

    1、Hibernate包下载地址:

    http://prdownloads.sourceforge.n ... t_by=date&sort=desc

    2、Ant包下载地址:

    http://archive.apache.org/dist/ant/

    3、JDBC Driver要根据你用的database来定,一般database官方网站上都会有。Hibernate支持常用的database,比如 MySQL, Oracle, PostgreSQL, 和MS-SQL Server。这些数据库都有JDBC Driver:

    Oracle JDBC Driver下载地址(下载前必须同意Oracle协议书)

    http://otn.oracle.com/software/h ... tdocs/jdbc9201.html

    MySQL JDBC Driver下载地址

    http://dev.mysql.com/downloads/connector/j/3.0.html

    PostgreSQL JDBC Driver下载地址

    http://jdbc.postgresql.org/download.html

    MS-SQL Server JDBC Driver下载地址

    http://www.microsoft.com/downloa ... bf71&displaylang=en

    4、将Hibernate包和Ant包分别解压至c:dev下(此目录不重要,你可以换其它任何目录)。

    配置环境

    1、你需要添加一个新的环境变量: ANT_HOME,让它指向c:dev<的ANT包所在目录>并在PATH环境变量里添加%ANT_HOME%in。

    2、你需要添加一个新的环境变量: JAVA_HOME,让它指向你的j2sdk根目录。并在PATH环境变量里添加%JAVA_HOME%in。

    3、创建一个项目ā?目录,比如c:workspaceMy1stHibernate。

    在项目目录下,另外创建三个目录: src, classes, lib。

    在lib目录下,创建两个目录: hibernate和db。

    这样你有了如下的文件结构:

    c:workspaceMy1stHibernate

    c:workspaceMy1stHibernatesrc

    c:workspaceMy1stHibernateclasses

    c:workspaceMy1stHibernatelib

    c:workspaceMy1stHibernatelibhibernate

    c:workspaceMy1stHibernatelibdb

    4、将c:dev<的Hibernate包所在目录>hibernate2.jar文件copy到c:workspaceMy1stHibernatelibhibernate下。

    将c:dev<的Hibernate包所在目录>lib下的所有文件同样copy到c:workspaceMy1stHibernatelibhibernate下。

    将你的JDBC Driver文件(一般是一个jar文件)copy到c:workspaceMy1stHibernatelibdb下。

    创建数据库

    1、用你最喜爱的database软件,创建一个hibernate_test的数据库。

    2、在此数据库下,新建一个table名为CUSTOMER

    CREATE TABLE CUSTOMER

    (

    CID INTEGER NOT NULL PRIMARY KEY, USERNAME VARCHAR(12) NOT NULL, PASSWORD VARCHAR(12)

    );

    编写Java文件

    public class Customer {

    private int id;

    private String username;

    private String password;

    public int getId() {

    return id;

    }

    public String getPassword() {

    return password;

    }

    public String getUsername() {

    return username;

    }

    public void setId(int id) {

    this.id = id;

    }

    public void setPassword(String password) {

    this.password = password;

    }

    public void setUsername(String username) {

    this.username = username;

    }

    }

    将此类存为c:workspaceMy1stHibernatesrcCustomer.java文件。

    编写Test类

    import net.sf.hibernate.*;

    import net.sf.hibernate.cfg.*;

    public class Test {

    public static void main(String[] args) {

    try {

    SessionFactory sf = new Configuration().configure().buildSessionFactory();

    Session session = sf.openSession();

    Transaction tx = session.beginTransaction();

    for (int i = 0; i <200; i++) {

    Customer customer = new Customer();

    custoā?mer.setUsername("customer" + i);

    customer.setPassword("customer");

    session.save(customer);

    }

    tx.commit();

    session.close();

    } catch (HibernateException e) {

    e.printStackTrace();

    }

    }

    }

    将此类存为c:workspaceMy1stHibernatesrcTest.java文件。

    创建Hibernate映射文件

    因为这里只有一个Class --- Customer 和一个Table --- CUSTOMER,你只需要建立一个映射文件--- Customer.hbm.xml,来对应Customer类和CUSTOMER表之间的关系。

    <xml version="1.0"?>

    <DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

    <ibernate-mapping>

    <lass name="Customer" table="CUSTOMER">

    <d name="id" column="CID">

    <enerator class="increment" />

    <id>

    <roperty name="username" column="USERNAME" />

    <roperty name="password" column="PASSWORD" />

    <class>

    <hibernate-mapping>

    把此文件存为c:workspaceMy1stHibernatesrcCustomer.hbm.xml,和Customer.java放在同一目录下。

    编写Ant build.xml文件

    你不一定要知道这个build.xml的细节,其实Ant也不是Hibernate所必须的。这里用Ant是为了简化一些任务,比如: 编译、copy、运行,等。

    <xml version="1.0" ?>

    <roject name="My1stHibernate" default="build" basedir=".">

    <roperty name="base.dir" value="." />

    <roperty name="src.dir" value="src" />

    <roperty name="lib.dir" value="lib" />

    <roperty name="build.dir" value="classes" />

    <ath id="myclasspath">

    <ileset dir="${lib.dir}">

    <nclude name="**/*.jar" />

    <fileset>

    <athelement location="${build.dir}" />

    <path>

    <arget name="init">

    <kdir dir="${build.dir}" />

    <target>

    <arget name="build" depends="init" description="compile the source files">

    <avac classpathref="myclasspath" srcdir="${src.dir}" destdir="${build.dir}" />

    <opy todir="${build.dir}" >

    <ileset dir="${src.dir}" >

    ā?<xclude name="**/*.java"/>

    <fileset>

    <copy>

    <target>

    <arget name="run" depends="build">

    <ava classpathref="myclasspath" classname="Test" fork="true" />

    <target>

    <arget name="clean">

    <elete includeEmptyDirs="true">

    <ileset dir="${build.dir}" />

    <delete>

    <target>

    <project>

    配置Hibernate描述文件

    Hibernate描述文件可以是一个properties或xml 文件,其中最重要的是定义数据库的连接。我这里列出的是一个XML格式的hibernate.cfg.xml描述文件。

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

    <DOCTYPE hibernate-configuration

    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"

    "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

    <ibernate-configuration>

    <ession-factory name="java:/hibernate/HibernateFactory">

    <roperty name="show_sql">rue<property>

    <roperty name="connection.driver_class">

    oracle.jdbc.driver.OracleDriver <-- 这里是Oracle 9i的JDBC driver class名 -->

    <property>

    <roperty name="connection.url">

    jdbc:oracle:oci8:@hibernate_test <-- 这里是Oracle的hibernate_test数据库URL -->

    <property>

    <roperty name="connection.username">

    你的数据库用户名

    <property>

    <roperty name="connection.password">

    你的数据库密码

    <property>

    <roperty name="dialect">

    net.sf.hibernate.dialect.Oracle9Dialect <-- 这里是Oracle 9i的Dialect -->

    <property>

    <apping resource="Customer.hbm.xml" /><-- 指定Customer的映射文件 -->

    <session-factory>

    <hibernate-configuration>

    如果你用的不是Oracle 9i,可到C:dev<的Hibernate包所在目录>srchibernate.properties文件里找到你的数据库,然后替换以上相对应的值。

    开始运行

    到c:workspaceMy1stHibernate下,运行ant run。如果你严格依照以上步骤,应该看到

    run:

    [java] log4j:WARN No appenders could be found for logger (net.sf.hibernate.cfg.Environment).

    [java] log4j:WARN Please initialize the log4j system properly.

    [java] Hibernate: insert into CUSTOMER (USERNAME, PASSWORD, CID) values (?, ?, ?)

    BUILD SUCCESSFUL

    到你的hibernate_test数据库看一下,在CUSTMOR表里新添了200条记录,但你没有写任何JDBC code。

    以后如果你要更换数据库,只需要改变hibernate.cfg.xml描述文件里相应的值即可。

    查看(89) 评论(4)

    掌握 Ajax, Ajax 简介

    2006-11-10

    Ajax 由 HTML、JavaScript™ 技术、DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应用程序。本文的作者是一位 Ajax 专家,他演示了这些技术如何协同工作 —— 从总体概述到细节的讨论 —— 使高效的 Web 开发成为现实。他还揭开了 Ajax 核心概念的神秘面纱,包括 XMLHttpRequest 对象。

    五年前,如果不知道 XML,您就是一只无人重视的丑小鸭。十八个月前,Ruby 成了关注的中心,不知道 Ruby 的程序员只能坐冷板凳了。今天,如果想跟上最新的技术时尚,那您的目标就是 Ajax。

    但是,Ajax 不仅仅 是一种时尚,它是一种构建网站的强大方法,而且不像学习一种全新的语言那样困难。

    但在详细探讨 Ajax 是什么之前,先让我们花几分钟了解 Ajax 做 什么。目前,编写应用程序时有两种基本的选择:

    桌面应用程序

    Web 应用程序

    两者是类似的,桌面应用程序通常以 CD 为介质(有时候可从网站下载)并完全安装到您的计算机上。桌面应用程序可能使用互联网下载更新,但运行这些应用程序的代码在桌面计算机上。Web 应用程序运行在某处的 Web 服务器上 —— 毫不奇怪,要通过 Web 浏览器访问这种应用程序。

    不过,比这些应用程序的运行代码放在何处更重要的是,应用程序如何运转以及如何与其进行交互。桌面应用程序一般很快(就在您的计算机上运行,不用等待互联网连接),具有漂亮的用户界面(通常和操作系统有关)和非凡的动态性。可以单击、选择、输入、打开菜单和子菜单、到处巡游,基本上不需要等待。

    另一方面,Web 应用程序是最新的潮流,它们提供了在桌面上不能实现的服务(比如 Amazon.com 和 eBay)。但是,伴随着 Web 的强大而出现的是等待,等待服务器响应,等待屏幕刷新,等待请求返回和生成新的页面。

    显然这样说过于简略了,但基本的概念就是如此。您可能已经猜到,Ajax 尝试建立桌面应用程序的功能和交互性,与不断更新的 Web 应用程序之间的桥梁。可以使用像桌面应用程序中常见的动态用户界面和漂亮的控件,不过是在 Web 应用程序中。

    还等什么呢?我们来看看 Ajax 如何将笨拙的 Web 界面转化成能迅速响应的 Ajax 应用程序吧。

    老技术,新技巧

    在谈到 Ajax 时,实际上涉及到多种技术,要灵活地运用它必须深入了解这些不同的技术(本系列的头几篇文章将分别讨论这些技术)。好消息是您可能已经非常熟悉其中的大部分技术,更好的是这些技术都很容易学习,并不像完整的编程语言(如 Java 或 Ruby)那样困难。

    Ajax 的定义

    顺便说一下,Ajax 是 Asynchronous JavaScript and XML(以及 DHTML 等)的缩写。这个短语是 Adaptive Path 的 Jesse James Garrett 发明的(请参阅 参考资料),按照 Jesse 的解释,这不是 个首字母缩写词。

    下面是 Ajax 应用程序所用到的基本技术:

    HTML 用于建立 Web 表单并确定应用程序其他部分使用的字段。

    JavaScript 代码是运行 Ajax 应用程序的核心代码,帮助改进与服务器应用程序的通信。

    DHTML 或 Dynamic HTML,用于动态更新表单。我们将使用 div、span 和其他动态 HTML 元素来标记 HTML。

    文档对象模型 DOM 用于(通过 JavaScript 代码)处理 HTML 结构和(某些情况下)服务器返回的 XML。

    我们来进一步分析这些技术的职责。以后的文章中我将深入讨论这些技术,目前只要熟悉这些组件和技术就可以了。对这些代码越熟悉,就越容易从对这些技术的零散了解转变到真正把握这些技术(同时也真正打开了 Web 应用程序开发的大门)。

    XMLHttpRequest 对象

    要了解的一个对象可能对您来说也是最陌生的,即 XMLHttpRequest。这是一个 JavaScript 对象,创建该对象很简单,如清单 1 所示。

    清单 1. 创建新的 XMLHttpRequest 对象

    <script language="javascript" type="text/javascript">

    var xmlHttp = new XMLHttpRequest();

    </script>

    下一期文章中将进一步讨论这个对象,现在要知道这是处理所有服务器通信的对象。继续阅读之前,先停下来想一想:通过 XMLHttpRequest 对象与服务器进行对话的是 JavaScript 技术。这不是一般的应用程序流,这恰恰是 Ajax 的强大功能的来源。

    在一般的 Web 应用程序中,用户填写表单字段并单击 Submit 按钮。然后整个表单发送到服务器,服务器将它转发给处理表单的脚本(通常是 PHP 或 Java,也可能是 CGI 进程或者类似的东西),脚本执行完成后再发送回全新的页面。该页面可能是带有已经填充某些数据的新表单的 HTML,也可能是确认页面,或者是具有根据原来表单中输入数据选择的某些选项的页面。当然,在服务器上的脚本或程序处理和返回新表单时用户必须等待。屏幕变成一片空白,等到服务器返回数据后再重新绘制。这就是交互性差的原因,用户得不到立即反馈,因此感觉不同于桌面应用程序。

    Ajax 基本上就是把 JavaScript 技术和 XMLHttpRequest 对象放在 Web 表单和服务器之间。当用户填写表单时,数据发送给一些 JavaScript 代码而不是 直接发送给服务器。相反,JavaScript 代码捕获表单数据并向服务器发送请求。同时用户屏幕上的表单也不会闪烁、消失或延迟。换句话说,JavaScript 代码在幕后发送请求,用户甚至不知道请求的发出。更好的是,请求是异步发送的,就是说 JavaScript 代码(和用户)不用等待服务器的响应。因此用户可以继续输入数据、滚动屏幕和使用应用程序。

    然后,服务器将数据返回 JavaScript 代码(仍然在 Web 表单中),后者决定如何处理这些数据。它可以迅速更新表单数据,让人感觉应用程序是立即完成的,表单没有提交或刷新而用户得到了新数据。JavaScript 代码甚至可以对收到的数据执行某种计算,再发送另一个请求,完全不需要用户干预!这就是 XMLHttpRequest 的强大之处。它可以根据需要自行与服务器进行交互,用户甚至可以完全不知道幕后发生的一切。结果就是类似于桌面应用程序的动态、快速响应、高交互性的体验,但是背后又拥有互联网的全部强大力量。

    加入一些 JavaScript

    得到 XMLHttpRequest 的句柄后,其他的 JavaScript 代码就非常简单了。事实上,我们将使用 JavaScript 代码完成非常基本的任务:

    获取表单数据:JavaScript 代码很容易从 HTML 表单中抽取数据并发送到服务器。

    修改表单上的数据:更新表单也很简单,从设置字段值到迅速替换图像。

    解析 HTML 和 XML:使用 JavaScript 代码操纵 DOM(请参阅 下一节),处理 HTML 表单服务器返回的 XML 数据的结构。

    对于前两点,需要非常熟悉 getElementById() 方法,如 清单 2 所示。

    清单 2. 用 JavaScript 代码捕获和设置字段值

    // Get the value of the "phone" field and stuff it in a variable called phone

    var phone = document.getElementById("phone").value;

    // Set some values on a form using an array called response

    document.getElementById("order").value = response[0];

    document.getElementById("address").value = response[1];

    这里没有特别需要注意的地方,真是好极了!您应该认识到这里并没有非常复杂的东西。只要掌握了 XMLHttpRequest,Ajax 应用程序的其他部分就是如 清单 2 所示的简单 JavaScript 代码了,混合有少量的 HTML。同时,还要用一点儿 DOM,我们就来看看吧。

    以 DOM 结束

    最后还有 DOM,即文档对象模型。可能对有些读者来说 DOM 有点儿令人生畏,HTML 设计者很少使用它,即使 JavaScript 程序员也不大用到它,除非要完成某项高端编程任务。大量使用 DOM 的是 复杂的 Java 和 C/C++ 程序,这可能就是 DOM 被认为难以学习的原因。

    幸运的是,在 JavaScript 技术中使用 DOM 很容易,也非常直观。现在,按照常规也许应该说明如何使用 DOM,或者至少要给出一些示例代码,但这样做也可能误导您。即使不理会 DOM,仍然能深入地探讨 Ajax,这也是我准备采用的方法。以后的文章将再次讨论 DOM,现在只要知道可能需要 DOM 就可以了。当需要在 JavaScript 代码和服务器之间传递 XML 和改变 HTML 表单的时候,我们再深入研究 DOM。没有它也能做一些有趣的工作,因此现在就把 DOM 放到一边吧。

    回页首

    获取 Request 对象

    有了上面的基础知识后,我们来看看一些具体的例子。XMLHttpRequest 是 Ajax 应用程序的核心,而且对很多读者来说可能还比较陌生,我们就从这里开始吧。从 清单 1 可以看出,创建和使用这个对象非常简单,不是吗?等一等。

    还记得几年前的那些讨厌的浏览器战争吗?没有一样东西在不同的浏览器上得到同样的结果。不管您是否相信,这些战争仍然在继续,虽然规模较小。但令人奇怪的是,XMLHttpRequest 成了这场战争的牺牲品之一。因此获得 XMLHttpRequest 对象可能需要采用不同的方法。下面我将详细地进行解释。

    使用 Micr

    fedora 20 64位 配置android 开发环境,需要安装哪些32位支持库

    1. 安装Eclipse(JDT插件),JDK等开发环境

    这个在Fedora上实在是太容易了,yum install xxxx,很多种选择,我的选择是:“sudo yum groupinstall ‘Development Tools’”

    2. 下载Android SDK并安装必要部件

    2.1 下载Android SDK并解压缩:

    解压缩到自己的home文件下,我就得到了:~/android-sdk-linux

    2.2 安装必要的android开发部件:

    这个主要是platform tools以及目标版本的开发资源:启动sdk管理器,运行~/android-sdk-linux/tools/android。第一次启动会有一个警告说没有找到platform tools(你还没下载,当然没有了)。启动之后选择自己需要的开发资源下载。我下载了最新的19.0.1的SDK Platform-tools和SDK Build-tools。然后下载了Android 4.4.2(API19)的所有开发资源。其实ARM的那个System Image后面没有用了,可以不用下载。后面模拟器要用的是Intel的那个System Image。

    3. 安装Eclipse 的ADT插件

    3.1 安装ADT

    这个是基于Eclipse的开发调试IDE(集成开发环境),google有打包了包括eclipse的完整开发套件包,这个显然不是自由人士的首选。安装ADT的步骤:

    启动Eclipse,Help->Install New Software,添加一个ADT的Repository,全选“Developer Tools”目录下的所有项,然后下一步下一步直到结束。

    ADT就安装成功了。

    这里需要注意的是,ADT下载的过程中也需要,不然很难下载成功。作为中国的开发人员,我们太不容易啦。在Eclipse的Windows->Preference,选择General->Network Connections,Active Provider那个地方选择Manual,然后把你的http和https的代理填上。

    3.2 配置ADT

    启动Eclipse,在ADT弹出的对话框中选“使用已有的SDK”,然后把前面说的~/android-sdk-linux填到sdk路径的位置,ADT就可以工作了。

    dbcp连接池放回链接后再次拿出来地址为什么不一样,我只初始化一个。怎么打印判断两链接是同一个链接

    1. 引入dbcp (选择1.4)

    Java代码  

    <dependency>  

    <groupId>com.alibaba.external</groupId>  

    <artifactId>jakarta.commons.dbcp</artifactId>  

    <version>1.4</version>  

    </dependency>  

    2. dbcp的基本配置

    相关配置说明:

    initialSize :连接池启动时创建的初始化连接数量(默认值为0)

    maxActive :连接池中可同时连接的最大的连接数(默认值为8,调整为20,高峰单机器在20并发左右,自己根据应用场景定)

    maxIdle:连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不(默认为8个,maxIdle不能设置太小,因为假如在高负载的情况下,连接的打开时间比关闭的时间快,会引起连接池中idle的个数 上升超过maxIdle,而造成频繁的连接销毁和创建,类似于jvm参数中的Xmx设置)

    minIdle:连接池中最小的空闲的连接数,低于这个数量会被创建新的连接(默认为0,调整为5,该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大,因为在机器很空闲的时候,也会创建低于minidle个数的连接,类似于jvm参数中的Xmn设置)

    maxWait  :最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间会抛出异常,如果设置-1表示无限等待(默认为无限,调整为60000ms,避免因线程池不够用,而导致请求被无挂起)

    poolPreparedStatements:开启池的prepared(默认是false,未调整,经过测试,开启后的性能没有关闭的好。)

    maxOpenPreparedStatements:开启池的prepared 后的同时最大连接数(默认无,同上,未配置)

    minEvictableIdleTimeMillis  :连接池中连接,在时间段内一直空闲, 被逐出连接池的时间

    (默认为30分钟,可以适当做调整,需要和后端服务端的策略配置相关)

    removeAbandonedTimeout  :超过时间,回收没有用(废弃)的连接(默认为 300秒,调整为180)

    removeAbandoned  :超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收(默认为false,调整为true)

    removeAbandoned参数解释:

    如果开启了removeAbandoned,当getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时被触发.

    举例当maxActive=20, 活动连接为18,空闲连接为1时可以触发"removeAbandoned".但是活动连接只有在没有被使用的时间超 过"removeAbandonedTimeout"时才被回收

    logAbandoned: 标记当连接被回收时是否打印程序的stack traces日志(默认为false,未调整)

    一般会是几种情况出现需要removeAbandoned: 

    代码未在finally释放connection , 不过我们都用sqlmapClientTemplate,底层都有链接释放的过程

    遇到数据库死锁。以前遇到过后端存储过程做了锁表操作,导致前台集群中连接池全都被block住,后续的业务处理因为拿不到链接所有都处理失败了。

    一份优化过的配置:

    基本配置代码  

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">   

    <property name="driverClassName" value="com.mysql.jdbc.Driver" />  

    <property name="url" value="xxxx" />  

    <property name="username"><value>xxxx</value></property>  

    <property name="password"><value>xxxxx</value></property>  

    <property name="maxActive"><value>20</value></property>  

    <property name="initialSize"><value>1</value></property>  

    <property name="maxWait"><value>60000</value></property>  

    <property name="maxIdle"><value>20</value></property>  

    <property name="minIdle"><value>3</value></property>  

    <property name="removeAbandoned"><value>true</value></property>  

    <property name="removeAbandonedTimeout"><value>180</value></property>  

    <property name="connectionProperties"><value>clientEncoding=GBK</value></property>  

    </bean>  

    2. dbcp的链接validate配置

    dbcp是采用了commons-pool做为其连接池管理,testOnBorrow,testOnReturn, testWhileIdle是pool是提供的几种校验机制,通过外部钩子的方式回调dbcp的相关数据库链接(validationQuery)校验

    dbcp相关外部钩子类:PoolableConnectionFactory,继承于common-pool PoolableObjectFactory

    dbcp通过GenericObjectPool这一入口,进行连接池的borrow,return处理

    testOnBorrow : 顾明思义,就是在进行borrowObject进行处理时,对拿到的connection进行validateObject校验

    testOnReturn : 顾明思义,就是在进行returnObject对返回的connection进行validateObject校验,个人觉得对数据库连接池的管理意义不大

    testWhileIdle : 关注的重点,GenericObjectPool中针对pool管理,起了一个Evict的TimerTask定时线程进行控制(可通过设置参数timeBetweenEvictionRunsMillis>0),定时对线程池中的链接进行validateObject校验,对无效的链接进行关闭后,会调用ensureMinIdle,适当建立链接保证最小的minIdle连接数。

    timeBetweenEvictionRunsMillis,设置的Evict线程的时间,单位ms,大于0才会开启evict检查线程

    validateQuery, 代表检查的sql

    validateQueryTimeout, 代表在执行检查时,通过statement设置,statement.setQueryTimeout(validationQueryTimeout)

    numTestsPerEvictionRun,代表每次检查链接的数量,建议设置和maxActive一样大,这样每次可以有效检查所有的链接.

    Validate配置代码  

    <property name="testWhileIdle"><value>true</value></property> <!-- 打开检查,用异步线程evict进行检查 -->  

    <property name="testOnBorrow"><value>false</value></property>  

    <property name="testOnReturn"><value>false</value></property>  

    <property name="validationQuery"><value>select sysdate from al</value></property>  

    <property name="validationQueryTimeout"><value>1</value></property>  

    <property name="timeBetweenEvictionRunsMillis"><value>30000</value></property>  

    <property name="numTestsPerEvictionRun"><value>20</value></property>  

    相关配置需求:

    目前网站的应用大部分的瓶颈还是在I/O这一块,大部分的I/O还是在数据库的这一层面上,每一个请求可能会调用10来次SQL查询,如果不走事务,一个请求会重复获取链接,如果每次获取链接都进行validateObject,性能开销不是很能接受,可以假定一次SQL操作消毫0.5~1ms(一般走了网络请求基本就这数)

    网站异常数据库重启,网络异常断开的频率是非常低的,一般也就在数据库升级,演习维护时才会进行,而且一般也是选在晚上,访问量相对比较低的请求,而且一般会有人员值班关注,所以异步的validateObject是可以接受,但一个前提需要确保能保证在一个合理的时间段内,数据库能完成自动重联。

    从代码层面简单介绍下dbcp的validate实现:

    1.  common-pools提供的PoolableObjectFactory,针对pool池的管理操作接口

    Java代码  

    public interface PoolableObjectFactory {  

    Object makeObject() throws Exception;  

    void destroyObject(Object obj) throws Exception;  

    boolean validateObject(Object obj);  

    void activateObject(Object obj) throws Exception;  

    void passivateObject(Object obj) throws Exception;  

    }  

    2. dbcp实现的pool从池管理操作

    这里贴了一个相关validate代码,具体类可见:PoolableConnectionFactory.validateConnection()

    Java代码  

    public class PoolableConnectionFactory implements PoolableObjectFactory {  

    ......  

    public boolean validateObject(Object obj) { //验证validateObject  

    if(obj instanceof Connection) {  

    try {  

    validateConnection((Connection) obj);  

    return true;  

    } catch(Exception e) {  

    return false;  

    }  

    } else {  

    return false;  

    }  

    }  

    public void validateConnection(Connection conn) throws SQLException {  

    String query = _validationQuery;  

    if(conn.isClosed()) {  

    throw new SQLException("validateConnection: connection closed");  

    }  

    if(null != query) {  

    Statement stmt = null;  

    ResultSet rset = null;  

    try {  

    stmt = conn.createStatement();  

    if (_validationQueryTimeout > 0) {  

    stmt.setQueryTimeout(_validationQueryTimeout);  

    }  

    rset = stmt.executeQuery(query);  

    if(!rset.next()) {  

    throw new SQLException("validationQuery didn't return a row");  

    }  

    } finally {  

    if (rset != null) {  

    try {  

    rset.close();  

    } catch(Exception t) {  

    // ignored  

    }  

    }  

    if (stmt != null) {  

    try {  

    stmt.close();  

    } catch(Exception t) {  

    // ignored  

    }  

    }  

    }  

    }  

    }  

    ....  

    }  

    3. pool池的evict调用代码:GenericObjectPool (apache commons pool version 1.5.4)

    Java代码  

    protected synchronized void startEvictor(long delay) { //启动Evictor为TimerTask  

    if(null != _evictor) {  

    EvictionTimer.cancel(_evictor);  

    _evictor = null;  

    }  

    if(delay > 0) {  

    _evictor = new Evictor();  

    EvictionTimer.schele(_evictor, delay, delay);  

    }  

    }  

    for (int i=0,m=getNumTests();i<m;i++) {  

    final ObjectTimestampPair pair;  

    .......  

    boolean removeObject = false;  

    // 空闲链接处理  

    final long idleTimeMilis = System.currentTimeMillis() - pair.tstamp;  

    if ((getMinEvictableIdleTimeMillis() > 0) &&  

    (idleTimeMilis > getMinEvictableIdleTimeMillis())) {  

    removeObject = true;  

    } else if ((getSoftMinEvictableIdleTimeMillis() > 0) &&  

    (idleTimeMilis > getSoftMinEvictableIdleTimeMillis()) &&  

    ((getNumIdle() + 1)> getMinIdle())) {   

    removeObject = true;  

    }  

    //  testWhileIdle sql 检查处理  

    if(getTestWhileIdle() && !removeObject) {  

    boolean active = false;  

    try {  

    _factory.activateObject(pair.value);  

    active = true;  

    } catch(Exception e) {  

    removeObject=true;  

    }  

    if(active) {  

    if(!_factory.validateObject(pair.value)) {   

    removeObject=true;  

    } else {  

    try {  

    _factory.passivateObject(pair.value);  

    } catch(Exception e) {  

    removeObject=true;  

    }  

    }  

    }  

    }  

    // 真正关闭  

    if (removeObject) {  

    try {  

    _factory.destroyObject(pair.value);  

    } catch(Exception e) {  

    // ignored  

    }  

    }  

    ........  

    注意: 目前dbcp的pool的实现是使用了公用的apache common pools进行扩展处理,所以和原生的连接池处理,代码看上去有点别扭,感觉自动重连这块异常处理不怎么好,我也就只重点关注了这部分代码而已   .

    3. dbcp的链接自动重链相关测试

    相关场景:

    数据库意外重启后,原先的数据库连接池能自动废弃老的无用的链接,建立新的数据库链接

    网络异常中断后,原先的建立的tcp链接,应该能进行自动切换

    测试需求1步骤

    建立一testCase代码

    配置mysql数据库

    循环执行在SQL查询过程

    异常重启mysql数据库

    测试需求2步骤

    建立一testCase代码

    配置mysql数据库

    循环执行在SQL查询过程

    通过iptables禁用网络链接 

    /sbin/iptables -A INPUT -s 10.16.2.69 -j REJECT

    /sbin/iptables -A FORWARD -p tcp -s 10.16.2.69 --dport 3306 -m state --state NEW,ESTABLISHED -j DROP

    5. iptables -F 清空规则,恢复链接通道。

    测试需求问题记录

    分别测试了两种配置,有validateObject的配置和没有validateObject的相关配置。

    1. 没有validate配置

    问题一: 异常重启mysql数据库后,居然也可以自动恢复链接,sql查询正常

    跟踪了一下代码,发现这么一个问题:

    在数据库关闭的时候,client中pool通过borrowObject获取一个异常链接返回给client

    client在使用具体的异常链接进行sql调用出错了,抛了异常

    在finally,调用connection.close(),本意是应该调用pool通过returnObject返回到的池中,但在跟踪代码时,未见调用GenericObjectPool的returnObject

    继续查,发现在dbcp在中PoolingDataSource(实现DataSource接口)调用PoolableConnection(dbcp pool相关的delegate操作)进行相应关闭时,会检查_conn.isClosed(),针对DataSource如果isClosed返回为true的则不调用returnObject,直接丢弃了链接  

    解释:

    正因为在获取异常链接后,因为做了_conn.isClosed()判断,所以异常链接并没有返回到连接池中,所以到数据库重启恢复后,每次都是调用pool重新构造一个新的connection,所以后面就正常了

    _conn.isClosed()是否保险,从jdk的api描述中: A connection is closed if the method close has been called on it or if certain fatal errors have occurred. 里面提供两种情况,一种就是被调用了closed方法,另一种就是出现一些异常也说的比较含糊。

    问题二:validateObject调用时,dbcp设置的validationQueryTimeout居然没效果

    看了mysql statement代码实现,找到了答案。 

    mysql com.mysql.jdbc.statemen 部分代码

    timeout时间处理:

    Java代码  

    timeoutTask = new CancelTask();  

    //通过TimerTask启动一定时任务  

    Connection.getCancelTimer().schele(timeoutTask,  this.timeoutInMillis);  

    对应的CancelTask的代码: 

    Java代码  

    class CancelTask extends TimerTask {  

    long connectionId = 0;  

    CancelTask() throws SQLException {  

    connectionId = connection.getIO().getThreadId();  

    }  

    public void run() {  

    Thread cancelThread = new Thread() {  

    public void run() {  

    Connection cancelConn = null;  

    java.sql.Statement cancelStmt = null;  

    try {  

    cancelConn = connection.plicate();  

    cancelStmt = cancelConn.createStatement();  

    // 简单暴力,再发起一条KILL SQL,关闭先前的sql thread id  

    cancelStmt.execute("KILL QUERY " + connectionId);  

    wasCancelled = true;  

    } catch (SQLException sqlEx) {  

    throw new RuntimeException(sqlEx.toString());  

    } finally {  

    if (cancelStmt != null) {  

    try {  

    cancelStmt.close();  

    } catch (SQLException sqlEx) {  

    throw new RuntimeException(sqlEx.toString());  

    }  

    }  

    if (cancelConn != null) {  

    try {  

    cancelConn.close();  

    } catch (SQLException sqlEx) {  

    throw new RuntimeException(sqlEx.toString());  

    }  

    }  

    }  

    }  

    };  

    cancelThread.start();  

    }  

    }  

    原因总结一句话: queryTimeout的实现是通过底层数据库提供的机制,比如KILL QUERY pid.  如果此时的网络不通,出现阻塞现象,对应的kill命令也发不出去,所以timeout设置的超时没效果。

    4.最后

    最后还是决定配置testWhileIdle扫描,主要考虑:

    pool池中的链接如果未被使用,可以通过testWhileIdle进行链接检查,避免在使用时后总要失败那么一次,可以及时预防

    配合连接池的minEvictableIdleTimeMillis(空闲链接),removeAbandoned(未释放的链接),可以更好的去避免因为一些异常情况引起的问题,防范于未然。比如使用一些分布式数据库的中间件,会有空闲链接关闭的动作,动态伸缩连接池,这时候需要能及时的发现,避免请求失败。

    testOnBorrow个人不太建议使用,存在性能问题,试想一下连接一般会在什么情况出问题,网络或者服务端异常终端空闲链接,网络中断你testOnBorrow检查发现不对再取一个链接还是不对,针对空闲链接处理异常关闭,可以从好业务端的重试策略进行考虑,同时配置客户端的空闲链接超时时间,maxIdle,minIdle等。

    --------------------------------------------

    新加的内容:

    5.dbcp密码加密处理

    以前使用jboss的jndi数据源的方式,是通过配置oracle-ds.xml,可以设置<security-domain>EncryptDBPassword</security-domain>,引用jboss login-config.xml配置的加密配置。

    Java代码  

    <application-policy name="EncryptDBPassword">  

    <authentication>  

    <login-mole code="org.jboss.resource.security.SecureIdentityLoginMole" flag="required">  

    <mole-option name="username">${username}</mole-option>  

    <mole-option name="password">${password_encrypt}</mole-option>  

    <mole-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=${jndiName}</mole-option>  

    </login-mole>  

    </authentication>  

    </application-policy>  

    为了能达到同样的效果,切换为spring dbcp配置时,也有类似密码加密的功能,运行期进行密码decode,最后进行数据链接。

    实现方式很简单,分析jboss的对应SecureIdentityLoginMole的实现,无非就是走了Blowfish加密算法,自己拷贝实现一份。

    华拓网还为您提供以下相关内容希望对您有帮助:

    JDBC常见面试题

    JDBC的DriverManager用于加载数据库驱动,ResultSet是查询结果集接口,DataSource用于获取数据库连接,提供连接池功能。如何创建连接池:使用DataSource与Apache Tomcat的JNDI结合,通过配置文件实现。Apache DBCP介绍:提供一个统一的DataSource实现,作为应用程序与不同JDBC驱动之间的抽象层。常见的JDBC异常:SQLExce...

    No suitable driver found for jdbc:apache:commons:dbcp:DEFAULT

    翻译:没有匹配的jdbc驱动...你看看你有没有加入apache的公共包,可能是commons-dbcp.jar

    MySQL持续维持连接状态mysql一直正在链接

    dataSource = new BasicDataSource();dataSource.setDriverClassName(“com.mysql.jdbc.Driver”);dataSource.setUrl(“jdbc:mysql://localhost:3306/mydatabase”);dataSource.setUsername(“username”);dataSource.setPassword(“password”);dataSource...

    java Spring 的JDBCTemplet批量入库数据时如果有一条数据入库不成功,其 ...

    xml代码oracle.jdbc.driver.OracleDrivervalue&gt;property&gt;bean&gt;oracle.jdbc.driver.OracleDrivervalue&gt;property&gt;bean&gt;为了得到spring的ApplicationContext,MultiDataSource类必须实现接口org.springframework.context.ApplicationContextAware,并且实现方法:java代码privateApplicationContextapplicationContext=null;publicvoidsetApplicationCon...

    dbcp连接池放回链接后再次拿出来地址为什么不一样,我只初始化一个。怎 ...

    3. dbcp的链接自动重链相关测试 相关场景: 数据库意外重启后,原先的数据库连接池能自动废弃老的无用的链接,建立新的数据库链接 网络异常中断后,原先的建立的tcp链接,应该能进行自动切换 测试需求1步骤 建立一testCase代码 配置mysql数据库 循环执行在SQL查询过程 异常重启mysql数据库 测试需求2步骤 建立一testCase代...

    如何创建 DataSource

    一、JNDI方式创建DataSource 以JNDI方式创建数据源首先要配置数据源的相关连接信息,也就是数据源连接池。该配置应该在Tomcat安装目录下的conf/context.xml文件中配置,在Eclipse的J2EE架构下,也可以把context.xml文件创建在/META-INF目录下。其配置如下:&lt;Context&gt;&lt;!--MySql--&gt; &lt;Resource name="jdbc/...

    ...org.apache.tomcat.dbcp.dbcp.BasicDataSource

    url="jdbc:mysql://127.0.0.1:3306 liuupeng?characterEncoding=utf8"/&gt; 应该改成 url="jdbc:mysql://127.0.0.1:3306/liuupeng?characterEncoding=utf8"/&gt;

    mysql数据库线程池问题,为什么总是报错Cannot create PoolableConnection...

    一般这种情况可能的原因有这几种:1. 可能连接超过mysql设置的上限(你的应该没超)2. 程序问题,建立了连接不关闭(这个有可能,看看你的session)3. 在没有使用连接池的情况下,每次都建立一个新的连接到数据库(即使每次操作完毕都及时准确的close了),但是由于可能建立到数据库连接的频率很高(比如在...

    求助,Spring下使用JNDI数据源时JDBCTemplate数据库连接关闭的问题_百 ...

    &lt;bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt; &lt;property name="driverClassName"&gt; &lt;value&gt;net.sourceforge.jtds.jdbc.Driver&lt;/value&gt; &lt;/property&gt; &lt;property name="url"&gt; &lt;value&gt;jdbc:jtds:sqlserver://127.0.0.1:1433/Sample&lt;/value&gt; &lt;/...

    Cannot load JDBC driver class 'com.mysql.jdbc.Driver'

    反正个人感觉用JB经常出现一些怪问题,所以我就没有用JB,建议你用eclipse,方便,思路清晰。象你这种情况,一般是有三种解释,一种是mysql的包不在工程的lib文件夹下面,第二种是mysql的包没有发布在tomcat的common.lib下面,另外还有一种就是你的数据库的包跟当前的mysql版本不同。

    显示全文

    猜你还关注