JDBC快速入门

news2025/2/26 2:53:45

一、JDBC 概述


  • JDBC(全称:Java Database Connectivity)Java数据库连接,就是使用Java语言操作关系型数据库的一套API。
  • sun公司为Java设计了一套操作所有关系型数据库的API(位于java.sql和javax.sql包下);然后各个数据库厂商去实现这套接口,并提供相应的数据库驱动jar包;这样我们可以使用这套接口(JDBC)编程,其实真正执行的代码是驱动jar包中的实现类。
  • 好处:各个数据库厂商使用相同的接口,这样Java代码不需要针对不同数据库分别开发;然后我们可以随时替换底层数据库,它访问数据库的Java代码基本不变。

在这里插入图片描述


二、JDBC快速入门


1. 开发环境搭建

1、创建一个普通的空项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQx9d6Ru-1669516492142)(JDBC.assets/image-20220718173544643.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XozNJduP-1669516492142)(JDBC.assets/image-20220718173708368.png)]

2、配置JDK版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1P5zM0ot-1669516492143)(JDBC.assets/image-20220718173857728.png)]

3、创建一个子模块(jdbc快速入门的程序在这里面写)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1vebDFa-1669516492147)(JDBC.assets/image-20220718174129296.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2jdOHMA-1669516492148)(JDBC.assets/image-20220718174238449.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lysBxsk6-1669516492149)(JDBC.assets/image-20220718174300017.png)]

4、导入jar包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oxmcqCqS-1669516492149)(JDBC.assets/image-20220718194901077.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NoxJXCh5-1669516492150)(JDBC.assets/image-20220718195342220.png)]


2. 使用JDBC访问数据库

JDBC操作数据库步骤如下:

  • 注册驱动
  • 获取数据库连接对象 (Connection)
  • 定义SQL语句
  • 获取执行SQL的对象 (Statement)
  • 执行SQL
  • 处理集并返回结果(ResultSet)
  • 释放资源

1、创建数据库和表:

CREATE DATABASE `jdbc_test` DEFAULT CHARSET utf8mb4;

CREATE TABLE `account`(
  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'ID',
  `name` varchar(20) NOT NULL COMMENT '姓名',
  `salary` int(11)  COMMENT '薪资',
);

2、编写Java程序:

package com.baidou.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
 * JDBC快速入门
 *
 * @author 白豆五
 * @version 2022/7/18 19:56
 * @since JDK8
 */
public class JDBCDemo {
    public static void main(String[] args) throws Exception {
        // 1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 2、获取连接
        String url = "jdbc:mysql://127.0.0.1:3306/jdbc_test?useSSL=false";
        String user = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, user, password);

        // 3、定义sql语句
        String sql = "insert into account(name,salary) values('王强',10000)";

        // 4、获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();

        // 5、执行sql
        int count = stmt.executeUpdate(sql);

        // 6、处理结果
        // 打印受影响的行数
        System.out.println(count);
        System.out.println(count>0?"插入成功":"插入失败");

        // 7、释放资源
        stmt.close();
        conn.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UrHX2XS4-1669516492150)(JDBC.assets/image-20220718203614831.png)]

控制输出结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XNEX2S7U-1669516492151)(JDBC.assets/image-20220718203124299.png)]

表中的数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hXxuqe5C-1669516492151)(JDBC.assets/image-20220718203225862.png)]


三、JDBC-API详解


1. DriverManager


  • DriverManager:驱动管理类。
  • 作用:注册驱动、获取数据库的连接。

1、注册驱动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7sp0OB2e-1669516492151)(JDBC.assets/image-20220718204431218.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QNMH8yBc-1669516492152)(JDBC.assets/image-20220718204849139.png)]

例如 MySQL数据库驱动类 com.mysql.jdbc.Driver,实现了java.sql.Driver接口。

查看源码发现底层是通过DriverManager.registerDriver()来注册驱动的,这样我们可以通过反射的方式来加载这个数据库驱动类Class.forName(xxx.Driver)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3XFzNB5-1669516492152)(JDBC.assets/image-20220718205216879.png)]

扩展:

  • MySQL5之后的驱动包,可以省略注册驱动 Class.forName("xxx");的步骤。
  • 自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBcg8WWX-1669516492152)(JDBC.assets/image-20220718210415594.png)]


2、获取数据库的连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bH8oLAvT-1669516492152)(JDBC.assets/image-20220718205718991.png)]

getConnection()方法中需要传递3个参数,分别是urluserpassword

1、url

  • url,统一资源定位符(网络中某个资源的绝对地址)。

  • url由哪几个部分组成:协议,ip,port,资源名。

比如我们访问百度的主页:

http://39.156.66.18:80/index.html

http://          通信协议
39.156.66.18     服务器ip地址
80               端口,80是Web服务的默认端口
index.html       是服务器上某个资源名

mysql5.7和8.0驱动中url:

// mysql5.7
// userSSL=false: 禁用安全连接方式,关闭警告问题。  
// useUnicode=true&characterEncoding=utf-8: 字符集编码
url=jdbc:mysql://127.0.0.1:3306/mydatabase?useSSL=false&useUnicode=true&characterEncoding=utf-8

// mysql8.0,
// 需要配置时区:serverTimezone=GMT%2B8 东八区GMT+8
url=jdbc:mysql://127.0.0.1:3306/mydatabase?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8

2、user:用户名

3、password:密码

扩展:

  • 如果连接的是本地MySQL并且端口号是默认的3306,可以简化为:jdbc:mysql:///db
  • 在url中拼接 userSSL=false,禁用安全连接方式,解决警告问题。
    • 例如:jdbc:mysql://127.0.0.1:3306/mydatabase?useSSL=false,如果后面还要拼接参数如要用 & 隔开。

2. Connection


  • Connection:数据库连接对象。
  • 作用:获取执行SQL的对象、管理事务。

1、获取执行SQL的对象

a. 普通执行SQL对象:

Statement createStatement()

b. 预编译的执行SQL对象:(防止SQL注入)

PreparedStatement prepareStatement(String sql)

c. 执行存储过程的对象

CallableStatement prepareCall(String sql)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5CkEbg5-1669516492153)(JDBC.assets/image-20220718214205257.png)]


2、事务管理

作用:保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行。

a. MySQL 事务管理:

开启事务:BEGIN; 或者 START TRANSACTION;
提交事务:COMMIT;
回滚事务:ROLLBACK;

# MySQL默认自动提交事务

b. JDBC事务管理:Connection接口中定义了3个对应的方法:

开启事务: setAutoCommit(boolean autoCommit): true为自动提交事务;false为手动提交事务,即为开启事务。

提交事务:commit()
回滚事务: rollback()

示例:

package com.baidou.jdbc;

import java.sql.*;
/**
 * Connection,事务操作
 *
 * @author 白豆五
 * @version 2022/7/18 21:50
 * @since JDK8
 */
public class JDBC_Connection {
    public static void main(String[] args) throws Exception {
        // 1、注册驱动
        // Class.forName("com.mysql.jdbc.Driver");

        // 2、获取连接
        String url = "jdbc:mysql:///jdbc_test?useSSL=false";
        String user = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, user, password);

        // 3、定义sql语句
        String sql1 = "insert into account(name,salary) values('李四',5000)";
        String sql2 = "insert into account(name,salary) values('王五',4004)";

        // 4、获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();

        try {
            /* 开启事务 */
            conn.setAutoCommit(false); // 手动提交事务
            // 5、执行sql
            int count1 = stmt.executeUpdate(sql1);
            // 6、处理结果
            System.out.println(count1);// 打印受影响的行数

            // 5、执行sql
            int count2 = stmt.executeUpdate(sql2);
            // 6、处理结果
            System.out.println(count2);// 打印受影响的行数
            /*提交事务*/
            conn.commit();
        } catch (Exception e) {
            /*回滚事务*/
            conn.rollback();
            e.printStackTrace();
        }

        // 7、释放资源
        stmt.close();
        conn.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qVdBdtXw-1669516492153)(JDBC.assets/image-20220718220025835.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NtbgdrdP-1669516492153)(JDBC.assets/image-20220718220042542.png)]


3. Statement


  • Statement:执行SQL的对象

  • 作用:执行SQL语句

1、执行DML、DDL语句

int executeUpdate(sql)
返回值: (1)DML语句影响的行数
       (2)DDL语句执行后,执行成功也可能返回0

2、执行DQL语句

ResultSet executeQuery(sql)
返回值: ResultSet结果集对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTPKCRYn-1669516492154)(JDBC.assets/image-20220719070429457.png)]


4. ResultSet


  • ResultSet:结果集对象
  • 作用:封装了DQL查询语句的结果

获取查询结果:

// next功能: (1)将游标从当前位置向下移动一行(2)判断当前行是否有效
boolean next() 
返回值:   true:有效行,当前行有数据 
	  	 false:	无效行,当前行无数据 
xxx getXxx(参数) //获取指定类型数据
  xxx是数据类型,如 int getInt(参数)String getString(参数) 
  参数(重载方法):  int: 列的编号,从1开始
      	      String: 列的名称

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GnYKAtmf-1669516492154)(JDBC.assets/image-20220719072523534.png)]

ResultSet使用步骤:

  • 游标向下移动一行,并判断该行否有数据:next()
  • 获取数据: getXxx(参数)
// 通过循环遍历结果集对象
while(rs.next()){ // rs.next()将游标从当前位置向下移动一行并判断当前行是否有效
    // 获取数据
    rs.getXxx(参数);
}

示例:

/**
 * ResultSet的使用
 *
 * @author 白豆五
 * @version 2022/7/19 7:42
 * @since JDK8
 */
public class JDBC_ResultSet {
    public static void main(String[] args) throws Exception {
        // 1、注册驱动
        // Class.forName("com.mysql.jdbc.Driver");

        // 2、获取连接
        String url = "jdbc:mysql:///jdbc_test?useSSL=false";
        String user = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, user, password);

        // 3、定义sql语句
        String sql = "select * from account";

        // 4、获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();

        // 5、执行sql并返回结果集
        ResultSet rs = stmt.executeQuery(sql);

        // 6、处理结果
        while (rs.next()) { // 通过循环取出ResultSet中的所有数据
            System.out.print("id:" + rs.getInt("id") + "\t");
            System.out.print("name:" + rs.getString("name") + "\t");
            System.out.print("salary:" + rs.getInt("salary") + "\t");
            System.out.println();
        }
    
       /*
            // 进行读取一次 判断是否有数据
            if (rs.next()) {
                System.out.println("id:" + rs.getInt(1) );
            }
        */
        

        // 7、释放资源
        rs.close();
        stmt.close();
        conn.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GwzQqA36-1669516492155)(JDBC.assets/image-20220719075752992.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9k9kjNx-1669516492155)(JDBC.assets/image-20220719075603999.png)]


5. PreparedStatement


5.1 SQL注入问题

通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

示例:模拟sql注入问题

数据库SQL:

CREATE TABLE `user`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `username` varchar(20) NOT NULL COMMENT '用户名',
  `password` varchar(20) NOT NULL COMMENT '密码',
  PRIMARY KEY (`id`)
);

insert into user(username,password) values('张三','123');

db.properties:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbc_test?useSSL=false&useUniCode=true&characterEncoding=utf-8
user=root
password=123456

Java程序:

/**
 * 模拟SQL注入问题
 *
 * @author 白豆五
 * @version 2022/7/19 8:14
 * @since JDK8
 */
public class JDBC_SQLinjection {
    /*
        功能:实现用户登录
        需求:接收用户输入的用户名和密码;
            验证用户名和密码;
            返回给用户提示信息
     */
    public static void main(String[] args) {
        Map<String, String> userLoginInfo = initUI();
        boolean loginSuccess  = login(userLoginInfo);
        System.out.println(loginSuccess?"登录成功":"用户名或密码有误");

    }

    /**
     * @param userLoginInfo 用户登录信息
     * @return false表示失败, true表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        // 定义一个红绿灯表示用户登录和失败
        boolean loginSuccess = false;

        try {
            // 创建配置类对象
            Properties properties = new Properties();
            // 通过类加载器获取类路径下的db.properties这个资源
            InputStream is = ClassLoader.getSystemResourceAsStream("db.properties");
            // 加载资源到配置类中
            properties.load(is);
            // 关闭流
            is.close();

            // 通过属性获取配置文件里的书
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");


            // 注册驱动
            Class.forName(driver);
            // 获取连接
            conn = DriverManager.getConnection(url, user, password);
            // 获取数据库操作对象
            stmt = conn.createStatement();
            // 定义sql
            String sql = "select * from user where username='" + userLoginInfo.get("username")
                    + "' and password='" + userLoginInfo.get("password") + "'";

            // 执行sql
            rs = stmt.executeQuery(sql);

            // 如果结果集中有数据表示登录成功
            if (rs.next()) {
                loginSuccess = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 是否资源
            close(rs,stmt,conn);
        }
        return loginSuccess;

    }

    /**
     * 初始化界面
     *
     * @return 用户名和密码等信息
     */
    public static Map<String, String> initUI() {
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String username = sc.nextLine();
        System.out.println("密码:");
        String password = sc.nextLine();
        // 定义一个Map,存储用户信息
        Map<String, String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("username", username);
        userLoginInfo.put("password", password);
        return userLoginInfo;
    }

    /**
     * 释放资源
     *
     * @param rs   结果集对象
     * @param stmt 执行sql的对象
     * @param conn 数据库连接对象
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u8V33nsK-1669516492155)(JDBC.assets/image-20220719085344240.png)]

分析:只要用户提供的信息不参与SQL语句的编译过程,问题就解决了。

解决方案:

1、可以利用正则表达式来防止用户输入一些非法字符,例如(‘=’,‘or’等)

2、将Statment换成PreparedStatement(预编译的数据库操作对象);

PreparedStatement的原理:首先将SQL语句传入PreparedStatement中,然后把传入到SQL语句中的参数用?(占位符)来代替,然后该SQL语句会进行编译(耗时操作),之后将获取的参数通过PreparedStatement中的set()方法传入编译后的SQL语句中,这样SQL语句就会先被编译再进行传值,最后在执行一下,就解决了SQL注入问题。

示例:使用PreparedStatement解决SQL注入问题

/**
 * 使用PreparedStatement解决SQL注入问题
 *
 * @author 白豆五
 * @version 2022/7/19 8:14
 * @since JDK8
 */
public class JDBC_SQLinjection2 {
    /*
        功能:实现用户登录
        需求:接收用户输入的用户名和密码;
            验证用户名和密码;
            返回给用户提示信息
     */
    public static void main(String[] args) {
        Map<String, String> userLoginInfo = initUI();
        boolean loginSuccess  = login(userLoginInfo);
        System.out.println(loginSuccess?"登录成功":"用户名或密码有误");

    }

    /**
     * @param userLoginInfo 用户登录信息
     * @return false表示失败, true表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        // 定义一个红绿灯表示用户登录和失败
        boolean loginSuccess = false;

        try {
            // 创建配置类对象
            Properties properties = new Properties();
            // 通过类加载器获取类路径下的db.properties这个资源
            InputStream is = ClassLoader.getSystemResourceAsStream("db.properties");
            // 加载资源到配置类中
            properties.load(is);
            // 关闭流
            is.close();

            // 通过属性获取配置文件里的书
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");


            // 注册驱动
            Class.forName(driver);
            // 获取连接
            conn = DriverManager.getConnection(url, user, password);

            // 定义sql
            String sql = "select * from user where username=? and password=?";
            // 获取数据库操作对象
            ps = conn.prepareStatement(sql); // 先编译后传值
            // 给占位符传值
            ps.setString(1,userLoginInfo.get("username"));
            ps.setString(2,userLoginInfo.get("password"));


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

            // 如果结果集中有数据表示登录成功
            if (rs.next()) {
                loginSuccess = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 是否资源
            close(rs,ps,conn);
        }
        return loginSuccess;

    }

    /**
     * 初始化界面
     *
     * @return 用户名和密码等信息
     */
    public static Map<String, String> initUI() {
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String username = sc.nextLine();
        System.out.println("密码:");
        String password = sc.nextLine();
        // 定义一个Map,存储用户信息
        Map<String, String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("username", username);
        userLoginInfo.put("password", password);
        return userLoginInfo;
    }

    /**
     * 释放资源
     *
     * @param rs   结果集对象
     * @param ps 执行sql的预编译对象
     * @param conn 数据库连接对象
     */
    public static void close(ResultSet rs, PreparedStatement ps, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5iS3g9xD-1669516492156)(JDBC.assets/image-20220719090611974.png)]


5.2 PreparedStatement

  • PreparedStatement:预编译的SQL执行对象。

  • 作用:预编译SQL并执行SQL语句

1、获取PreparedStatement 对象

// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ?";

//通过Connection对象获取,并传入对应的sql语句,然后进行预编译操作
PreparedStatement pstmt = conn.prepareStatement(sql);

2、设置参数值

ps.setXxx(参数1,参数2) //给?赋值 
    Xxx:数据类型; 如 ps.setInt (参数1,参数2)、ps.setString (参数1,参数2)
	参数:
		参数1: ?的位置编号,从1开始
        参数2: ?的值

3、执行SQL

ps.ecuteUpdate(); // 不需要再传递sql

5.3 PreparedStatement的CRDU操作

import org.junit.Test;

import java.sql.*;

/**
 * @ClassName: JDBCTest05
 * @Description: 使用PreparedStatement完成增删改查功能
 * @Author: baidou
 * @Date: 2022/2/2 09:06
 * Version: 1.0
 */
public class JDBCTest05 {

    Connection conn;
    PreparedStatement pstmt;

    /**
     * 获取数据库连接对象
     *
     * @return connection
     * @throws SQLException, ClassNotFoundException
     */
    public static Connection getConnection() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest?useSSL=false&useUniCode=true&characterEncoding=utf-8", "root", "123456");
        return connection;
    }

    /**
     * 获取数据库的预处理对象
     *
     * @param connection 数据库连接对象
     * @param sql        我们传入的sql语句
     * @param obj        占位符的参数
     * @return
     * @throws SQLException
     */
    public static PreparedStatement getPreparedStatement(Connection connection, String sql, Object[] obj) throws SQLException {
        PreparedStatement pstmt = connection.prepareStatement(sql);
        if (obj != null) {
            for (int i = 0; i < obj.length; i++) {
                pstmt.setObject(i + 1, obj[i]);
            }
        }
        return pstmt;
    }

    /**
     * 释放资源
     *
     * @param rs
     * @param ps
     * @param conn
     * @throws SQLException
     */
    public static void close(ResultSet rs, PreparedStatement ps, Connection conn) throws SQLException {
        if (rs != null) {
            rs.close();
        }
        if (ps != null) {
            ps.close();
        }
        if (conn != null) {
            conn.close();
        }

    }

    @Test
    public void add() throws SQLException, ClassNotFoundException {
        conn = JDBCTest05.getConnection();
        String sql = "insert into user(name,password,vocation) values(?,?,?)";
        Object[] obj = {"大灰狼", "2333", "战士"};
        pstmt = JDBCTest05.getPreparedStatement(conn, sql, obj);
        int count = pstmt.executeUpdate();
        System.out.println(count > 0 ? "添加成功" : "添加失败");
        JDBCTest05.close(null, pstmt, conn);
    }

    @Test
    public void delete() throws SQLException, ClassNotFoundException {
        conn = JDBCTest05.getConnection();
        String sql = "delete from user where id=?";
        pstmt = JDBCTest05.getPreparedStatement(conn, sql, new Object[]{4});
        int count = pstmt.executeUpdate();
        System.out.println(count > 0 ? "删除成功" : "删除失败");
        JDBCTest05.close(null, pstmt, conn);
    }

    @Test
    public void update() throws SQLException, ClassNotFoundException {
        conn = JDBCTest05.getConnection();
        String sql = "update user set name=?,password=? where name=?";
        Object[] obj = {"铠甲勇士", "0000", "zhangsan"};
        pstmt = JDBCTest05.getPreparedStatement(conn, sql, obj);
        int count = pstmt.executeUpdate();
        System.out.println(count > 0 ? "修改成功" : "修改失败");
        JDBCTest05.close(null, pstmt, conn);
    }

    @Test
    public void list() throws SQLException, ClassNotFoundException {
        conn = JDBCTest05.getConnection();
        String sql = "select * from user";
        pstmt = JDBCTest05.getPreparedStatement(conn, sql, null);
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            System.out.println("id:" + rs.getObject(1) + "\t用户名:" + rs.getObject(2) + "\t密码:" + rs.getObject(3) + "\t职业:" + rs.getObject(4));
        }
        JDBCTest05.close(rs, pstmt, conn);
    }
}

四、数据库连接池

1. 数据库连接池简介

  • 数据库连接池,它就是个容器,用来负责分配、管理数据库连接(Connection)。
  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
  • 释放空闲时间超过最大空闲时间的数据库连接,避免因为没有释放数据库连接而引起的数据库连接遗漏问题。
  • 使用数据库连接池的好处:
    • 资源重用
    • 提升系统响应速度
    • 避免数据连接遗漏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWeTUphG-1669516492156)(JDBC.assets/image-20220719095350923.png)]

数据库连接池的实现

1、标准接口:javax.sql.DataSource

  • 官方(SUN公司)为数据库连接池提供了一套标准接口,由第三方组织实现此接口。
  • 核心方法:Connection getConnection(),获取连接。

2、常见的数据库连接池:

  • DBCP
  • C3P0
  • Druid
  • HikariCP,SpringBoot内置的连接池。

2. Durid

  • Druid(德鲁伊),是阿里开源的数据库连接池项目(文少)。
  • 项目地址:https://github.com/alibaba/druid
  • 优点:功能强大、性能优秀、是Java语言最好的数据库连接池之一。

Druid使用步骤:

1、导入jar包 druid-1.1.12.jar

2、定义配置文件

3、加载配置文件

4、获取数据库连接池对象

5、获取连接


druid.properties:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc_test?useSSL=false&useServerPrepStmts=true
username=root
password=123456
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
package com.baidou.druid;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * Druid的使用
 *
 * @author 白豆五
 * @version 2022/7/19 10:28
 * @since JDK8
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {
        //加载配置文件
        Properties prop = new Properties();
        // System.out.println(System.getProperty("user.dir"));
        prop.load(new FileInputStream("jdbc_demo2/src/druid.properties"));
        // 获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        // 获取数据库连接
        Connection conn = dataSource.getConnection();
        System.out.println("conn = " + conn);
        conn.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BjeTZjcH-1669516492157)(JDBC.assets/image-20220719111306421.png)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端css样式小知识点(大杂烩)

文章目录一、前言二、图文实操讲解1、使用微信开发者工具&#xff0c;如何整洁代码的快捷键2、微信小程序中rpx和px有什么区别3、css中flex设置为1是什么意思4、opacity:1 的作用是什么效果图&#xff1a;5、css样式如何实现半圆等效果图&#xff1a;6、css样式如何将图片置于元…

Elasticsearch实用教程---从门->进阶->精通

第1章 Elasticsearch概述 Elasticsearch 是什么 The Elastic Stack, 包括 Elasticsearch、 Kibana、 Beats 和 Logstash&#xff08;也称为 ELK Stack&#xff09;。能够安全可靠地获取任何来源、任何格式的数据&#xff0c;然后实时地对数据进行搜索、分析和可视化。 Elati…

【滤波器设计】微波带低通高通带通滤波器设计【含Matlab源码 2217期】

⛄一、数字滤波器设计简介 1 设计原理 1.1 滤波器概念 1.2 数字滤波器的系统函数和差分方程 1.3 数字滤波器结构的表示 1.4 数字滤波器的分类 2.1 IIR滤波器与FIR滤波器的分析比较 2.2 FIR滤波器的原理 3 FIR滤波器的仿真步骤 ⛄二、部分源代码 function …

工作中如何规范定义Java常量

目录 1.【强制】不允许任何魔法值&#xff08;即未经预先定义的常量&#xff09;直接出现在代码中。 2.【强制】long 或 Long 赋值时&#xff0c;数值后使用大写 L&#xff0c;不能是小写 l&#xff0c;小写容易跟数字混淆&#xff0c;造成误解。 3.【强制】浮点数类型的数值…

verilog练习——组合逻辑

目录 组合逻辑 VL11 4位数值比较器电路 VL12 4bit超前进位加法器电路 VL13 优先编码器电路① VL14 用优先编码器①实现键盘编码电路 VL15 优先编码器Ⅰ VL16 使用8线-3线优先编码器Ⅰ VL17 用3-8译码器实现全减器 VL18 实现3-8译码器① VL19 使用3-8译码器①实现逻辑函…

【架构师必知必会系列】系统架构设计需要知道的5大精要(5 System Design fundamentals)...

无论是在大厂还是初创公司&#xff0c;技术产品经理 (TPM)都需要具备系统设计的基础知识。从历史上看&#xff0c;系统设计基础知识通常是软件工程师在面试时的要求&#xff0c;而 TPM 不受此期望的约束。然而&#xff0c;现在趋势正在发生变化。作为 TPM&#xff0c;您需要在面…

1.1 测控系统对测控电路的要求、测控电路中的重要指标

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

【Redis-06】从源码层面深入理解Redis主从复制的实现原理

在Redis中&#xff0c;可以通过slaveof命令或者设置slaveof选项实现两台Redis服务器的主从复制&#xff0c;比如我们有两个Redis机器&#xff0c;地址分别是 127.0.0.1:6379 和 127.0.0.1:6380&#xff0c;现在我们在前者上面执行&#xff1a; 127.0.0.1:6379 > SLAVEOF 12…

PyTorch学习笔记-Torchvision数据集使用方法

Torchvision 官方文档 Torchvision 中的 torchvision.datasets 就是 Torchvision 提供的标准数据集&#xff0c;其中有以下内容&#xff1a; 我们以 CIFAR 为例&#xff0c;该数据集包括了60000张32*32像素的图像&#xff0c;总共有10个类别&#xff0c;每个类别有6000张图像&a…

[附源码]Python计算机毕业设计高校创新学分申报管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

数据可视化:四种关系图数据可视化的效果对比!

python关系图的可视化主要就是用来分析一堆数据中&#xff0c;每一条数据的节点之间的连接关系从而更好的分析出人物或其他场景中存在的关联关系。 这里使用的是networkx的python非标准库来测试效果展示&#xff0c;通过模拟出一组DataFrame数据实现四种关系图可视化。 其余还…

【网页设计】期末大作业html+css(音乐网站)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Ubuntu 20.04.5安装无线网卡RTL8821CE驱动

陈拓 2022/11/26-2022/11/26 准备工作 查看网络设备WiFi设备未驱动。 查看WiFi设备型号 lspci | grep -i wireless 或 lspci -nn | grep -i net 设备代号10ec:c821可以用来查询验证WiFi设备型号。 在网站PCI devices查询无线设备型号&#xff1a; Wifi设备型号&#xff1a…

“面向大厂编程”一线互联网公司面试究竟问什么?打入内部针对性学习!

今年来&#xff0c;由于寒冬影响&#xff0c;各大公司都缩减了HC&#xff0c;甚至是采取了“裁员”措施&#xff0c;在这样的大环境之下&#xff0c;想要获得一份更好的工作&#xff0c;必然需要付出更多的努力。 但在最近的一份工作报告中显示&#xff0c;开发者的热门选择依…

Mysql语法四:索引查找和了解何为事务

目录 1.索引 1.1&#xff1a;使用 1.1.1&#xff1a;查看索引 1.2.2&#xff1a;创建索引 1.1.3&#xff1a;删除索引 1.2&#xff1a;索引查询的原理 1.2.1&#xff1a;何为 B树 2.事务 2.1:特性 2.1.1&#xff1a;原子性 2.1.2&#xff1a;一致性 2.1.3&#xff1…

(附源码)计算机毕业设计Java坝上长尾鸡养殖管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven Vue 等等组成&#xff0c;B/…

博易大师期货程序化交易软件,期货买卖点提示量化分析系统幅图指标公式,期货波段进场点信号

期货指标公式不是交易的圣杯&#xff0c;也不是期货亏损后的救命稻草。请理性运用指标公式&#xff0c;独立决策&#xff0c;盈亏自负。期货市场具有不确定性和不可预测性的&#xff0c;请正常对待和使用指标公式! 期货指标公式是通过数学逻辑角度计算而来&#xff0c;仅是期货…

【Kotlin 协程】协程底层实现 ④ ( 结构化并发 | viewModelScope 作用域示例 )

文章目录一、viewModelScope 作用域作用二、viewModelScope 作用域示例常见的 CoroutineScope 协程作用域 : GlobalScope : 该作用域是 进程级别的 , 与应用进程同级 , 即使 Activity 被销毁 , 协程任务也可以继续执行 ;MainScope : 该 作用域仅在 Activty 中 , 如果 Activity…

VuePress构建一个文档管理网站

序言 目前无论笔记还是项目文档&#xff0c;大部分我都会通过 Markdown来记录&#xff0c;并且大部分文档写完都只存在自己电脑上&#xff0c;每次查找起来都需要耗费一些时间 自己的写的一部分技术教程由于初次记录时了解知识不多&#xff0c;内容存在偏差或考虑不全面&…

数仓搭建-ODS层

数仓搭建-ODS层 1&#xff09;保持数据原貌不做任何修改&#xff0c;起到备份数据的作用。 2&#xff09;数据采用LZO压缩&#xff0c;减少磁盘存储空间。100G数据可以压缩到10G以内。 3&#xff09;创建分区表&#xff0c;防止后续的全表扫描&#xff0c;在企业开发中大量使用…