JDBC — используйте JDBC для подключения к базе данных MySQL.

база данных

существуетJDBC - Что такое JDBCВ этой статье мы представили основные принципы JDBC.

В этой статье мы поговорим о том, как использовать JDBC для подключения к базе данных MySQL.

1. Основные операции

Сначала нам нужна база данных и таблица:

CREATE DATABASE `test`;
USE `test`;
CREATE TABLE `user` (
	`id` INT(10) NOT NULL PRIMARY KEY AUTO_INCREMENT, 
	`username` VARCHAR(20) NOT NULL,
	`password` VARCHAR(20) NOT NULL
);

Затем мы импортируем пакет jar драйвераmysql-connector-java-8.0.20.jar Импортируйте пакет jar или используйте зависимости maven:

Что касается того, как импортировать пакеты jar или использовать зависимости maven, я не буду здесь вдаваться в подробности.


Основные шаги:

  1. Зарегистрировать водителя
  2. получить объект подключения
  3. Создать оператор SQL
  4. Создайте объект оператора, который выполняет оператор SQL.
  5. Выполнить оператор SQL
  6. бесплатные ресурсы

1. Добавить, удалить, изменить

public static void main(String[] args) {
    Connection conn = null;
    Statement stmt = null;
    try {
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接对象
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false", "root", "123456");
        //创建SQL语句
        String sql = "insert into user values (null, '行小观', '1234')";
        //创建Statement对象
        stmt = conn.createStatement();
        //执行SQL语句
        int i = stmt.executeUpdate(sql);
        System.out.println(i);
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (stmt != null) {//避免空指针异常
            try {
                stmt.close();//释放资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

Код оператора DML тот же.

2. Запрос

public static void main(String[] args) {
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    try {
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接对象
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false", "root", "123456");
        //创建SQL语句
  		String username = "行小观";
         String password = "1234";
         String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";//拼接字符串
        //创建Statement对象
        stmt = conn.createStatement();
        //执行SQL语句
        rs = stmt.executeQuery(sql);
        while (rs.next()) {
            int id = rs.getInt("id");
            String name = rs.getString("name");
            float money = rs.getFloat("money");
            System.out.println(id + "--" + name + "--" + money);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {//避免空指针异常
            try {
                stmt.close();//释放资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

Во-вторых, объяснение класса

1. DriverManager

(1) Зарегистрируйте драйвер через DriverManager

Class.forName("com.mysql.cj.jdbc.Driver")Загрузите класс Driver в память.

Смотрим исходный код класса Driver и находим блок статического кода:

static {
    try {
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
    }
}

Этот статический блок кода выполняется при загрузке класса, а после выполнения выполняется черезDriverManager.registerDriver(new Driver())Зарегистрируйте драйвер.

(2) Получите объект Connection через DriverManager

DriverManager.getConnection(url, username, password)

Нам нужно указать только три параметра: URL-адрес базы данных, имя пользователя и пароль.

Примечание. К URL необходимо добавить часовой пояс.

2. Connection

conn.createStatement()

Создайте объект Statement из объекта Connection

3. Statement

Этот объект может выполнять статические операторы SQL и возвращать результаты выполнения.

4. ResultSet

Таблица данных, представляющая набор результатов базы данных, обычно сгенерированная путем выполнения оператора, который запрашивает базу данных.

можно использоватьnext()метод перебирает набор результатов

3. SQL-инъекция

Серьезная проблема в приведенном выше примере заключается в том, что операторы SQL, которые мы пишем, являются статическими, другими словами, операторы SQL объединяются с использованием строк. Например:

String username = "行小观";
String password = "1234";
String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";

Эффект после замены переменной:

select * from user where username = '行小观' and password = '1234'

Это не проблема.

Но теперь все изменилось:

String username = "行小观";
String password = "1' or '1' = '1";

Эффект после замены переменной:

select * from user where username = '行小观' and password = '1' or '1' = '1'

потому чтоor '1'='1'Причина, по которой предложение where оператора SQL истинно, что эквивалентно

select * from user

Таким образом, будет опрошена вся таблица.

Вышеупомянутое является SQL-инъекцией.

В-четвертых, используйте PreparedStatement для предотвращения SQL-инъекций.

Использование объекта Statement для выполнения статического оператора SQL, если выполняется специально сконструированный оператор, приведет к SQL-инъекции и дыре в безопасности.

Использование объектов PreparedStatement позволяет избежать описанных выше проблем.

Объекты PreparedStatementПредварительно скомпилированные операторы SQLОбъект, наследуемый от Statement.

Что такое предварительно скомпилированный оператор SQL?

статический оператор SQL

String sql = "select * from user where username = '" + username + "' and password = ' " + password + "'";

Перейдите к предварительно скомпилированному оператору SQL:

String sql = "select * from user where username = ? and password = ? ";

При написании операторов SQL вместо использования строк для конкатенации используйте вопросительные знаки? Заполнители вместо переменных.

Шаги по использованию JDBC изменились:

  1. Зарегистрировать водителя
  2. получить объект подключения
  3. Создать оператор SQL
  4. Создайте объект PreparedStatement, который выполняет оператор SQL.
  5. назначить в?
  6. Выполнить оператор SQL
  7. бесплатные ресурсы
public static void main(String[] args) {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接对象
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false", "root", "123456");
        //创建SQL语句
        String username = "行小观";
        String password = "1234";
        String sql = "select * from user where username = ? and password = ?";
        //创建PreparedStatement对象
        pstmt = conn.prepareStatement(sql);
        //给?赋值
        pstmt.setString(1, username);
        pstmt.setString(2, password);
        //执行SQL语句
        rs = pstmt.executeQuery();
        while (rs.next()) {
            int id = rs.getInt("id");
            String unm = rs.getString("username");
            String pwd = rs.getString("password");
            System.out.println(id + "--"+ unm + "--" + pwd);
        }

    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pstmt != null) {//避免空指针异常
            try {
                pstmt.close();//释放资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

5. Дальнейшая инкапсуляция

Приведенный выше пример имеет несколько недостатков:

  1. Много дублированного кода.
  2. Полное имя класса драйвера, URL-адрес базы данных, имя пользователя и пароль записываются в коде. Если вы измените эти значения, вам необходимо изменить код.

Сначала мы пишем полное имя класса драйвера и информацию о базе данных в файле конфигурации.database.properties, получить эти значения, прочитав файл конфигурации.Когда нам нужно изменить информацию, мы можем напрямую изменить информацию в файле конфигурации без изменения кода.

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false
username=root
password=123456

Затем мы инкапсулируем операции регистрации классов драйверов, получения соединений и высвобождения ресурсов в классы инструментов.JdbcUtilсередина.

public class JdbcUtil {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        try {
            Properties pro = new Properties();
            ClassLoader classLoader = JdbcUtil.class.getClassLoader();
            URL resourceURL = classLoader.getResource("database.properties");
            String path = resourceURL.getPath();
            pro.load(new FileReader(path));
            driver = pro.getProperty("driver");
            url = pro.getProperty("url");
            username = pro.getProperty("username");
            password = pro.getProperty("password");
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {//避免空指针异常
            try {
                stmt.close();//释放资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        close(stmt, conn);

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

Когда мы снова используем JDBC, мы можем использовать служебные классы для упрощения кода.

public static void main(String[] args) {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        //获取连接
        conn = JdbcUtil.getConnection();
        //创建SQL语句
        String username = "行小观";
        String password = "1234";
        String sql = "select * from user where username = ? and password = ?";
        //创建PreparedStatement对象
        pstmt = conn.prepareStatement(sql);
        //给?赋值
        pstmt.setString(1, username);
        pstmt.setString(2, password);
        //执行SQL语句
        rs = pstmt.executeQuery();
        while (rs.next()) {
            int id = rs.getInt("id");
            String unm = rs.getString("username");
            String pwd = rs.getString("password");
            System.out.println(id + "--"+ unm + "--" + pwd);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(rs, pstmt, conn);
    }
}

Если есть ошибка, поправьте меня


Статья была впервые опубликована в паблике «Pedestrian View Study».

在这里插入图片描述