Java-JDBC中的数据源和连接池

在上一篇文章Java JDBC Steps to Connect to DB中给出的示例中,我们已经了解了如何使用DriverManager类获取连接。这对于您只需要使用连接进行测试并关闭它的示例代码是可以的。但是在现实生活中的应用程序中,每次需要数据库交互时创建连接对象将非常耗时。您需要的是一个连接池,其中一开始就创建了给定数量的连接对象并被重用。

在这篇文章中,我们将看到另一种使用提供连接池的 DataSource 对象从 Java 应用程序连接到 DB 的方法。在 JDBC 中使用 DataSource 还有其他优点。

使用数据源的优势

  1. 抽象层——在企业应用程序中,您可以在应用程序服务器中配置 JDBC 数据源并将其注册到 JNDI。这样,用户只需要知道 DataSource 的绑定逻辑名称,并且隐藏了 DB 特定的详细信息。

  2. 连接池- 如果池中有一个可以满足请求的连接,它会将连接返回给应用程序。如果池中的所有连接都在使用中,则会创建一个新连接并将其返回给应用程序。应用程序使用连接在数据库上执行一些工作,然后将对象返回到池中。然后该连接可用于下一个连接请求。

    通过将连接池化,您可以重用连接对象,而不是每次都创建它,从而提高数据库密集型应用程序的性能,因为创建连接对象在时间和资源方面都是昂贵的。

  3. 分布式事务——DataSource 实现还可以提供可用于分布式事务的连接对象。分布式事务是访问两个或多个 DBMS 服务器的事务。

Java中的数据源接口

JDBC API 提供了一个接口DataSource,该接口必须由供应商特定的 DataSource 实现来实现。DataSource 接口是javax.sql 包的一部分,它有两个被覆盖的方法。

  • 获取连接()
  • getConnection(字符串用户名,字符串密码)

这两种方法都返回一个Connection对象。

数据源实现

一个 JDBC 驱动程序应该至少包含一个基本的 DataSource 实现。例如 MySQL DB JDBC 驱动程序包括实现com.mysql.jdbc.jdbc2.optional.MysqlDataSource和 Oracle DB 的实现是 oracle.jdbc.pool.OracleDataSource

JDBC 数据源示例

让我们看一些使用中的 DataSource 示例。首先让我们看一个 MySQL 数据源的例子。尽管人们更喜欢将连接池库之一Apache DBCPmchange c3p0至少与独立的 Java 程序一起使用,但我们也会看到这些示例。

MySQL 数据源示例

这里我们有一个 DataSource 类,它是一个提供 MysqlDataSource 实例的单例类。MySQL 中的模式也是netjs,表是Employee。您的类路径中应该有mysql-connector jar。

还有另一个类 DSConnection,我们在其中获取 MysqlDataSource 的实例并使用它来获取 Connection 对象。

然后使用 Select SQL 语句创建PreparedStatement对象,以获取具有传递 ID 的 Employee 数据。

DataSource.java


import com.mysql.cj.jdbc.MysqlDataSource;

public class DataSource {

    private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
    private static final String DB_CONNECTION_URL = "jdbc:mysql://localhost:3306/testdb";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "root";
    private static DataSource ds;
    private MysqlDataSource mySqlDS = new MysqlDataSource();

    //private constructor
    private DataSource() {
        //mySqlDS.setDriverClassName(DRIVER_CLASS);
        mySqlDS.setUrl(DB_CONNECTION_URL);
        mySqlDS.setUser(DB_USER);
        mySqlDS.setPassword(DB_PWD);
    }

    /**
     * static method for getting instance.
     */
    public static DataSource getInstance() {
        if (ds == null) {
            ds = new DataSource();
        }
        return ds;
    }

    public MysqlDataSource getMySqlDS() {
        return mySqlDS;
    }

    public void setMySqlDS(MysqlDataSource mySqlDS) {
        this.mySqlDS = mySqlDS;
    }
}

DSConnection.java


import com.mysql.cj.jdbc.MysqlDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DSConnection {

    public static void main(String[] args) {
        DSConnection dsCon = new DSConnection();
        try {
            dsCon.displayEmployee(1);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param connection
     * @param id
     * @throws SQLException
     */
    private void displayEmployee(int id) throws SQLException {

        Connection connection = null;
        String selectSQL = "Select * from employee where id = ?";
        PreparedStatement prepStmt = null;
        try {
            MysqlDataSource basicDS = DataSource.getInstance().getMySqlDS();
            connection = basicDS.getConnection();
            prepStmt = connection.prepareStatement(selectSQL);
            prepStmt.setInt(1, id);
            ResultSet rs = prepStmt.executeQuery();
            while (rs.next()) {
                System.out.println("id : " + rs.getInt("id") + " Name : "
                        + rs.getString("name") + " Age : " + rs.getInt("age"));
            }
        } finally {
            if (prepStmt != null) {
                prepStmt.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

使用 Apache DBCP 的数据源示例

对于需要数据源的独立 Java 程序,使用 DBCP 等连接池库会更方便。

您需要项目的类路径中的以下 jars(下载路径- DBCP – Overview),根据您的 Java 和 DB 版本检查版本。

commons-dbcp2-2.1.1.jar
commons-pool2-2.5.0.jar
commons-logging-1.2.jar

以及所用数据库的 JDBC 驱动程序。在此示例中使用 MySQL,因此使用 mysql-connector-java-5.1.39 jar。

这里我们有一个 DataSource 类,它是一个创建并返回 dbcp2 BasicDataSource 实例的单例类。

还有另一个类 DSConnection,我们在其中获取 dbcp2 BasicDataSource 的实例并使用它来获取 Connection 对象。

然后使用 Select SQL 语句创建 PreparedStatement 对象,以获取具有传递 ID 的 Employee 数据。

MySQL 中的数据库模式是 netjs,表是 Employee。

DataSource.java

package DBCP;

import org.apache.commons.dbcp2.BasicDataSource;

public class DataSource {

    private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
    private static final String DB_CONNECTION_URL = "jdbc:mysql://localhost:3306/testdb";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "root";
    private static DataSource ds;
    private BasicDataSource basicDS = new BasicDataSource();

    //private constructor
    private DataSource() {
        //BasicDataSource basicDS = new BasicDataSource();
        basicDS.setDriverClassName(DRIVER_CLASS);
        basicDS.setUrl(DB_CONNECTION_URL);
        basicDS.setUsername(DB_USER);
        basicDS.setPassword(DB_PWD);

        // Parameters for connection pooling
        basicDS.setInitialSize(10);
        basicDS.setMaxTotal(10);
    }

    /**
     * static method for getting instance.
     */
    public static DataSource getInstance() {
        if (ds == null) {
            ds = new DataSource();
        }
        return ds;
    }

    public BasicDataSource getBasicDS() {
        return basicDS;
    }

    public void setBasicDS(BasicDataSource basicDS) {
        this.basicDS = basicDS;
    }
}

DSConnection.java

package DBCP;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.dbcp2.BasicDataSource;

public class DSConnection {

    public static void main(String[] args) {
        DSConnection dsCon = new DSConnection();
        try {
            dsCon.displayEmployee(1);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param connection
     * @param id
     * @throws SQLException
     */
    private void displayEmployee(int id) throws SQLException {

        Connection connection = null;
        String selectSQL = "Select * from employee where id = ?";
        PreparedStatement prepStmt = null;
        try {
            BasicDataSource basicDS = DataSource.getInstance().getBasicDS();
            connection = basicDS.getConnection();
            prepStmt = connection.prepareStatement(selectSQL);
            prepStmt.setInt(1, id);
            ResultSet rs = prepStmt.executeQuery();
            while (rs.next()) {
                System.out.println("id : " + rs.getInt("id") + " Name : "
                        + rs.getString("name") + " Age : " + rs.getInt("age"));
            }
        } finally {
            if (prepStmt != null) {
                prepStmt.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

使用 c3p0 的数据源示例

获取 DataSource 对象的另一种方法是使用 c3p0 库。使用独立的 Java 程序,您可以创建ComboPooledDataSource的实例。

使用的罐子

c3p0-0.9.5.2.jar
更改-commons-java-0.2.11.jar

如果我们保留与上述相同的类结构。现在课程看起来像 -

DataSource.java

package c3p0;

import java.beans.PropertyVetoException;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DataSource {

    private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
    private static final String DB_CONNECTION_URL = "jdbc:mysql://localhost:3306/testdb";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "root";
    private static DataSource ds;
    private ComboPooledDataSource cpds = new ComboPooledDataSource();

    //private constructor
    private DataSource() throws PropertyVetoException {
        cpds.setDriverClass(DRIVER_CLASS); //loads the jdbc driver
        cpds.setJdbcUrl(DB_CONNECTION_URL);
        cpds.setUser(DB_USER);
        cpds.setPassword(DB_PWD);

        // the settings below are optional
        // c3p0 can work with defaults
        cpds.setMinPoolSize(5);
        cpds.setAcquireIncrement(5);
        cpds.setMaxPoolSize(20);
    }

    /**
     * Static method for getting instance.
     *
     * @throws PropertyVetoException
     */
    public static DataSource getInstance() throws PropertyVetoException {
        if (ds == null) {
            ds = new DataSource();
        }
        return ds;
    }

    public ComboPooledDataSource getCpds() {
        return cpds;
    }

    public void setCpds(ComboPooledDataSource cpds) {
        this.cpds = cpds;
    }
}

DSConnection.java

package c3p0;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DSConnection {

    public static void main(String[] args) throws PropertyVetoException {
        DSConnection dsCon = new DSConnection();
        try {
            dsCon.displayEmployee(1);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param connection
     * @param id
     * @throws SQLException
     * @throws PropertyVetoException
     */
    private void displayEmployee(int id) throws SQLException, PropertyVetoException {

        Connection connection = null;
        String selectSQL = "Select * from employee where id = ?";
        PreparedStatement prepStmt = null;
        try {
            ComboPooledDataSource basicDS = DataSource.getInstance().getCpds();
            connection = basicDS.getConnection();
            prepStmt = connection.prepareStatement(selectSQL);
            prepStmt.setInt(1, id);
            ResultSet rs = prepStmt.executeQuery();
            while (rs.next()) {
                System.out.println("id : " + rs.getInt("id") + " Name : "
                        + rs.getString("name") + " Age : " + rs.getInt("age"));
            }
            for (int i = 1; i <= 1000; i++) {

                Connection conn = basicDS.getConnection();
                System.out.println(conn + " : " + i);

                System.out.println("正在使用连接数:" + basicDS.getNumBusyConnections());
                System.out.println("空闲连接数:" + basicDS.getNumIdleConnections());
                System.out.println("总连接数:" + basicDS.getNumConnections());

                conn.close();
            }

        } finally {
            if (prepStmt != null) {
                prepStmt.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

这就是本主题DataSource in Java-JDBC的全部内容。如果您有任何疑问或任何建议,请发表评论。谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值