DBCP、C3P0、DBUtils的jar包和配置文件(百度云盘):点我下载

JDBC

JDBC(Java 数据库连接,Java Database Connectify)是标准的Java访问数据库的API。JDBC定义了数据库的连接,SQL语句的执行以及处理数据库返回的结果等。

Java应用程序使用JDBC API与数据库连接而实际的动作则是由JDBC驱动程序管理器(JDBC Driver Manager)通过JDBC驱动程序(JDBC Driver)与数据库系统进行连接。所以其实真正提供存取数据库功能的是JDBC驱动程序(JDBC Driver)。JDBC驱动程序(JDBC Driver)由数据库厂家自己提供,JDBC提供了一个通用的JDBC Driver Manager,用来管理各种数据库厂家提供的JDBC驱动程序,从而访问其数据库。

img

JDBC接口层把各个厂家的JDBC驱动程序都进行了包装,这样你在实际开发中只需要使用JDBC API提供给你的接口就够了,而不需要关心底层的细节。

img

JDBC的使用

  1. JDBC的连接

    JDBC连接数据库,首先需要加载JDBC驱动程序,然后再通过JDBC Driver Manager得到一个对该数据库连接的Connection对象。

    先新建一个名为jdbc.properties配置文件,里面写上用于连接的driverClass,user,password,url四个属性,这样可以避免信息直接暴露在代码里,而且易于维护。

    jdbc.properties:

    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    name=root
    password=123456
    

    编写一个工具类JDBCUtil,用于得到Connection对象和关闭资源等功能,待会我们将会使用该工具类。

    JDBCUtil:

    package utils;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    public class JDBCUtil {
        private static String DRIVERCLASS = null;
        private static String NAME = null;
        private static String PASSWORD = null;
        private static String URL = null;
    
        //得到配置信息
        static {
            try {
                Properties properties = new Properties();
                InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
                properties.load(is);
                DRIVERCLASS = properties.getProperty("driverClass");
                URL = properties.getProperty("url");
                NAME = properties.getProperty("name");
                PASSWORD = properties.getProperty("password");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //保证驱动程序只加载一次
        static {
            try {
                Class.forName(DRIVERCLASS);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        //得到Connection对象
        public static Connection getConn() {
            try {
                return DriverManager.getConnection(URL, NAME, PASSWORD);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        //关闭操作
        public static void release(Connection conn , Statement st , ResultSet rs) throws SQLException {
            closeResultSet(rs);
            closeStatement(st);
            closeConn(conn);
        }
    
        private static void closeConn(Connection conn) throws SQLException {
            if(conn!=null){
                conn.close();
            }
        }
    
        private static void closeStatement(Statement st) throws SQLException{
            if(st!=null){
                st.close();
            }
        }
    
        private static void closeResultSet(ResultSet rs) throws SQLException{
            if(rs!=null){
                rs.close();
            }
        }
    
    }
    
  2. 执行SQL语句的Statement对象

    Statement对象用于将SQL语句发送到数据库中,主要有三种Statement对象:

    • Statement:用于执行不带参数的简单SQL语句:

      String sql = "select * from stuifo where id= 1";

      Statement st = conn.createStatement();

      st.excuteUpdate(sql);  //执行增删改语句

      st.excuteQuery(sql);  //执行查询语句

      Statement的sql语句必须是完整的,不能带有参数。

    • PreparedStatement(从Statement继承):用于执行带或不带输入参数的预编译SQL语句,用?表示参数,由于PreparedStatement对象已预编译过,所以其执行速度要快于Statement对象。

      String sql = "select * from stuifo where id = ?";

      PreparedStatement ps=conn.prepareStatement(sql);

      ps.setInt(index, value);

      ps.excuteUpdate();  //执行增删改语句

      ps.excuteQuery();  //执行查询语句

    • CallableStatement(从PreparedStatement继承):用于执行数据库存储过程的调用。现在还没用到,用到再学习一下。

    总结:平常开发中使用的最多的是PreparedStatement,因为它可以设置参数,预编译,执行速度更快。

  3. 获得结果集对象

    int num = ps.excuteUpdate();  //执行增删改的语句,返回表中受影响的行数。

    ResultSet rs = ps.excuteQuery();  //执行查询语句,返回查询的结果集,里面存放的是一行一行的数据表的信息。

  4. 处理结果集

    while (resultSet.next()) {
    	resultSet.getString(index);  //index代表第几列,从1开始
    	resultSet.getString(String);  //使用字段名称
    }
    

    从数据库中得到字段,数据库中的字段有自己的类型,需要了解数据库中字段类型与Java数据类型的类型转换,这样才能在Java程序中正确的操作数据库中的数据。

    SQL类型 Jdbc(rs)对应方法 返回类型
    BIT(1) bit(10) getBoolean getBytes() Boolean byte[]
    TINYINT getByte() Byte
    SMALLINT getShort() Short
    Int getInt() Int
    BIGINT getLong() Long
    CHAR,VARCHAR,LONGVARCHAR getString() String
    Text(clob) Blob getClob getBlob() Clob Blob
    DATE getDate(), getString() java.sql.Date
    TIME getTime() java.sql.Time
    TIMESTAMP getTimestamp java.sql.Timestamp

数据库连接池

理解数据库连接池

数据库的连接对象创建工作是非常消耗性能的,每次使用时都要重新创建一个Connection对象,这样会导致程序的效率非常低,所以就有了数据库连接池的概念。一开始在内存中开辟一块空间(集合),在池子里放置多个连接对象,我们需要使用连接对象的时候就不需要自己创建连接对象了,直接在里面拿就可以,使用完再归还到池子里,这样能大大的提高程序的效率。

img

自定义数据库连接池

JDBC提供了统一的数据库连接池接口DataSource,里面定义了很多方法,我们只需要实现该接口即可。我们自定义数据库连接池的功能主要有4个:

  • 一开始先往池子里放入10个连接对象。
  • 一个对外提供连接对象的接口。
  • 回收连接对象的接口。
  • 连接对象用完时,可以扩容。

但是DataSource接口里并没有提供回收连接对象的方法,所以需要我们自己定义一个回收连接对象的方法addBack()。

池子实际上就是一个存有Connection对象的集合,我们对数据库连接池的操作实际就是针对该集合的操作。

必须使用单例模式,所有的程序应该使用同一个数据库连接池对象,否则每次想获取连接时都会创建一个新的数据库连接池对象,这样就完全违背了数据库连接池本来的意义。

MyDataSource:

package utils;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * 一个数据库连接池
 * 1、一开始先往池子里放10个连接
 * 2、通过getConnection获取连接
 * 3、用完后addBack归还连接
 * 4、扩容
 */
public class MyDataSource implements DataSource {

    private static final MyDataSource myDataSource = new MyDataSource();
    private static final List<Connection> list = new ArrayList<>();

    private MyDataSource() {}

    //一开始放置10个连接
    public static MyDataSource getMyDataSource() {
        for(int i = 0; i < 10; i++) {
            Connection conn = JDBCUtil.getConn();
            list.add(conn);
        }
        return myDataSource;
    }

    //对外提供连接的方法
    @Override
    public Connection getConnection() throws SQLException {
        //扩容,看池子里还有没有连接对象,没有就增加5个
        if(list.size() == 0) {
            for(int i = 0; i < 5; i++) {
                Connection conn = JDBCUtil.getConn();
                list.add(conn);
            }
        }
        return list.remove(0);
    }

    //DataSource接口中没有该方法,自己定义的方法,归还Connection
    public void addBack(Connection conn) throws SQLException {
        list.add(conn);
    }

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

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

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

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

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

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

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

使用自定义数据库连接池MyDataSourceTest:

import utils.JDBCUtil;
import utils.MyDataSource;

import java.sql.*;

public class MyDataSourceTest {
    public static void main (String[] args) {
        try {
            //得到自定义数据连接池
            MyDataSource myDataSource = MyDataSource.getMyDataSource();
            //得到连接对象
            Connection connection = myDataSource.getConnection();
            String sql = "select * from stuifo";
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                String string1 = resultSet.getString(1);
                String string2 = resultSet.getString(2);
                System.out.println(string1 + string2);
            }
            //归还连接对象
            myDataSource.addBack(connection);
            //释放资源
            JDBCUtil.release(connection, statement, resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

这个自定义数据库连接池实现了基本的功能,但是有一个很大的问题,在上面提到JDBC提供的DataSource接口没有addBack()方法,这个方法是我们在实现DataSource接口时自己定义的,我们额外的给他添加了该功能,这意味着什么呢?

  • 无法使用面向接口编程:

    DataSource dataSource = MyDataSource().getMyDataSource();

    dataSource.addBack(connection);  ✖这是错的,DataSource接口中并没有定义该方法

  • 用户在使用该MyDataSource时,必须记住还有一个额外方法addBack(),这个方法不是JDBC规范的方法

    MyDataSource myDataSource = MyDataSource().getMyDataSource();

    myDataSource.addBack(connection);

如何解决自定义数据库连接池出现的问题呢?

可以考虑不在MyDataSource中实现归还连接对象的功能,这样就可以实现面向接口编程,我们可以修改Connection接口中的那个close方法。 原来的Connection对象的close方法,是真的关闭连接。 打算修改这个close方法,以后在调用close, 并不是真的关闭,而是归还连接对象。

如何扩展一个方法呢?

  • 直接修改源代码:这是不切实际的  ✖
  • 继承:但是不知道父类是谁,Connection只是一个接口  ✖
  • 装饰者模式:装饰者模式指的是在不改变原类和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。  ✔

如何理解装饰者模式?详细了解请看设计模式中装饰者模式这一篇,go There。

这里简单来说就是创建一个包装对象,用来包装连接对象,包装对象继承Connection接口,连接对象以Connection接口传到包装对象中,包装对象再扩充连接对象。

img

ConnectionWrap:

package utils;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

public class ConnectionWrap implements Connection {

    private Connection connection = null;
    private List<Connection> list = null;

    public ConnectionWrap(Connection connection, List<Connection> list) {
        super();
        this.connection = connection;
        this.list = list;
    }
    
    @Override
    public void close() throws SQLException {
        System.out.println("有人归还了");
        list.add(connection);
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }

    @Override
    public Statement createStatement() throws SQLException {
        return connection.createStatement();
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return null;
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        return null;
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {

    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return false;
    }

    @Override
    public void commit() throws SQLException {

    }

    @Override
    public void rollback() throws SQLException {

    }

    @Override
    public boolean isClosed() throws SQLException {
        return false;
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return null;
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {

    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return false;
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {

    }

    @Override
    public String getCatalog() throws SQLException {
        return null;
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {

    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        return 0;
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        return null;
    }

    @Override
    public void clearWarnings() throws SQLException {

    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return null;
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return null;
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {

    }

    @Override
    public void setHoldability(int holdability) throws SQLException {

    }

    @Override
    public int getHoldability() throws SQLException {
        return 0;
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        return null;
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return null;
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {

    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {

    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return null;
    }

    @Override
    public Clob createClob() throws SQLException {
        return null;
    }

    @Override
    public Blob createBlob() throws SQLException {
        return null;
    }

    @Override
    public NClob createNClob() throws SQLException {
        return null;
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        return null;
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        return false;
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {

    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {

    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return null;
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return null;
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return null;
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return null;
    }

    @Override
    public void setSchema(String schema) throws SQLException {

    }

    @Override
    public String getSchema() throws SQLException {
        return null;
    }

    @Override
    public void abort(Executor executor) throws SQLException {

    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {

    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return 0;
    }

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

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

改写后的MyDataSource:

package utils;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {

    private static final MyDataSource myDataSource = new MyDataSource();
    private static final List<Connection> list = new ArrayList<>();

    private MyDataSource() {}

    //一开始放置10个连接
    public static MyDataSource getMyDataSource() {
        for(int i = 0; i < 10; i++) {
            Connection conn = JDBCUtil.getConn();
            list.add(conn);
        }
        return myDataSource;
    }

    //对外提供连接的方法
    @Override
    public Connection getConnection() throws SQLException {
        //扩容,看池子里还有没有连接对象,没有就增加5个
        if(list.size() == 0) {
            for(int i = 0; i < 5; i++) {
                Connection conn = JDBCUtil.getConn();
                list.add(conn);
            }
        }
        Connection conn =  list.remove(0);
        return new ConnectionWrap(conn, list);
    }

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

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

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

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

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

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

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

改写后的MyDataSourceTest:

import utils.JDBCUtil;
import utils.MyDataSource;

import javax.sql.DataSource;
import java.sql.*;

public class MyDataSourceTest {
    public static void main (String[] args) {
        try {
            //得到自定义数据连接池
            DataSource dataSource = MyDataSource.getMyDataSource();
            //得到连接对象
            Connection connection = dataSource.getConnection();
            String sql = "select * from stuifo";
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                String string1 = resultSet.getString(1);
                String string2 = resultSet.getString(2);
                System.out.println(string1 + string2);
            }
            //释放资源
            JDBCUtil.release(connection, statement, resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

使用开源连接池

DBCP

DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。

使用之前需要导入两个jar包,commons-dbcp.jar和commons-pool.jar。

使用:

首先要编写配置文件dbcpconfig.properties,这个配置文件定义了连接设置,即数据库连接的四个参数,还有dbcp连接池的一些基本配置,比如初始化连接对象个数,最大连接数量等等。。。

dbcpconfig.properties:

#连接设置
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/student
name=root
password=123456

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

使用dbcp连接池做一个简单的查询DBCPTest:

package utils;


import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class DBCPTest {
    private static void main(String[] args) throws Exception {
        //得到配置文件
        Properties properties = new Properties();
        InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
        properties.load(is);
        //创建数据库连接池
        BasicDataSourceFactory factory = new BasicDataSourceFactory();
        DataSource dataSource = factory.createDataSource(properties);
        //简单查询
        Connection conn = dataSource.getConnection();
        String sql = "select * from stuifo";
        PreparedStatement preparedStatement = conn.prepareStatement(sql);
        ResultSet rs = preparedStatement.executeQuery();
        while(rs.next()) {
            String value1 = rs.getString(1);
            String value2 = rs.getString(2);
            System.out.println(value1 + " " + value2);
        }
        conn.close();
        preparedStatement.close();
        rs.close();
    }
}

C3P0

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

使用时需要添加C3P0的两个jar包,c3p0.jar和mchange-commons-java.jar。

使用:

首先也是要编写配置文件c3p0-config.xml,里面的内容与上面dbcp的配置文件dbcpconfig.properties内容大体一致,也是一些初始化的参数。

c3p0-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

    <!-- default-config 默认的配置,  -->
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost/student?useSSL=false</property>
    <property name="user">root</property>
    <property name="password">123456</property>
    
    
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">200</property>
  </default-config>
  
   <!-- This app is massive! -->
  <named-config name="oracle"> 
    <property name="acquireIncrement">50</property>
    <property name="initialPoolSize">100</property>
    <property name="minPoolSize">50</property>
    <property name="maxPoolSize">1000</property>

    <!-- intergalactoApp adopts a different approach to configuring statement caching -->
    <property name="maxStatements">0</property> 
    <property name="maxStatementsPerConnection">5</property>

    <!-- he's important, but there's only one of him -->
    <user-overrides user="master-of-the-universe"> 
      <property name="acquireIncrement">1</property>
      <property name="initialPoolSize">1</property>
      <property name="minPoolSize">1</property>
      <property name="maxPoolSize">5</property>
      <property name="maxStatementsPerConnection">50</property>
    </user-overrides>
  </named-config>

 
</c3p0-config>

把该c3p0连接池封装在JDBCUtil中,从连接池中得到连接对象,就不需要我们自己编写加载JDBC驱动器,获取连接对象等等。

优化后的JDBCUtil:

package utils;

import java.sql.*;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;

public class JDBCUtil {

    private static ComboPooledDataSource dataSource = null;
    static{
        dataSource = new ComboPooledDataSource();
    }

    public static DataSource getDataSource() {
        return dataSource;
    }

    public static Connection getConn() throws SQLException{
        return dataSource.getConnection();
    }

    //关闭操作
    public static void release(Connection conn , Statement st , ResultSet rs) {
        closeResultSet(rs);
        closeStatement(st);
        closeConn(conn);
    }

    private static void closeConn(Connection conn) {
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    private static void closeStatement(Statement st) {
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    private static void closeResultSet(ResultSet rs) {
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
}

DBUtils

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

使用时需要添加dbutil的jar包,commons-dbutils.jar。

使用:

首先需要创建QueryRunner对象,这里就需要使用到上面基于C3P0连接池的JDBCUtil,创建QueryRunner对象需要向其构造函数传入一个数据库连接池。

QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

现在就可以使用该queryRunner对象进行CRUD操作了。

以数据库student下的stuifo表为例:

img

  1. 查询

    查询:queryRunner.query(sql, hander, params),sql为sql语句,hander为java.sql.ResultSetHander接口的实现类,该接口用于处理java.sql.ResultSet,将查询到的数据按要求转换为另一种形式,比如自定义对象,ArrayList,Map...,params为sql语句中的参数(可变参数,取决于?的个数)。

    ResultSetHandler接口的实现类:

    • ArrayHandler :将ResultSet中第一行的数据转化成对象数组
    • ArrayListHandler将ResultSet中所有的数据转化成List,List中存放的是Object[]
    • BeanHandler :将ResultSet中第一行的数据转化成类对象
    • BeanListHandler :将ResultSet中所有的数据转化成List,List中存放的是类对象
    • ColumnListHandler :将ResultSet中某一列的数据存成List,List中存放的是Object对象
    • KeyedHandler :将ResultSet中存成映射,key为某一列对应为Map。Map中存放的是数据
    • MapHandler :将ResultSet中第一行的数据存成Map映射
    • MapListHandler :将ResultSet中所有的数据存成List。List中存放的是Map
    • ScalarHandler :将ResultSet中一条记录的其中某一列的数据存成Object,常用于聚合函数。

    举例:

    创建一个Student类,里面定义了上面id、scold、name、sex四个属性,Student类中的属性必须要与数据库中的字段名一一对应,否则将会查询失败。

    Student:

    package model;
    
    public class Student {
        private int id;
        private String scold;
        private String name;
        private String sex;
    
        public Student(int id, String scold, String name, String sex) {
            this.id = id;
            this.scold = scold;
            this.name = name;
            this.sex = sex;
        }
    
        public Student() {
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getScold() {
            return scold;
        }
    
        public void setScold(String scold) {
            this.scold = scold;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", scold='" + scold + '\'' +
                    ", name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    '}';
        }
    }
    

    BeanHander:

    private static void main(String[] args) throws Exception {
            //查询id为1的学生
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            String sql = "select *  from stuifo where id = ?";
            int id = 1;
            Student student = queryRunner.query(sql, new BeanHandler<>(Student.class), id);
            System.out.println(student.toString());
        }
    

    BeanListHander:

    public static void main(String[] args) throws Exception {
            //查询所有学生
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            String sql = "select *  from stuifo";
            List<Student> list = queryRunner.query(sql, new BeanListHandler<>(Student.class));
            System.out.println(list);
        }
    

    ScalarHandler:

    public static void main(String[] args) throws Exception {
            //查询一共有多少学生
           QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
           String sql = "select count(*) from stuifo";
           Object obj = queryRunner.query(sql, new ScalarHandler<>());
           Long num = (Long) obj;
           System.out.println(num.intValue());
        }
    
  2. 增删改

    增删改:queryRunner.update(sql, params),第一个参数sql为要执行的sql语句,后面为sql语句中的参数(可变参数,取决于sql语句中?号的多少)。

    插入学生:

    public static void main(String[] args) throws Exception {
            //插入学生
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            String sql = "insert into stuifo values(null, ?, ?, ?)";
            String scold = "111111";
            String name = "大耳朵图图";
            String sex = "男";
            queryRunner.update(sql, scold, name, sex);
        }  
    

    更新学生信息:

    public static void main(String[] args) throws Exception {
            //修改id为1的学生的性别为女
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            String sql = "update stuifo set sex = ? where id = ?";
            int id = 1;
            String sex = "女";
            queryRunner.update(sql, sex, id);
        }
    

    删除学生:

    public static void main(String[] args) throws Exception {
            //删除id为1的学生
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            String sql = "delete from stuifo where id = ?";
            int id = 1;
            queryRunner.update(sql, id);
        }
    

总结:虽然这一篇内容很多,但是实际上就是对数据库的一些操作,平常开发中只要使用基于C3P0连接池的JDBCUtil工具类,和DBUtils工具类就可以完成基本开发了。这样比我们自己手写创建连接,进行CRUD操作,高效多了。

posted on 2018-10-13 10:31  kindleheart  阅读(241)  评论(0编辑  收藏  举报