JDBC

  • JDBC是Java数据库连接的缩写,它是一种用于Java编程语言中访问和操作关系型数据库的API

JDBC执行过程

  1. 导入jar包
  2. 注册驱动
  3. 获取数据库连接
  4. 获取执行者对象
  5. 执行sql语句并返回结果
  6. 处理结果
  7. 释放资源

JDBC操作表

  1. 注册驱动
  2. 获取链接
  3. 获取sql对象或者预编译对象
  4. 执行sql语句
  5. 释放资源
package Demo2;

import java.sql.*;

public class jdbc_test {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            String url = "jdbc:mysql://localhost:3306/mydb7";
            String username = "root";
            String passwd = "153425769";
            //2.获取连接数据库
            conn = DriverManager.getConnection(url, username, passwd);
            System.out.println(conn + "数据库连接成功");

            //3.获取sql对象
            statement = conn.createStatement();

            //4.执行sql 添加数据
            statement.executeUpdate("insert into student values (7,'八戒')");

            //修改
            //statement.executeUpdate("update student set name = '阿乐的小屋' where id = 3");

            //删除
            //statement.executeUpdate("delete from student where id =1");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null){
                    statement.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            try {
                if (conn != null) {
                    conn.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

JDBC查询表

  1. 注册驱动
  2. 获取链接
  3. 获取sql对象
  4. 执行sql
  5. 获取列数 处理结果
  6. 释放资源
public class Jdbc_Test02 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/mydb7";
        String username = "root";
        String password = "153425769";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3.获取Sql对象
        Statement statement = conn.createStatement();

        //4.执行Sql
        ResultSet resultSet = statement.executeQuery("select * from student");

        //获取表的列数
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();

        //5.处理结果
        while (resultSet.next()) { //获取每一行的数据
            for (int i = 1; i <= columnCount; i++) {
                //获取每一列的数据
                System.out.print(resultSet.getObject(i) + "\t");
            }
            System.out.println();
        }

        //6.释放资源
        resultSet.close();
        statement.close();
        conn.close();
    }
}

JDBC类的介绍

DriverManager驱动管理对象

  • DriverManager类是Java中的一个类,主要作用是管理JDBC驱动程序。它负责加载和注册JDBC驱动程序,并提供了一些静态方法使得应用程序可以通过该类连接到数据库。
//注册驱动
Class.forName("com.mysql.jdbc.Driver");

//连接数据库
Connection connection = DriverManager.getConnection(url, username, password);

Connection数据库连接对象

  • Connection类是Java中表示数据库连接的核心接口之一。它提供了与数据库建立连接、执行SQL语句、提交事务和关闭连接等关键功能。
  • Connection对象可以实现对关系型数据库(如MySQL、Oracle等)进行操作,从而实现数据的存储、查询、更新和删除等操作。
//连接数据库
Connection connection = DriverManager.getConnection(url, username, password);

//获取Sql对象
Statement statement = connection.createStatement();

//获取预编译执行者对象
PreparedStatement ps = conn.prepareStatement(sql)

Statement执行sql语句的对象

  • Statement类是用于执行SQL语句的接口。它可以与Connection对象一起使用来执行查询和更新操作,并可通过ResultSet对象获取结果集。
  • Statement还提供了批处理和参数绑定等功能,可以提高数据库操作的效率和安全性。总之,Statement类是Java中访问关系型数据库的重要组件之一。
//连接数据库
Connection connection = DriverManager.getConnection(url, username, password);

//获取Sql对象
Statement statement = connection.createStatement();

//执行sql语句
ResultSet resultSet = statement.executeQuery("select * from student");
ResultSet resultSet = statement.executeUpdate("insert into student values(1,'张三')");

ResultSet结果集对象

  • ResultSet类用于表示数据库查询操作的结果集,它提供了一种遍历和访问数据库查询结果的方法。
  • 可以从数据库表中检索行和列数据,并对它们进行处理和操作,例如插入、更新、删除等操作。ResultSet类还提供了许多用于获取和转换不同数据类型的方法,以及用于在结果集中导航、筛选和排序数据的方法。
//连接数据库
Connection connection = DriverManager.getConnection(url, username, password);

//获取Sql对象
Statement statement = connection.createStatement();

//获取表的列数
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();

//5.处理结果
while (resultSet.next()) { //获取每一行的数据
    for (int i = 1; i <= columnCount; i++) {
        //获取每一列的数据
        System.out.print(resultSet.getObject(i) + "\t");
    }
    System.out.println();
}

//5.处理结果集
while (esultSet.next()){
    System.out.println(rs.getInt("id")+"\t"+rs.getString("name"));
}

SQL注入

攻击者通过在用户输入中添加恶意代码来欺骗应用程序执行不安全的SQL语句,从而绕过应用程序的认证和授权机制,并获得对数据库的非法访问权限。

mysql> create database mydb8

mysql> use mydb8

create table user(
uid int primary key auto_increment,
username varchar(20),
password varchar(20));
    
insert into user values(null,"admin","123456");
package Demo2;

import java.sql.*;
import java.util.Scanner;

public class jdbc_test2 {
    public static void main(String[] args) {
        show();
    }


    /**
     * @test SQL注入示例代码
     */
    public static void test(){
        Scanner scan = new Scanner(System.in);

        System.out.println("请输入用户名:");
        String username = scan.nextLine();

        System.out.println("请输入密码:");
        String passwd = scan.nextLine();


        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/mydb8";
            String name = "root";
            String pwd = "153425769";

            // 2.获取连接
            conn = DriverManager.getConnection(url,name,pwd);

            // 3.获取sql对象
            statement = conn.createStatement();

            //aaa 'or' 1=1
            String sql = "select * from user where username = '"+username+"' and password = '"+passwd+"' ";
            resultSet = statement.executeQuery(sql);


            if (resultSet.next()) {
                System.out.println("登录成功");
                System.out.println(sql);
            }else {
                System.out.println("登录失败");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

            try {
                if (statement != null) {
                    statement.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

            try {
                if (conn != null) {
                    conn.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

            try {
                if (scan != null) {
                    scan.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @show 解决sql注入
     */
    public static void show(){
        Scanner scan = new Scanner(System.in);

        System.out.println("请输入用户名:");
        String username = scan.nextLine();

        System.out.println("请输入密码:");
        String passwd = scan.nextLine();


        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/mydb8";
            String name = "root";
            String pwd = "153425769";

            // 2.获取连接
            conn = DriverManager.getConnection(url,name,pwd);

            // 3.获取sql对象
            String sql = "select * from user where username = ? and password = ? ";

            // 4. 创建预编译statement设置sql语句结果
            preparedStatement = conn.prepareStatement(sql);

            // 5. 单独的占位符进行赋值
            preparedStatement.setObject(1,username);
            preparedStatement.setObject(2,passwd);

            // 6. 发送sql语句获取结果
            ResultSet resultSet1 = preparedStatement.executeQuery();

            if (resultSet1.next()) {
                System.out.println("登录成功");
                System.out.println(sql);
            }else {
                System.out.println("登录失败");
            }
        }catch (Exception e){
            e.printStackTrace();

            //s释放资源
        }finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (conn != null) {
                try {
                    conn.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (scan != null) {
                try {
                    scan.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

JDBC工具类封装

新建配置文件db 需要放在src目录下 不然会出现错误

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb8
username=root
password=153425769

工具类

package Demo2;

import java.sql.*;
import java.util.ResourceBundle;

public class DBUtil {

    private  DBUtil(){}

    public static ResourceBundle bundle = ResourceBundle.getBundle("db");

    static {
        try {
            Class.forName(bundle.getString("driver"));
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取数据库连接对象
     * @return 新的连接对象
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        String url = bundle.getString("url");
        String username = bundle.getString("username");
        String password = bundle.getString("password");
        Connection conn = DriverManager.getConnection(url, username, password);
        return  conn;
    }


    /**
     * 释放资源
     * @param conn 连接对象
     * @param statement 数据操作对象
     * @param resultSet 查询结果集
     */
    public static void close(Connection conn, Statement statement,ResultSet resultSet){
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

示例代码

package Demo2;

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

public class jdbc_test3 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            // 1.获取连接
            conn = DBUtil.getConnection();

            // 2.获取预编译的数据库操作对象
            String sql = "select uid from user where username like ?";

            ps = conn.prepareStatement(sql); //防止sql被恶意注入

            // 3. 给 ?传值
            ps.setObject(1,"%a%");

            // 4. 执行sql
            rs = ps.executeQuery();

            // 5. 获取表的列数
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            // 5. 处理结果集
            while (rs.next()) {
                for (int i = 1; i <= columnCount; i++) {
                    //获取每一列的数据
                    System.out.print(rs.getObject(i) + "\t");
                }
                System.out.println();
            }

        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}

JDBC事务

  • 在JDBC中,事务是一组数据库操作,它们要么全部成功执行提交,要么全部失败回滚。
  • 在JDBC中,通过Connection对象来管理事务,使用commit()方法来提交事务,使用rollback()方法来回滚事务。默认情况下,每个SQL语句都会自动提交一个事务,如果需要开启事务需要手动设置Connection对象的autocommit属性为false。
create table account(
name char(20),
balance double(10,2));

insert into account values('张三',20000),('李四',0);

select * from account;
+--------+----------+
| name   | balance  |
+--------+----------+
| 张三   | 20000.00 |
| 李四   |     0.00 |
+--------+----------+

当运行以下案例以后会出现异常情况 在有异常的情况下 金额会发生变动 如下 导致程序不安全

select name as '姓名',balance as '余额' from account;
+--------+----------+
| 姓名   | 余额     |
+--------+----------+
| 张三   | 10000.00 |
| 李四   |     0.00 |
+--------+----------+
package Demo2;

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

public class jdbc_test4 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            // 1. 获取连接  使用工具类
            conn = DBUtil.getConnection();

            // 2.获取预编译的数据库操作对象 做模糊查询
            String sql = "update account set balance = ? where name = ?";
            ps = conn.prepareStatement(sql);

            // 3. 给 ? 传值
            ps.setObject(1,10000);
            ps.setObject(2,"张三");

            int count = ps.executeUpdate(); // 更新成功返回1

            Thread.sleep(5000);
          
            // 4. 出现了异常 异常以后下面不会执行的
            String s = null;
            s.toString();

            ps.setDouble(1,10000);
            ps.setString(2,"李四");
            count += ps.executeUpdate();  //再次更新一条返回 1
            
            System.out.println(count == 2 ? "转账成功" : "转账失败");

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //使用工具类来释放资源
            DBUtil.close(conn,ps,rs);
        }
    }
}

张三有2w需要给李四转1w 在没有使用事务前 若出现异常则金额会减少导致程序非常不安全 在使用事务后会进行回滚 金额不会变少

package Demo2;

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

public class jdbc_test4 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            // 1. 获取连接  使用工具类
            conn = DBUtil.getConnection();

            // 1.1开启事务 关闭自动提交机制
            conn.setAutoCommit(false);

            // 2.获取预编译的数据库操作对象 做模糊查询
            String sql = "update account set balance = ? where name = ?";
            ps = conn.prepareStatement(sql);

            // 3. 给 ? 传值
            ps.setObject(1,10000);
            ps.setObject(2,"张三");

            int count = ps.executeUpdate(); // 更新成功返回1

            Thread.sleep(5000);

            // 4. 出现了异常 异常以后下面不会执行的
            String s = null;
            s.toString();

            ps.setDouble(1,10000);
            ps.setString(2,"李四");
            count += ps.executeUpdate();  //再次更新一条返回 1

            System.out.println(count == 2 ? "转账成功" : "转账失败");
          
          
            // 1.2 程序到这里执行完毕 需要手动提交事务
            conn.commit();

        }catch (Exception e){
            // 1.3 回滚事务
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            //使用工具类来释放资源
            DBUtil.close(conn,ps,rs);
        }
    }
}

JDBC连接池

数据连接池是一个存储在内存中的缓存,它维护着一组数据库连接,可以被应用程序重复使用,以避免频繁地打开和关闭数据库连接。这提高了应用程序的性能并减少了数据库服务器的负担。当应用程序需要与数据库通信时,它可以从连接池中获取一个可用的连接,完成后将其返回给池子中,这样其他的请求就可以重复使用它。

C3P0数据库连接池

C3P0是一个开源的Java数据库连接池,它可以管理应用程序与数据库之间的连接。通过在内存中维护一组预先分配的数据库连接并对这些连接进行有效的重复利用,C3P0可以显著提高应用程序的性能并减少数据库开销。

  1. 在src下新建一个lib文件夹
  2. 导入jar包到lib文件夹中 驱动管理(mysql-connector-j-8.0.33.jar)、cp30(c3p0-0.9.5.5.jar)、mchange-commons-java-0.2.19.jar
  3. 选择jar包 右键 Add as library...
  4. 在src下新建配置文件 c3p0-config.xml或 c3pO-config.properties

c3p0-config.xml

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

    <!--  默认配置  -->
    <default-config>
        <!--   连接参数  -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb7</property>
        <property name="user">root</property>
        <property name="password">153425769</property>
        <!--  连接池参数  -->
        <!-- 初始化申请的连接数量 -->
        <property name="initialPoolSize">5</property>
        <!-- 最大的连接数量 -->
        <property name="maxPoolSize">10</property>
        <!-- 超时时间 -->
        <property name="checkoutTimeout">3000</property>
    </default-config>




    <!--c3p0配置1-->
    <named-config name="c3p0">
        <!--   连接参数  -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb7</property>
        <property name="user">root</property>
        <property name="password">153425769</property>
        <!--  连接池参数  -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">8</property>
        <property name="checkoutTimeout">1000</property>
    </named-config>

</c3p0-config>
package com.blog.dx;

import com.mchange.v2.c3p0.ComboPooledDataSource;

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


public class C3P0 {
    public static void main(String[] args) throws SQLException {
        //获取连接池对象
        DataSource ds = new ComboPooledDataSource();

        // 获取连接对象
        for (int i = 1; i <= 11; i++) {
            // 由于配置文件 有一个最大的连接数量为 10 所以当请求次数超过10次会延迟3秒 最终出现错误
            Connection conn = ds.getConnection();
            System.out.println(i + "conn = " + conn);

            //解决方案如下 当DB使用完了以后会归还回去
            if (i == 5) {
                conn.close();
            }
        }

        System.out.println("==============================");

        //获取配置一的连接对象
        DataSource ds1 = new ComboPooledDataSource("c3p0");

        //获取连接对象
        for (int i = 1; i <= 8; i++) {
            Connection conn1 = ds1.getConnection();
            System.out.println(i + "=" + conn1);
        }

    }

    private static void show() throws SQLException {
        // 获取连接池对象
        DataSource ds = new ComboPooledDataSource();

        // 获取连接对象
        Connection conn = ds.getConnection();

        // 查询sql
        String sql="select * from student";

        //获取预编译对象
        PreparedStatement p = conn.prepareStatement(sql);

        // 执行sql
        ResultSet rs = p.executeQuery();

        // 处理结果集
        while (rs.next()){
            System.out.println(rs.getInt("id")+"\t"+rs.getString("name"));
        }

        //释放资源
        rs.close();
        p.close();
        conn.close();
    }
}

Druid数据库连接池

Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池、高可用、可扩展的数据库连接池。它能够管理数据库连接,提供数据库连接池服务,支持监控和统计等功能,同时也支持水平扩展和分布式部署。Druid数据库连接池广泛应用于各种Java应用程序中,尤其是Web应用程序和分布式系统中。

  1. 在src下新建lib文件夹
  2. 导入jar包到lib文件夹中 (druid-1.1.12.jar)
  3. 选择jar包 右键 Add as library...
  4. 在src下新建配置文件 druid.properties

配置文件信息 druid.properties

driver="com.mysql.jdbc.Driver"
url=jdbc:mysql://localhost:3306/mydb7
username=root
password=153425769
initialSize=10
maxActive=30
minIdle=10
maxWait=2000

基于Druid数据库连接池创建的工具类

package com.blog.dx.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.blog.dx.Druid;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
    private static DataSource ds;

    static {
        try {
            // 加载配置文件
            Properties pro = new Properties();

            // 获取配置文件信息
            pro.load(Druid.class.getClassLoader().getResourceAsStream("druid.properties"));

            // 获取DataSource
            ds = DruidDataSourceFactory.createDataSource(pro);

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 获取连接的方法
     * @return 获取连接
     * @throws SQLException
     */
    public static Connection getconnection() throws SQLException {
        return ds.getConnection();
    }


    /**
     * 增删改的释放资源
     * @param conn
     * @param statement
     */
    public static void close(Statement statement,Connection conn){
        close(conn,statement,null);
    }

    /**
     * 查询的释放资源
     * @param conn 连接对象
     * @param statement 数据库操作对象
     * @param rs 查询结果集
     */
    public static void close(Connection conn, Statement statement,ResultSet rs){
        if (rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取连接池方法
     * @return
     */
    public static DataSource getDataSource() {
        return ds;
    }
}

示例代码

package com.blog.dx;

import com.blog.dx.utils.JdbcUtils;

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

public class Druid {
    public static void main(String[] args)  {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            //1、获取连接
            conn = JdbcUtils.getconnection();

            //2、插入数据
            String sql = "insert into student values(?,?)";

            //3、获取预编译对象
            ps = conn.prepareStatement(sql);

            //4、给 ? 赋值
            ps.setObject(1,17);
            ps.setObject(2,"三国");

            //5、执行sql
            int i = ps.executeUpdate();
            if (i == 1){
                System.out.println("插入成功");
            }

        }catch (Exception e){
            e.printStackTrace();
            System.out.println("插入失败");
        }finally {
            //增删改的释放资源都是这两个  只有查询是有结果集的 这里调用的是重载的方法
            JdbcUtils.close(ps,conn);
        }
    }
}
最后修改:2023 年 05 月 22 日
如果觉得我的文章对你有用,请随意赞赏