javaweb获取数据库连接

本文探讨了JavaWeb应用程序直接获取数据库连接的缺点,如资源浪费和效率低下,并介绍了使用数据库连接池进行性能优化。详细讲解了数据库连接池的基本概念,如如何创建和管理连接,以及如何设置连接池的最小和最大连接数。接着,文章列举了开源数据库连接池DBCP和C3P0的特点及使用方法,并简述了如何在Tomcat中配置数据源以利用JNDI技术获取数据库连接。
摘要由CSDN通过智能技术生成

一、应用程序直接获取数据库连接的缺点

用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。如下图所示:

  

二、使用数据库连接池优化程序性能

2.1、数据库连接池的基本概念

  数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。如下图所示:

  

       数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中.

       数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:

  1. 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
  2. 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
  3. 如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接.不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是空间超时后被释放.

2.2、编写数据库连接池

  编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:

  • Connection getConnection()
  • Connection getConnection(String username, String password)

  实现DataSource接口,并实现连接池功能的步骤:

  1. 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
  2. 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
  3. 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到LinkedList中是此处编程的难点

 数据库连接池核心代码

  使用动态代理技术构建连接池中的connection

proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()
            .getClassLoader(), new Class[]{Connection.class},
            new InvocationHandler() {
        //此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行
            public Object invoke(Object proxy, Method method,
                      Object[] args) throws Throwable {
                if (method.getName().equals("close")) {
                    pool.addLast(conn);
                    return null;
            }
            return method.invoke(conn, args);
        }
    });


数据库连接池编写范例:

package me.gacl.demo;

import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;
import javax.sql.DataSource;

/**
* @ClassName: JdbcPool
* @Description:编写数据库连接池
* @author: 孤傲苍狼
* @date: 2014-9-30 下午11:07:23
*
*/
public class JdbcPool implements DataSource{

    /**
    * @Field: listConnections
    *         使用LinkedList集合来存放数据库链接,
    *        由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适
    */
    private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
    
    static{
        //在静态代码块中加载db.properties数据库配置文件
        InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
        Properties prop = new Properties();
        try {
            prop.load(in);
            String driver = prop.getProperty("driver");
            String url = prop.getProperty("url");
            String username = prop.getProperty("username");
            String password = prop.getProperty("password");
            //数据库连接池的初始化连接数大小
            int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
            //加载数据库驱动
            Class.forName(driver);
            for (int i = 0; i < jdbcPoolInitSize; i++) {
                Connection conn = DriverManager.getConnection(url, username, password);
                System.out.println("获取到了链接" + conn);
                //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池
                listConnections.add(conn);
            }
            
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public int getLoginTimeout() throws SQLException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        // TODO Auto-generated method stub
        return false;
    }

    /* 获取数据库连接
     * @see javax.sql.DataSource#getConnection()
     */
    @Override
    public Connection getConnection() throws SQLException {
        //如果数据库连接池中的连接对象的个数大于0
        if (listConnections.size()>0) {
            //从listConnections集合中获取一个数据库连接
            final Connection conn = listConnections.removeFirst();
            System.out.println("listConnections数据库连接池大小是" + listConnections.size());
            //返回Connection对象的代理对象
            return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    if(!method.getName().equals("close")){
                        return method.invoke(conn, args);
                    }else{
                        //如果调用的是Connection对象的close方法,就把conn还给数据库连接池
                        listConnections.add(conn);
                        System.out.println(conn + "被还给listConnections数据库连接池了!!");
                        System.out.println("listConnections数据库连接池大小为" + listConnections.size());
                        return null;
                    }
                }
            });
        }else {
            throw new RuntimeException("对不起,数据库忙");
        }
    }

    @Override
    public Connection getConnection(String username, String password)
            throws SQLException {
        return null;
    }
}


 db.properties配置文件如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy
username=root
password=XDP

jdbcPoolInitSize=10

写一个JdbcUtil测试数据库连接池

package me.gacl.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import me.gacl.demo.JdbcPool;

public class JdbcUtil {
    
    /**
    * @Field: pool
    *          数据库连接池
    */
    private static JdbcPool pool = new JdbcPool();
    
    /**
    * @Method: getConnection
    * @Description: 从数据库连接池中获取数据库连接对象
    * @Anthor:孤傲苍狼
    * @return Connection数据库连接对象
    * @throws SQLException
    */
    public static Connection getConnection() throws SQLException{
        return pool.getConnection();
    }
    
    /**
    * @Method: release
    * @Description: 释放资源,
    * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
    * @Anthor:孤傲苍狼
    *
    * @param conn
    * @param st
    * @param rs
    */
    public static void release(Connection conn,Statement st,ResultSet rs){
        if(rs!=null){
            try{
                //关闭存储查询结果的ResultSet对象
                rs.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(st!=null){
            try{
                //关闭负责执行SQL命令的Statement对象
                st.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        if(conn!=null){
            try{
                //关闭Connection数据库连接对象
                conn.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


三、开源数据库连接池

  现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。
  也有一些开源组织提供了数据源的独立实现:

  • DBCP 数据库连接池
  • C3P0 数据库连接池

  在使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了,直接从数据源获得数据库的连接。

3.1、DBCP数据源

  DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 文件:

  • Commons-dbcp.jar:连接池的实现
  • Commons-pool.jar:连接池实现的依赖库

  Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

3.2、在应用程序中加入dbcp连接池

  1.导入相关jar包
        commons-dbcp-1.2.2.jar、commons-pool.jar
  2、在类目录下加入dbcp的配置文件:dbcpconfig.properties

    dbcpconfig.properties的配置信息如下:

复制代码
 1 #连接设置
 2 driverClassName=com.mysql.jdbc.Driver
 3 url=jdbc:mysql://localhost:3306/jdbcstudy
 4 username=root
 5 password=XDP
 6 
 7 #<!-- 初始化连接 -->
 8 initialSize=10
 9 
10 #最大连接数量
11 maxActive=50
12 
13 #<!-- 最大空闲连接 -->
14 maxIdle=20
15 
16 #<!-- 最小空闲连接 -->
17 minIdle=5
18 
19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
20 maxWait=60000
21 
22 
23 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
24 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
25 connectionProperties=useUnicode=true;characterEncoding=UTF8
26 
27 #指定由连接池所创建的连接的自动提交(auto-commit)状态。
28 defaultAutoCommit=true
29 
30 #driver default 指定由连接池所创建的连接的只读(read-only)状态。
31 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
32 defaultReadOnly=
33 
34 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
35 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
36 defaultTransactionIsolation=READ_UNCOMMITTED
复制代码

  如下图所示:

  

  3、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池

复制代码
 1 package me.gacl.util;
 2 
 3 import java.io.InputStream;
 4 import java.sql.Connection;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 import java.util.Properties;
 9 import javax.sql.DataSource;
10 import org.apache.commons.dbcp.BasicDataSourceFactory;
11 
12 /**
13 * @ClassName: JdbcUtils_DBCP
14 * @Description: 数据库连接工具类
15 * @author: 孤傲苍狼
16 * @date: 2014-10-4 下午6:04:36
17 *
18 */ 
19 public class JdbcUtils_DBCP {
20     /**
21      * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现
22      * DBCP连接池就是java.sql.DataSource接口的一个具体实现
23      */
24     private static DataSource ds = null;
25     //在静态代码块中创建数据库连接池
26     static{
27         try{
28             //加载dbcpconfig.properties配置文件
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaWeb项目中连接数据库sqlyog,你可以按照以下步骤进行操作: 1. 导入数据库驱动包:将下载好的MySQL Connector/J驱动包(例如mysql-5.1.45-bin.jar)复制到你的项目的lib目录下。 2. 在项目中配置数据库连接信息:在你的项目中的配置文件(如web.xml或者spring配置文件)中添加数据库连接的相关配置,包括数据库URL、用户名、密码等。 3. 创建数据库连接:在你的Java代码中,使用JDBC API来创建数据库连接。以下是一个示例代码: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnection { private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name"; private static final String USER = "your_username"; private static final String PASS = "your_password"; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(DB_URL, USER, PASS); } } ``` 4. 使用数据库连接进行操作:通过调用getConnection()方法获取数据库连接对象,然后使用该连接对象执行SQL语句或者其他数据库操作。 ```java import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Main { public static void main(String[] args) { Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { connection = DatabaseConnection.getConnection(); statement = connection.createStatement(); resultSet = statement.executeQuery("SELECT * FROM your_table_name"); while (resultSet.next()) { // 处理查询结果 } } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭资源 try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ``` 请注意,上述代码中的"your_database_name"、"your_username"、"your_password"和"your_table_name"需要根据你的实际情况进行替换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值