Mysql&JDBC(详细版)

Mysql&JDBC

在学习JDBC操作前,最好复习一下Mysql的操作,以免学着前面的,忘记后面的,最后什么都学不到。
在博客的最后我给出了一个小练习,最好看完这个博客,你感觉自己都会了,就去把那个小练习写了,不要觉得浪费时间;这个练习考验了你封装的思想。

Mysql-复习

DDL

(Data Definition Language)是用于定义和管理数据库结构的SQL语言的一部分。MySQL支持许多DDL命令,这些命令用于创建、修改和删除数据库对象(例如表、索引、视图等)。以下是一些常用的MySQL DDL命令:

CREATE TABLE: 用于创建表格。例如:

CREATE TABLE employees (
    id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    birth_date DATE
);
ALTER TABLE: 用于修改现有表的结构。例如,添加列:
ALTER TABLE employees
ADD COLUMN email VARCHAR(100);

DROP TABLE: 用于删除表。例如:
DROP TABLE employees;

CREATE INDEX: 用于创建索引,以提高检索效率。例如:
CREATE INDEX idx_last_name ON employees (last_name);

DROP INDEX: 用于删除索引。例如:
DROP INDEX idx_last_name ON employees;

CREATE DATABASE: 用于创建数据库。例如:
CREATE DATABASE mydatabase;

DROP DATABASE: 用于删除数据库。例如:
DROP DATABASE mydatabase;

USE: 用于选择要使用的数据库。例如:
USE mydatabase;

DML

DML(Data Manipulation Language)是SQL的一部分,用于处理数据库中的数据。DML命令用于查询、插入、更新和删除数据库中的数据。以下是一些常用的MySQL DML命令:

SELECT: 用于查询数据库中的数据。例如:
SELECT * FROM employees WHERE department = 'IT';

INSERT INTO: 用于向表中插入新的行。例如:
INSERT INTO employees (first_name, last_name, birth_date)
VALUES ('John', 'Doe', '1990-01-15');

UPDATE: 用于更新表中的数据。例如:
UPDATE employees
SET department = 'HR'
WHERE last_name = 'Doe';

DELETE: 用于删除表中的数据。例如:
DELETE FROM employees
WHERE last_name = 'Doe';

INSERT INTO ... SELECT: 将查询结果插入到另一个表中。例如:
INSERT INTO new_employees (first_name, last_name, birth_date)
SELECT first_name, last_name, birth_date
FROM old_employees
WHERE department = 'IT';

DCL

DCL(Data Control Language)是SQL的一部分,用于授予或撤销访问数据库对象的权限。DCL命令用于管理数据库的安全性和访问控制。以下是两个主要的MySQL DCL命令:

GRANT: 用于授予用户或用户组对数据库对象(如表、视图)的特定权限。例如:
GRANT SELECT, INSERT ON employees TO 'user1'@'localhost';
上述命令授予了'user1'@'localhost'用户对employees表的SELECT和INSERT权限。

REVOKE: 用于撤销用户或用户组对数据库对象的权限。例如:
REVOKE SELECT ON employees FROM 'user1'@'localhost';
上述命令撤销了'user1'@'localhost'用户对employees表的SELECT权限。

DQL

DQL(Data Query Language)是SQL的一部分,专门用于执行查询操作以检索数据库中的数据。DQL命令的主要目的是从数据库中选择数据,而不对数据进行更改。以下是一个主要的MySQL DQL命令:

SELECT: 用于从一个或多个表中选择数据。例如:
SELECT first_name, last_name, birth_date
FROM employees
WHERE department = 'IT';
上述命令选择了employees表中部门为'IT'的员工的姓名和出生日期。

JDBC

什么是JDBC?

JDBC(Java Database Connectivity)是Java的数据库连接API,用于连接和操作关系型数据库,如MySQL、Oracle等。它包括驱动管理器(DriverManager)、驱动程序(Driver)、连接(Connection)、语句(Statement)、结果集(ResultSet)等组件,提供了统一的方式让Java应用程序与不同数据库交互。

在学习JDBC前的准备

安装Mysql数据库,和下载JDBC驱动包

JDBC连接数据库的流程-查询

public class JDBCConnection {
    /**
     * 数据库连接的信息,这里我使用了final,主要是这些是常量,我不想这些值改变。
     * 在学到后面,这些有关数据连接的信息一般存放在Jdbc.properties文件下
     */
    private final String URL = "jdbc:mysql://localhost:3306/learn";
    private final String USER = "learn";
    private final String PASSWORD = "888888";
    private final String DRIVER = "com.mysql.cj.jdbc.Driver";
}
//数据库查询数据
    public void selectShow() throws ClassNotFoundException, SQLException {
        //加载数据库驱动程序
        Class.forName(DRIVER);

        /**
         * 注册驱动,建立数据库连接
         * 其中的三个参数的作用
         *      url:jdbc:mysql://localhost:3306/learn
         *          jdbc:mysql:jdbc连接Mysql数据库的协议前缀
         *          localhost:服务器的主机名或ip地址
         *          3306:Mysql数据库服务端的默认端口号
         *          learn:数据库名
         *      user:数据库的用户名
         *      password:对应用户的密码
         */
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);

        /**
         * 创建statement对象
         * 这个对象有两个,一个是createStatement(),还有一个是prepareStatement()
         */
        Statement statement = connection.createStatement();

        //要执行的sql语句
        String selectSql ="SELECT * FROM user";

        /**
         * 执行sql语句
         *      这里使用的是executeQuery(String sql)方法,返回的是一个迭代器,
         *      使用resultSet.next();
         *      statement.executeUpdate(selectSql);
         */
        ResultSet resultSet = statement.executeQuery(selectSql);

        while(resultSet.next()){
            //通过列名或索引获取数据
            int id = resultSet.getInt(1);
            String username = resultSet.getString(2);
            String password = resultSet.getString(3);

            //打印数据
            System.out.println("id:" + id + "&" + "username:" + username +"&" + "password:" + password);
        }

        //关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }

prepareStatement()&createStatement()-添加

让我们来看看两者的区别

createStatement()

  • 使用 createStatement() 方法创建的 Statement 对象用于执行简单的 SQL 语句,这些语句在执行时不包含参数。例如,执行一条简单的 SELECT 语句或更新语句。

  • 不支持参数绑定,因此对于包含变量的 SQL 语句,你需要手动拼接字符串。这可能导致安全性问题(例如 SQL 注入)。

  • Statement statement = connection.createStatement();
    String sql = "SELECT * FROM user WHERE username = 'zhangsan'";
    ResultSet resultSet = statement.executeQuery(sql);
    

prepareStatement()

  • 使用 prepareStatement() 方法创建的 PreparedStatement 对象用于执行预编译的 SQL 语句,这些语句在执行时可以包含参数。这种方式更安全,能够防止 SQL 注入攻击。

  • 支持参数绑定,可以通过 setXXX() 方法为 SQL 语句的参数传递值。这使得 SQL 语句的执行更加灵活和可维护。

  • String sql = "SELECT * FROM user WHERE username = ?";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setString(1, "zhangsan");
    ResultSet resultSet = preparedStatement.executeQuery();
    
    //数据库添加数据
    public void addShow() throws ClassNotFoundException, SQLException {
        //加载驱动
        Class.forName(DRIVER);
        //注册驱动
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        //预编译的sql语句,?是一个占位符
        String addSql = "INSERT INTO user(username,password) VALUES(?,?);";
        //获取预编译对象
        PreparedStatement preparedStatement = connection.prepareStatement(addSql);
        //设置占位符的参数值(可以通过索引或参数名)
        preparedStatement.setString(1,"test");
        preparedStatement.setString(2,"444444");
        /**
         * 返回sql语句执行的结果(sql语句执行的影响行数)
         * 在执行删除sql语句的时候,其返回的值的就不可靠了
         *
         */
        int executeUpdate = preparedStatement.executeUpdate();
        //判断sql语句的执行情况
        if (executeUpdate > 0){
            System.out.println("success!");
        }else{
            System.out.println("error!");
        }

        //关闭资源
        preparedStatement.close();
        connection.close();
    }

数据库修改操作

//数据库修改数据
public void updateShow() throws ClassNotFoundException, SQLException {
    //加载驱动
    Class.forName(DRIVER);

    //获取连接
    Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);

    //updateSql语句的编写
    String updateSql = "UPDATE user SET password = ? WHERE id = ?";

    //获取预编译对象
    PreparedStatement preparedStatement = connection.prepareStatement(updateSql);

    //参数赋值
    preparedStatement.setString(1,"testPassword");
    preparedStatement.setInt(2,4);

    //开始执行,获取结果
    int executeUpdate = preparedStatement.executeUpdate();

    //解析结果
    if (executeUpdate != 0){
        System.out.println("success!");
    }else{
        System.out.println("error!");
    }

    //关闭资源
    preparedStatement.close();
    connection.close();
}

数据库删除操作

//数据库删除数据
public void deleteShow() throws ClassNotFoundException, SQLException {
    //加载驱动
    Class.forName(DRIVER);
    //获取连接
    Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
    //deleteShow语句编写
    String deleteSql = "DELETE FROM user WHERE id = ?";
    //获取预编译对象
    PreparedStatement preparedStatement = connection.prepareStatement(deleteSql);
    //设置参数
    preparedStatement.setInt(1,4);
    //执行sql语句,返回结果
    int executeUpdate = preparedStatement.executeUpdate();
    //解析结果
    if (executeUpdate != 0){
        System.out.println("success!");
    }else{
        System.out.println("error!");
    }
}

主键回显-

一般都是在数据添加的时候会有要求,要回显主键

//数据库添加数据
public void addShow() throws ClassNotFoundException, SQLException {
    //加载驱动
    Class.forName(DRIVER);
    //注册驱动
    Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
    //预编译的sql语句,?是一个占位符
    String addSql = "INSERT INTO user(username,password) VALUES(?,?);";
    //获取预编译对象
    PreparedStatement preparedStatement = connection.prepareStatement(addSql,Statement.RETURN_GENERATED_KEYS);
    //设置占位符的参数值(可以通过索引或参数名)
    preparedStatement.setString(1,"test");
    preparedStatement.setString(2,"444444");
    /**
     * 返回sql语句执行的结果(sql语句执行的影响行数)
     * 在执行删除sql语句的时候,其返回的值的就不可靠了
     *
     */
    int executeUpdate = preparedStatement.executeUpdate();
    //判断sql语句的执行情况
    if (executeUpdate > 0){
        System.out.println("success!");
        ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
        generatedKeys.next();
        int id = generatedKeys.getInt(1);
        System.out.println("添加user返回的编号id:" + id);
    }else{
        System.out.println("error!");
    }

    //关闭资源
    preparedStatement.close();
    connection.close();
}

多次添加数据优化

注意在对于addBatch()sql语句的添加,就是添加(domei,domei)到原来sql语句values的后面

本质就是添加数据VALUES(?,?),(?,?),(?,?),(?,?),(?,?)…

想使用这个功能,需要在url后面添加这个rewriteBatchedStatement=true

开启多值写入的功能

//添加缓冲区(多次添加数据)
public void bufferShow() throws SQLException, ClassNotFoundException {
    //加载驱动
    Class.forName(DRIVER);

    //注册驱动,获取连接
    Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);

    //编写sql语句
    String insertSql = "INSERT INTO user(username,password) VALUES(?,?)";

    //获取预编译器
    PreparedStatement preparedStatement = connection.prepareStatement(insertSql);

    //记录开始时间
    long start = System.currentTimeMillis();

    //添加1000条数据
    for (int i = 0; i < 1000; i++) {
        //设置参数
        preparedStatement.setString(1, "dome" + i);
        preparedStatement.setString(2,"dome" + i);

        //sql语句的添加
        preparedStatement.addBatch();
    }
    preparedStatement.executeBatch();
    //记录结束时间
    long end = System.currentTimeMillis();

    //输出用时
    System.out.println("添加10000条数据一共用时:"+ (end - start) + "毫秒");

    //关闭资源
    preparedStatement.close();
    connection.close();
}

事务

/**
 *事务回滚(删除数据库里数据的时候,如果代码执行错误的话,可以将原来执行代码的效果取消)
 * 案例:在转账的时候,如果对方用户不存在,你原来进行转账执行的sql效果就要取消,这个时候就需要回滚操作
 */

public void affairShow() throws SQLException, ClassNotFoundException {
    //加载驱动
    Class.forName(DRIVER);

    //注册驱动,获取连接
    Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);

    //编写sql语句
    String deleteSql =  "DELETE FROM user WHERE id = ?";

    try{
        //关闭自动提交事务
        connection.setAutoCommit(false);

        //获取编译器对象
        PreparedStatement preparedStatement = connection.prepareStatement(deleteSql);

        //参数赋值
        preparedStatement.setInt(1,41001);

        //发送sql语句(执行sql语句)
        int executeUpdate = preparedStatement.executeUpdate();

        if (executeUpdate > 0){
            System.out.println("success!");
        }else {
            System.out.println("error!");
        }

        //关闭资源
        preparedStatement.close();
        connection.close();

    }catch (Exception e){
        //有异常,就会进行回滚
        connection.rollback();
    }
}

连接池

变量的声明

private final String URL = "jdbc:mysql://localhost:3306/learn";
private final String USER = "learn";
private final String PASSWORD = "888888";
private final String DRIVER = "com.mysql.cj.jdbc.Driver";

显性创建连接池

public void druidShow1() throws SQLException {
    //获取连接池对象
    DruidDataSource dataSource = new DruidDataSource();

    //设置参数
    dataSource.setDriverClassName(DRIVER);//加载驱动的参数
    dataSource.setUrl(URL);//注册驱动的参数
    dataSource.setUsername(USER);//注册驱动的参数
    dataSource.setPassword(PASSWORD);//注册驱动的参数
    dataSource.setInitialSize(5);//初始化连接数量
    dataSource.setMaxActive(10);//最大的数量
    //获取连接
    Connection connection = dataSource.getConnection();

    //数据库操作

    //回收连接
    connection.close();//在连接池中connection.close()是回收连接
}

隐性创建连接池

//隐性操作创建连接池
public void druidShow2() throws Exception {
    //去读外部配置文件Properties
    Properties properties = new Properties();

    //src下的文件,可以使用类加载器提供的方法
    InputStream ips = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");

    //使用连接池的工具类的工程模式,创建连接池
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    Connection connection = dataSource.getConnection();

    //数据库操作

    //回收操作
    connection.close();

}

封装

首先我来了解对简单的工具类封装

public class DruidUtil {
/**
 * 连接池工具类的封装(就是创建一个DruidUtil类把使用这需要的方法,放到类中)
 *      获取连接池对象
 *      关闭连接
 */

//创建连接池对象
private static DataSource druidDataSource= null;

static {
    //获取外部配置文件
    Properties properties = new Properties();

    //加载外部配置文件
    InputStream inputStream = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");

    try {
        //将配置文件信息加载到properties
        properties.load(inputStream);

        //通过配置文件信息创建连接池对象
        druidDataSource = DruidDataSourceFactory.createDataSource(properties);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
  
//外部获取连接对象
public static Connection getConnection() throws SQLException {
    //返回连接对象
    return druidDataSource.getConnection();
}

//外部回收连接对象
public static void freeConnection(Connection connection) throws SQLException {
    connection.close();
}
}

在上面的封装类中,你可以发现,在外部获取连接对象的时候,本质还是new了一个连接对象,我们想要的是我们每次获取连接对象的时候,不是直接new一个而是看看本地有没有,下面给出优化代码。

public class DruidUtil {
 //创建连接池对象
    private static DataSource druidDataSource= null;
    //获取线程本地变量,来存放我们的连接对象
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    static {
        //获取外部配置文件
        Properties properties = new Properties();

        //加载外部配置文件
        InputStream inputStream = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");

        try {
            //将配置文件信息加载到properties
            properties.load(inputStream);

            //通过配置文件信息创建连接池对象
            druidDataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //外部获取连接对象
    public static Connection getConnection() throws SQLException {
        /**
         * 在向外部提供连接对象的时候,我要先判断本地线程对象中是否有空闲的,
         * 如果有的话,我们直接向外部提供已经创建好的对象,
         * 会节省很多资源
         */
        Connection connection = threadLocal.get();
        //进行判断
        if (connection == null){
            //重新创建一个连接对象
            connection= druidDataSource.getConnection();
            //并把新创建的对象存放到本地线程变量里
            threadLocal.set(connection);
        }
        //返回连接对象
        return  connection;
    }

    //外部回收连接对象
    public static void freeConnection() throws SQLException {
        //从线程本地变量里获取连接对象
        Connection connection = threadLocal.get();

        //判断连接对象是否存在,
        if (connection != null){
            //连接对象存在,清空线程本地变量
            threadLocal.remove();
            //事务状态回滚
            connection.setAutoCommit(true);
            //关闭连接
            connection.close();
        }
    }
}

在最后我给出一个小练习,使用上面学过的知识,把JDBC对数据库的增、删、改、查这四个操作封装成一个工具类;这里给出一点小提示:请注意增、删、改这个三个操作高度相似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习路上的bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值