JDBC完全解析

前言

以前做项目的时候用到了JDBC操作mysql数据库,后面百度面试问到数据库的时候又忘了,最近几天把项目重新看了一遍,查了相关的文章把JDBC做一个总结。

JDBC的结构

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。Java中使用JDBC的整体结构如下图:
这里写图片描述

JDBC的用途

简单地说,JDBC 主要做四件事:①、加载对应数据库驱动 (Load Driver) ②、与数据库建立连接(connection) ③、发送 操作数据库的语句(createStatement) ④、执行并处理返回结果(executeQuery)如下图:

这里写图片描述

下面是四个步骤简单的代码:

/*1 加载驱动JDBC_DRIVER="com.mysql.jdbc.Driver"*/

Class.forName(JDBC_DRIVER); 

/*2 建立连接DB_URL数据库的url,  USER 数据库的用户名, PASS 数据库密码*/

Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER, PASS);

/*3  sql = "select * from student"预编译sql语句*/
PreparedStatement pstmt=conn.prepareStatement(sql);

/*4执行sql语句并返回结果*/
ResultSet rs = pstmt.executeQuery();

安装mysql以及Navicat for mysql

上面以及简单的讲了一下jdbc为了实现在eclipse上运行操作数据库的效果,必须得先安装某种数据库,我安装的是mysql数据库为了方便操作最好安装mysql数据库可视化工具Navicat for mysql。安装好了之后就可以使用Navicat for mysql来管理数据库了。关于如何安装mysql和使Navicat for mysql用可以看下这篇文章MySQL安装安装好了之后我是用Navicat for mysql建立了一个students的数据库以方便后面的测试。数据库如下图
这里写图片描述
student表很简单就一个id 一个name 一个age 然后自己添加了四条数据。

eclipse配置及运行

首先在eclipse中新建一个DateBase的项目,往项目中添加依赖包mysql-connector-java-5.0.8-bin.jar,然后就来看看如何对上面的数据库进行简单的:插入(insert),更新(update),查询(select)等操作


import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;


public class JDBCDemo {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  //MySQL数据库驱动
    static final String DB_URL = "jdbc:mysql://localhost/students";//数据库地址
    static final String USER = "hanking";//用户名
    static final String PASS = "hu123";//密码
    public static void main(String[] args) {
        try {
            insert();
            update();
            select() ;
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

//  insert() 往数据库中插入一条数据
    private static void insert() throws Exception {

        Connection conn = null;
        PreparedStatement pstsm = null;
        try {
            // 1:调用工具类获取连接
            conn = getConnection();

            // 2:准备sql预编译语句
            // ?占用一个参数位
            String sql = "INSERT INTO student (id,name,age) VALUES (?,?,?);";

            // 3:执行sql预编译语句(检查语法)
            pstsm =(PreparedStatement) conn.prepareStatement(sql);

            // 4:设置传递的参数

            pstsm .setInt(1, 5);
            pstsm .setString(2, "hanking");
            pstsm .setInt(3, 20);

            // 5:发送参数,执行sql
            // 注意:这里的方法后面没有参数
            int result =  pstsm .executeUpdate();
            System.out.println("影响了" + result + "行");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
             pstsm.close();
             conn.close();
            // 6:关闭连接
        }
    }

//  更新数据库中的一条数据 
     private static int update() {
            Connection conn = getConnection();
            int i = 0;
            String sql = "UPDATE student SET age = ? WHERE id = ?;";
            PreparedStatement pstmt;
            try {
                pstmt = (PreparedStatement) conn.prepareStatement(sql);
                pstmt.setInt(1, 20);
                pstmt.setInt(2, 1);            
                i = pstmt.executeUpdate();
                System.out.println("resutl: " + i);
                pstmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return i;
        }

//选择出数据库中所有的数据      
     private static void select() {   
            Connection conn = getConnection();
            String sql = "select * from student";
            PreparedStatement pstmt;
            try {
                pstmt = (PreparedStatement) conn.prepareStatement(sql);
                ResultSet rs = pstmt.executeQuery();
                int col = rs.getMetaData().getColumnCount();
                System.out.println("============================");
                while (rs.next()) {
                    for (int i = 1; i <= col; i++) {
                        System.out.print(rs.getString(i) + "\t");
                        if ((i == 2) && (rs.getString(i).length() < 8)) {
                            System.out.print("\t");
                        }
                     }
                    System.out.println("");
                }
                    System.out.println("============================");
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
    private static Connection getConnection() {

        Connection conn = null;
        try {
            Class.forName(JDBC_DRIVER); //classLoader,加载对应驱动
            conn = (Connection) DriverManager.getConnection(DB_URL, USER, PASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
}
//最后输出如下
============================
1   hust0       20  
2   hust1       24  
3   hust2       25  
4   hust3       23  
5   hanking     20  
============================

数据库连接池

上面的例子简单的实现了通过JDBC对数据库进行的简单操作,然而实际项目中往往会使用到数据库连接池,原因:对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
这里写图片描述

数据库连接池的功能

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。连接复用,通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。

数据库连接池的优点

1. 资源重用

由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。

2. 更快的系统响应速度

数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。

3. 统一的连接管理,避免数据库连接泄漏

在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。

数据库连接池的实现

在eclipse中新建一个项目,在项目中加入commons-dbcp-1.4.jar,commons-pool-1.5.6.jar这两个依赖包,还是使用上面的那个数据库进行测试。代码如下



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

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;


public class BasicDataSourceExample {

    public static void main(String[] args) {

        System.out.println("Setting up data source.");

        //创建数据库连接池

        DataSource dataSource = setupDataSource("jdbc:mysql://127.0.0.1:3306/students");
        System.out.println("Done.");

        //
        // Now, we can use JDBC DataSource as we normally would.
        //
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rset = null;

        try {
            System.out.println("Creating connection.");

            conn = dataSource.getConnection();

            System.out.println("Creating statement.");

            String sql="SELECT *from student";

            stmt = conn.prepareStatement(sql);

            System.out.println("Executing statement.");

            rset = stmt.executeQuery();

         //输出正在使用的数据库连接和空闲的数据库连接   
            printDataSourceStats(dataSource);

            System.out.println("Results:");

            int numcols = rset.getMetaData().getColumnCount();

            while(rset.next()) {
                for(int i=1;i<=numcols;i++) {
                    System.out.print("\t" + rset.getString(i));
                }
                System.out.println("");
            }
        } catch(SQLException e) {
            e.printStackTrace();
        } finally {
            try { if (rset != null) rset.close(); } catch(Exception e) { }
            try { if (stmt != null) stmt.close(); } catch(Exception e) { }
            try { if (conn != null) conn.close(); } catch(Exception e) { }
            try {
                //关闭数据库连接池
                shutdownDataSource(dataSource);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static DataSource setupDataSource(String connectURI) {
        BasicDataSource ds = new BasicDataSource();
        ds.setUsername("hanking");  
        ds.setPassword("hu123");  
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl(connectURI);
        //设置初始化连接数为5
        ds.setInitialSize(5);
        //设置最大连接数为20
        ds.setMaxActive(20);
        //设置最大空闲数为 10
        ds.setMaxIdle(10);
        return ds;
    }

    public static void printDataSourceStats(DataSource ds) {
        BasicDataSource bds = (BasicDataSource) ds;
        System.out.println("NumActive: " + bds.getNumActive());
        System.out.println("NumIdle: " + bds.getNumIdle());
    }

    public static void shutdownDataSource(DataSource ds) throws SQLException {
        BasicDataSource bds = (BasicDataSource) ds;
        bds.close();
        System.out.println("bds closed");
    }
}


//输出结果
/*Setting up data source.
Done.
Creating connection.
Creating statement.
Executing statement.
NumActive: 1
NumIdle: 4
Results:
    1   hust0   20
    2   hust1   24
    3   hust2   25
    4   hust3   23
    5   hanking 20
bds closed
*/

由上面代码可知使用数据库连接池很简单,首先建立一个数据库连接池dataSource ,然后从数据库连接池中获得一个空闲的数据库连接conn = dataSource.getConnection() 后面的步骤就和JDBC中的操作是一样的。上面是最简单的例子,还可以对数据库连接池的各种参数进行设置。比如说数据库连接池最大连接数,最小连接数等等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值