JDBC数据源(DataSource)数据源技术是Java操作数据库的一个很关键技术,流行的持久化框架都离不开数据源的应用。

时间:2022-05-10 01:53:15
JDBC数据源(DataSource)的简单实现
 
数据源技术是Java操作数据库的一个很关键技术,流行的持久化框架都离不开数据源的应用。
2.数据源提供了一种简单获取数据库连接的方式,并能在内部通过一个池的机制来复用数据库连接,这样就大大减少创建数据库连接的次数,提高了系统性能。
3.对于数据源的应用,一般都选择实用开源的数据源或数据库连接池来使用,比如,常见的有DBCP、C3P0、Proxool等等。
 
下面自己手动实现个精简的数据源,代码如下:
 
package com.lavasoft.simpledatesource;

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory;

import javax.sql.DataSource; 
import java.util.Collections; 
import java.util.LinkedList; 
import java.sql.Connection; 
import java.sql.SQLException; 
import java.sql.DriverManager; 
import java.io.PrintWriter;

/** 
* 一个简单的DataSource实现 

* @author leizhimin 2010-1-14 0:03:17 
*/ 
public class SimpleDateSource implements DataSource { 
        private static Log log = LogFactory.getLog(SimpleDateSource.class); 
        private static final String dirverClassName = "com.mysql.jdbc.Driver"; 
        private static final String url = "jdbc:mysql://127.0.0.1:3306/testdb"; 
        private static final String user = "root"; 
        private static final String pswd = "leizhimin"; 
        //连接池 
        private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections.synchronizedList(new LinkedList<Connection>()); 
        private static SimpleDateSource instance = new SimpleDateSource();

static { 
                try { 
                        Class.forName(dirverClassName); 
                } catch (ClassNotFoundException e) { 
                        log.error("找不到驱动类!", e); 
                } 
        }

private SimpleDateSource() { 
        }

/** 
         * 获取数据源单例 
         * 
         * @return 数据源单例 
         */ 
        public SimpleDateSource instance() { 
                if (instance == null) instance = new SimpleDateSource(); 
                return instance; 
        }

/** 
         * 获取一个数据库连接 
         * 
         * @return 一个数据库连接 
         * @throws SQLException 
         */ 
        public Connection getConnection() throws SQLException { 
                synchronized (pool) { 
                        if (pool.size() > 0) return pool.removeFirst(); 
                        else return makeConnection(); 
                } 
        }

/** 
         * 连接归池 
         * 
         * @param conn 
         */ 
        public static void freeConnection(Connection conn) { 
                pool.addLast(conn); 
        }

private Connection makeConnection() throws SQLException { 
                return DriverManager.getConnection(url, user, pswd); 
        }

public Connection getConnection(String username, String password) throws SQLException { 
                return DriverManager.getConnection(url, username, password); 
        }

public PrintWriter getLogWriter() throws SQLException { 
                return null; 
        }

public void setLogWriter(PrintWriter out) throws SQLException {

}

public void setLoginTimeout(int seconds) throws SQLException {

}

public int getLoginTimeout() throws SQLException { 
                return 0; 
        }

public <T> T unwrap(Class<T> iface) throws SQLException { 
                return null; 
        }

public boolean isWrapperFor(Class<?> iface) throws SQLException { 
                return false; 
        } 
}

 
这个数据源的实现虽然很简陋,总代码量不到百行,却基本上实现了数据源的所有功能,达到了提高Connection复用的目的。
 
如果你想做的更复杂些,做个配置文件,
配置数据库连接信息
写个后台线程监控连接池的Connection超时、被强制关闭、池的尺寸、当前大小等等。
再完善下数据源的log相关方法的实现。
 

DataSource接口(javax.sql.DataSource)替代DriverManager获取Connection的方法,有以下好处:

  • 可以在部署时灵活更换Connection实现;
  • 可以更好的屏蔽数据库的相关性。

以下以Oracle为例说明。

使用厂商DataSource

数据库厂商在提高JDBC2.0和以上版本的JDBC驱动中应该包含厂商的DataSource实现。

OracleDataSource ods = new OracleDataSource();
ods.setUser(“my_user”);
ods.setPassword(“my_password”);
ods.setURL(“jdbc:oracle:thin:@<database>”);
Connection conn = ods.getConnection();

第三方DataSource

第三方厂商也可提供DataSource实现,比如免费开源的有DBCP,C3P0和proxool等,中间件厂商比如ibm的websphere,bea的weblogic等也都有实现。

以下是DBCP的示例:

BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName(“oracle.jdbc.OracleDriver”); basicDataSource.setUrl(“jdbc:oracle:thin:@<database>”); basicDataSource.setUsername(“user”);basicDataSource.setPassword(“password”); Connection connection=basicDataSource.getConnection();

结合JNDI的DataSource

以tomcat为例,将数据库驱动库复制到{tomcat}/commmon/lib目录下。

配置{tomcat}/conf/context.xml文件,加入:

<Resource name=”jdbc/demo” auth=”Container” type=”javax.sql.DataSource”
        driverClassName=”org.apache.derby.jdbc.ClientDriver”
        url=”jdbc:derby://localhost:1527/demo”
        username=”test”
        password=”test”
        maxActive=”2″
        maxIdle=”1″
        removeAbandoned=”true”
        maxWait=”300″ />

在程序中访问DataSource:

Context initContext = new InitialContext();

// 注意: 以下写法只适用于tomcat(Java:/comp/env).
Context envContext = (Context) initContext.lookup(“java:/comp/env”);
dataSource = (DataSource) envContext.lookup(“jdbc/demo”);

配置内容也可以加到webapp/META-INF/context.xml文件中,这样更便于打包部署。

<%@page import="java.sql.*, javax.sql.*, javax.naming.*"%>
<html>
<head>
<title>Using a DataSource</title>
</head>
<body>
<h1>Using a DataSource</h1>
<%
    DataSource ds = null;
    Connection conn = null;
    ResultSet result = null;
    Statement stmt = null;
    ResultSetMetaData rsmd = null;
    try{
      Context context = new InitialContext();
      Context envCtx = (Context) context.lookup("java:comp/env");
      ds =  (DataSource)envCtx.lookup("jdbc/address");
      if (ds != null) {
        conn = ds.getConnection();
        stmt = conn.createStatement();
        result = stmt.executeQuery("SELECT * FROM AddressList");
       }
     }
     catch (SQLException e) {
        System.out.println("Error occurred " + e);
      }
      int columns=0;
      try {
        rsmd = result.getMetaData();
        columns = rsmd.getColumnCount();
      }
      catch (SQLException e) {
         System.out.println("Error occurred " + e);
      }
 %>
 <table width="90%" border="1">
   <tr>
   <% // write out the header cells containing the column labels
      try {
         for (int i=1; i<=columns; i++) {
              out.write("<th>" + rsmd.getColumnLabel(i) + "</th>");
         }
   %>
   </tr>
   <% // now write out one row for each entry in the database table
         while (result.next()) {
            out.write("<tr>");
            for (int i=1; i<=columns; i++) {
              out.write("<td>" + result.getString(i) + "</td>");
            }
            out.write("</tr>");
         }
 
         // close the connection, resultset, and the statement
         result.close();
         stmt.close();
         conn.close();
      } // end of the try block
      catch (SQLException e) {
         System.out.println("Error " + e);
      }
      // ensure everything is closed
    finally {
     try {
       if (stmt != null)
        stmt.close();
       }  catch (SQLException e) {}
       try {
        if (conn != null)
         conn.close();
        } catch (SQLException e) {}
    }
 
    %>
</table>
</body>
</html>