The latest Java basic series courses--Day16-JDBC programming

Author Homepage: Programming Compass

About the author: High-quality creator in the Java field, CSDN blog expert
, CSDN content partner, invited author of Nuggets, Alibaba Cloud blog expert, 51CTO invited author, many years of architect design experience, resident lecturer of Tencent classroom

Main content: Java project, Python project, front-end project, artificial intelligence and big data, resume template, learning materials, interview question bank, technical mutual assistance

Favorites, likes, don't get lost, it's good to follow the author

Get the source code at the end of the article

​## JDBC

today's goal

  • Master CRUD of JDBC
  • Understand the role of each object in JDBC
  • Master the use of Druid

1. Overview of JDBC

We use the java language in development, so it is necessary to manipulate the data in the database through the java language. This is the JDBC to learn next.

1.1 JDBC concept

JDBC is a set of APIs that use the Java language to operate relational databases

Full name: ( Java DataBase Connectivity ) Java database connection

The same set of Java code we developed cannot operate different relational databases, because the underlying implementation details of each relational database are different. If this is the case, the problem is very big. The MySQL database can be used in the development stage in the company, but the company finally chooses the oracle database when it goes online. We need to modify the code in large quantities, which is obviously not what we want to see. . What we want to do is to operate different relational databases with the same set of Java codes. At this time, Sun Company has specified a set of standard interfaces (JDBC), and JDBC defines all the rules for operating relational databases. We all know that the interface cannot be used directly, we need to use the implementation class of the interface, and this set of implementation class (called: driver) is provided by the respective database vendors.

1.2 JDBC essence

  • A set of rules defined by the official (sun company) to operate all relational databases, that is, the interface
  • Various database vendors implement this set of interfaces and provide database driver jar packages
  • We can use this set of interfaces (JDBC) to program, and the code that is actually executed is the implementation class in the driver jar package

1.3 JDBC benefits

  • All database vendors use the same interface, and Java code does not need to be developed separately for different databases
  • The underlying database can be replaced at any time, and the Java code for accessing the database remains basically unchanged

In the future, the code for operating the database only needs to be oriented to JDBC (interface). To operate any relational database, you need to import the driver package of the database. If you need to operate the MySQL database, you need to import the driver package of the MySQL database into the project. The following figure is the MySQL driver package

2, JDBC quick start

Let's take a look at the process of operating the database through Java

Step 1: Write Java code

Step 2: Java code sends SQL to MySQL server

Step 3: The MySQL server receives the SQL statement and executes the SQL statement

Step 4: Return the result of the SQL statement execution to the Java code

2.1 Writing code steps

  • Create a project and import the driver jar package

  • register driver

    Class.forName("com.mysql.jdbc.Driver");
    
  • get connection

    Connection conn = DriverManager.getConnection(url, username, password);
    

    If the Java code needs to send SQL to the MySQL server, it needs to establish a connection first

  • define SQL statement

    String sql =update…” ;
    
  • Get the executed SQL object

    Executing SQL statements requires a SQL execution object, and this execution object is the Statement object

    Statement stmt = conn.createStatement();
    
  • Execute SQL

    stmt.executeUpdate(sql);  
    
  • Handle the returned result

  • release resources

2.2 Concrete operation

  • Create new empty project

  • Define the name of the project and specify the location

  • Set up the project, JDK version, compiled version

  • Create a module, specify the name and location of the module

  • Import driver package

    Put the mysql driver package in the lib directory (named at will) under the module, and add the jar package as a library file

  • When adding as a library file, there are three options as follows
    • Global Library: globally valid
    • Project Library : The project is available
    • Module Library: The module is valid

  • Create class under src

  • Write the code as follows
/**
 * JDBC快速入门
 */
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/db1";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql = "update account set money = 2000 where id = 1";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //5. 执行sql
        int count = stmt.executeUpdate(sql);//受影响的行数
        //6. 处理结果
        System.out.println(count);
        //7. 释放资源
        stmt.close();
        conn.close();
    }
}

3. Detailed explanation of JDBC API

3.1 DriverManager

DriverManager (driver management class) role:

  • register driver

    [External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-U7gFOKcn-1691030112385)(assets/image-20210725171339346.png)]

    The registerDriver method is used to register the driver, but the introductory case we did before was not written in this way. Instead implement it as follows

    Class.forName("com.mysql.jdbc.Driver");
    

    We query the Driver class provided by MySQL to see how it is implemented. The source code is as follows:

    In the static code block in this class, the DriverManagerobject registerDriver()method has been executed to register the driver, then we only need to load Driverthe class, and the static code block will be executed. And Class.forName("com.mysql.jdbc.Driver");you can load Driverthe class.

    hint:

    • The driver package after MySQL 5 can omit the step of registering the driver
    • Automatically load the driver class in the META-INF/services/java.sql.Driver file in the jar package
  • Get database connection

    [External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-gzk767uW-1691030112389)(assets/image-20210725171355278.png)]

    Parameter Description:

    • url: connection path

      Syntax: jdbc:mysql://ip address (domain name): port number/database name? Parameter key-value pair 1 & parameter key-value pair 2...

      Example: jdbc:mysql://127.0.0.1:3306/db1

      detail:

      • If the local mysql server is connected, and the default port of the mysql service is 3306, the url can be abbreviated as: jdbc:mysql:///database name? parameter key-value pair

      • Configure the useSSL=false parameter, disable the secure connection mode, and solve the warning prompt

    • user: username

    • poassword: password

3.2 Connection

Connection (database connection object) role:

  • Get the object that executes SQL
  • management affairs

3.2.1 Get the execution object

  • Ordinary Execution SQL Object

    Statement createStatement()
    

    In the entry case, it is the execution object obtained through this method.

  • Executing SQL objects for precompiled SQL: preventing SQL injection

    PreparedStatement  prepareStatement(sql)
    

    The SQL statement execution object obtained in this way PreparedStatementis what we will focus on explaining later, and it can prevent SQL injection.

  • The object that executes the stored procedure

    CallableStatement prepareCall(sql)
    

    The execution object obtained in this way CallableStatementis used to execute stored procedures, and stored procedures are not commonly used in MySQL, so we will not explain this.

3.2.2 Transaction Management

First review the operation of MySQL transaction management:

  • Open transaction: BEGIN; or START TRANSACTION;
  • Commit the transaction: COMMIT;
  • Rollback transaction: ROLLBACK;

MySQL automatically commits transactions by default

Next, learn the method of JDBC transaction management.

Connection defines three corresponding methods:

  • open transaction

    [External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-togxm8mT-1691030112392)(assets/image-20210725173444628.png)]

    Participating in autoCommit means whether to automatically commit the transaction, true means to automatically commit the transaction, false means to manually commit the transaction. To start a transaction, you need to set this parameter to false.

  • commit transaction

    [External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-M10PnTsu-1691030112393)(assets/image-20210725173618636.png)]

  • rollback transaction

    [External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-7FVlkzcC-1691030112395)(assets/image-20210725173648674.png)]

The specific code is implemented as follows:

/**
 * JDBC API 详解:Connection
 */
public class JDBCDemo3_Connection {

    public static void main(String[] args) throws Exception {
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql1 = "update account set money = 3000 where id = 1";
        String sql2 = "update account set money = 3000 where id = 2";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();

        try {
            // ============开启事务==========
            conn.setAutoCommit(false);
            //5. 执行sql
            int count1 = stmt.executeUpdate(sql1);//受影响的行数
            //6. 处理结果
            System.out.println(count1);
            int i = 3/0;
            //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();
    }
}

3.3 Statement

3.3.1 Overview

The purpose of the Statement object is to execute SQL statements. The methods used for different types of SQL statements are also different.

  • Execute DDL and DML statements

    [External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-2skdeikP-1691030112398)(assets/image-20210725175151272.png)]

  • Execute DQL statement

    This method involves ResultSetthe object, and we haven't learned this object yet, so we will focus on it later.

3.3.2 Code implementation

  • execute DML statement

    /**
      * 执行DML语句
      * @throws Exception
      */
    @Test
    public void testDML() throws  Exception {
          
          
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql = "update account set money = 3000 where id = 1";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //5. 执行sql
        int count = stmt.executeUpdate(sql);//执行完DML语句,受影响的行数
        //6. 处理结果
        //System.out.println(count);
        if(count > 0){
          
          
            System.out.println("修改成功~");
        }else{
          
          
            System.out.println("修改失败~");
        }
        //7. 释放资源
        stmt.close();
        conn.close();
    }
    
  • Execute DDL statements

    /**
      * 执行DDL语句
      * @throws Exception
      */
    @Test
    public void testDDL() throws  Exception {
          
          
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql = "drop database db2";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //5. 执行sql
        int count = stmt.executeUpdate(sql);//执行完DDL语句,可能是0
        //6. 处理结果
        System.out.println(count);
    
        //7. 释放资源
        stmt.close();
        conn.close();
    }
    

    Notice:

    • Future development rarely uses java code to operate DDL statements

3.4 ResultSet

3.4.1 Overview

ResultSet (result set object) function:

  • Encapsulates the results of SQL query statements.

After the DQL statement is executed, the object will be returned. The corresponding method of executing the DQL statement is as follows:

ResultSet  executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

Then we need to ResultSetget the data we want from the object. ResultSetThe object provides methods for manipulating query result data, as follows:

boolean next()

  • Move the cursor one line forward from the current position
  • Determine whether the current row is a valid row

Method return value description:

  • true : valid navigation, the current line has data
  • false : Invalid row, current row has no data

xxx getXxx (parameter): get data

  • xxx : data type; such as: int getInt(parameter) ; String getString(parameter)
  • parameter
    • Parameters of type int: the number of the column, starting from 1
    • Parameters of type String: the name of the column

The following figure shows the result after executing the SQL statement

At the beginning, the cursor is designated before the first row, and the red arrow points to the header row as shown in the figure. When we call next()the method, the cursor will move down to the first row of data, and the method returns true. At this time, we can getInt("id")get the value of the id field of the current row or getString("name")the value of the name field of the current row through . If you want to get the data of the next row, continue to call next()the method, and so on.

3.4.2 Code implementation

/**
  * 执行DQL
  * @throws Exception
  */
@Test
public void testResultSet() throws  Exception {
    
    
    //1. 注册驱动
    //Class.forName("com.mysql.jdbc.Driver");
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);
    //3. 定义sql
    String sql = "select * from account";
    //4. 获取statement对象
    Statement stmt = conn.createStatement();
    //5. 执行sql
    ResultSet rs = stmt.executeQuery(sql);
    //6. 处理结果, 遍历rs中的所有数据
    /* // 6.1 光标向下移动一行,并且判断当前行是否有数据
        while (rs.next()){
            //6.2 获取数据  getXxx()
            int id = rs.getInt(1);
            String name = rs.getString(2);
            double money = rs.getDouble(3);

            System.out.println(id);
            System.out.println(name);
            System.out.println(money);

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

        }*/
    // 6.1 光标向下移动一行,并且判断当前行是否有数据
    while (rs.next()){
    
    
        //6.2 获取数据  getXxx()
        int id = rs.getInt("id");
        String name = rs.getString("name");
        double money = rs.getDouble("money");

        System.out.println(id);
        System.out.println(name);
        System.out.println(money);

        System.out.println("--------------");
    }

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

3.5 Case

  • Requirement: Query the account table data, encapsulate it into an Account object, and store it in the ArrayList collection

  • Code

    /**
      * 查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
      * 1. 定义实体类Account
      * 2. 查询数据,封装到Account对象中
      * 3. 将Account对象存入ArrayList集合中
      */
    @Test
    public void testResultSet2() throws  Exception {
          
          
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
    
        //3. 定义sql
        String sql = "select * from account";
    
        //4. 获取statement对象
        Statement stmt = conn.createStatement();
    
        //5. 执行sql
        ResultSet rs = stmt.executeQuery(sql);
    
        // 创建集合
        List<Account> list = new ArrayList<>();
       
        // 6.1 光标向下移动一行,并且判断当前行是否有数据
        while (rs.next()){
          
          
            Account account = new Account();
    
            //6.2 获取数据  getXxx()
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");
    
            //赋值
            account.setId(id);
            account.setName(name);
            account.setMoney(money);
    
            // 存入集合
            list.add(account);
        }
    
        System.out.println(list);
    
        //7. 释放资源
        rs.close();
        stmt.close();
        conn.close();
    }
    

3.6 PreparedStatement

PreparedStatement role:

  • Precompile and execute SQL statements: prevent SQL injection problems

You must not understand the SQL injection problem in the above function. Then let's explain SQL injection first.

3.6.1 SQL Injection

SQL injection is a method of modifying pre-defined SQL statements by manipulating input to execute code to attack the server.

day03-JDBC\资料\2. sql注入演示Modify application.propertiesthe user name and password in the file under today's information , the file content is as follows:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=1234

testCreate a database named in MySQL

create database test;

day03-JDBC\资料\2. sql注入演示\sql.jarRun the jar package under today's information in the command prompt .

At this point we can see the user table in the database

This is the SQL injection vulnerability, and it is also very dangerous. Of course, there are no such problems in the systems on the market now, so don't try to use this method to try other systems.

So how to solve it? Here you can replace the SQL execution object Statementwith PreparedStatementan object.

3.6.2 Code simulation SQL injection problem

@Test
public void testLogin() throws  Exception {
    
    
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);

    // 接收用户输入 用户名和密码
    String name = "sjdljfld";
    String pwd = "' or '1' = '1";
    String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
    // 获取stmt对象
    Statement stmt = conn.createStatement();
    // 执行sql
    ResultSet rs = stmt.executeQuery(sql);
    // 判断登录是否成功
    if(rs.next()){
    
    
        System.out.println("登录成功~");
    }else{
    
    
        System.out.println("登录失败~");
    }

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

The above code is to splice the user name and password into the sql statement, and the spliced ​​sql statement is as follows

select * from tb_user where username = 'sjdljfld' and password = ''or '1' = '1'

username = 'sjdljfld' and password = ''From the above statement, it can be seen that no matter whether the condition is satisfied or not, orthe following '1' = '1'is always satisfied, and the final condition is established, and the login can be performed normally.

Next, let's learn about the PreparedStatement object.

3.6.3 Overview of PreparedStatements

PreparedStatement role:

  • Precompile and execute SQL statements: prevent SQL injection problems
  • Get the PreparedStatement object

    // SQL语句中的参数值,使用?占位符替代
    String sql = "select * from user where username = ? and password = ?";
    // 通过Connection对象获取,并传入对应的sql语句
    PreparedStatement pstmt = conn.prepareStatement(sql);
    
  • set parameter value

    In the above sql statement, the parameters use? to place place, and the value of these? must be set before.

    PreparedStatement object: setXxx (parameter 1, parameter 2): assign a value to?

    • Xxx: data type; such as setInt (parameter 1, parameter 2)

    • parameter:

      • Parameter 1: ? position number, starting from 1

      • Parameter 2: ? the value of

  • Execute SQL statement

    executeUpdate(); Execute DDL statements and DML statements

    executeQuery(); execute DQL statement

    Notice:

    • There is no need to pass the SQL statement when calling these two methods, because the SQL statement has been precompiled when the SQL statement execution object is obtained.

3.6.4 Improvements using PreparedStatement

 @Test
public void testPreparedStatement() throws  Exception {
    
    
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);

    // 接收用户输入 用户名和密码
    String name = "zhangsan";
    String pwd = "' or '1' = '1";

    // 定义sql
    String sql = "select * from tb_user where username = ? and password = ?";
    // 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    // 设置?的值
    pstmt.setString(1,name);
    pstmt.setString(2,pwd);
    // 执行sql
    ResultSet rs = pstmt.executeQuery();
    // 判断登录是否成功
    if(rs.next()){
    
    
        System.out.println("登录成功~");
    }else{
    
    
        System.out.println("登录失败~");
    }
    //7. 释放资源
    rs.close();
    pstmt.close();
    conn.close();
}

Execute the above statement and you can find that there will be no SQL injection vulnerability. So how does PreparedStatement solve it? It escapes special characters, and the escaped SQL is as follows:

select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'

3.6.5 Principle of PreparedStatement

PreparedStatement benefits:

  • Precompiled SQL for higher performance
  • Prevent SQL injection:Escape sensitive characters

The Java code operation database process is shown in the figure:

  • Send sql statement to MySQL server

  • The MySQL server will perform the following operations on the sql statement

    • Check the SQL statement

      Check whether the syntax of the SQL statement is correct.

    • Compile the SQL statement. Compile SQL statements into executable functions.

      Checking SQL and compiling SQL takes longer than executing SQL. If we just reset the parameters, then checking SQL statements and compiling SQL statements will not need to be repeated. This improves performance.

    • Execute SQL statement

Next, let's look at the principle by querying the log.

  • Enable precompilation

    The following parameters need to be added when writing the url in the code. And we didn't turn on the precompilation function at all before, but only solved the SQL injection vulnerability.

    useServerPrepStmts=true
    
  • Configure MySQL execution log (take effect after restarting the mysql service)

    Add the following configuration in the mysql configuration file (my.ini)

    log-output=FILE
    general-log=1
    general_log_file="D:\mysql.log"
    slow-query-log=1
    slow_query_log_file="D:\mysql_slow.log"
    long_query_time=2
    
  • The java test code is as follows:

     /**
       * PreparedStatement原理
       * @throws Exception
       */
    @Test
    public void testPreparedStatement2() throws  Exception {
          
          
    
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        // useServerPrepStmts=true 参数开启预编译功能
        String url = "jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
    
        // 接收用户输入 用户名和密码
        String name = "zhangsan";
        String pwd = "' or '1' = '1";
    
        // 定义sql
        String sql = "select * from tb_user where username = ? and password = ?";
    
        // 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
    
        Thread.sleep(10000);
        // 设置?的值
        pstmt.setString(1,name);
        pstmt.setString(2,pwd);
        ResultSet rs = null;
        // 执行sql
        rs = pstmt.executeQuery();
    
        // 设置?的值
        pstmt.setString(1,"aaa");
        pstmt.setString(2,"bbb");
        // 执行sql
        rs = pstmt.executeQuery();
    
        // 判断登录是否成功
        if(rs.next()){
          
          
            System.out.println("登录成功~");
        }else{
          
          
            System.out.println("登录失败~");
        }
    
        //7. 释放资源
        rs.close();
        pstmt.close();
        conn.close();
    }
    
  • Execute the SQL statement and view D:\mysql.logthe log as follows:

    [External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-ktpojifT-1691030112401)(assets/image-20210725202829738.png)]

    In the third line in the figure above Prepareis to precompile the SQL statement. The fourth and fifth lines execute the SQL statement twice, but the SQL is not precompiled before the second execution.

summary:

  • When obtaining the PreparedStatement object, send the sql statement to the mysql server for checking and compiling (these steps are time-consuming)
  • There is no need to perform these steps during execution, and the speed is faster
  • If the sql template is the same, you only need to check and compile once

4. Database connection pool

4.1 Introduction to database connection pool

  • The database connection pool is a container responsible for allocating and managing database connections (Connection)

  • It allows an application to reuse an existing database connection instead of re-establishing a new one;

  • Release database connections whose idle time exceeds the maximum idle time to avoid missing database connections caused by not releasing database connections

  • benefit

    • resource reuse
    • Improve system response speed
    • Avoid missing database connections

Before using the connection in our code, we created a Connection object without using it, and it will be destroyed after use. This repeated creation and destruction process is particularly consuming of computer performance and time-consuming.

After the database uses the database connection pool, it can achieve the reuse of Connection objects, as shown in the following figure

The connection pool is created at the beginning to store some connection (Connection) objects. When the user needs to connect to the database, he does not need to create a connection himself, but only needs to obtain a connection from the connection pool for use, and then return the connection object to the connection pool after use; this can reuse resources and save frequent creation The time it takes for the connection to destroy the connection, thus improving the speed of the system response.

4.2 Implementation of database connection pool

  • Standard interface:DataSource

    The standard interface of the database connection pool provided by the official (SUN), which is implemented by a third-party organization. This interface provides the function of obtaining connection:

    Connection getConnection()
    

    Then you don't need DriverManagerto get Connectionthe object through the object in the future, but get Connectionthe object through the connection pool (DataSource).

  • Common database connection pool

    • DBCP
    • C3P0
    • Druid

    We use more Druid now, and its performance will be better than the other two.

  • Druid

    • Druid connection pool is Alibaba's open source database connection pool project

    • Powerful, excellent performance, one of the best database connection pools in Java language

4.3 Use of Driud

  • Import the jar package druid-1.1.12.jar
  • Define configuration files
  • load configuration file
  • Get the database connection pool object
  • get connection

Now through the code implementation, first you need to put the jar package of druid under the lib under the project and add it as a library file

The project structure is as follows:

Write the configuration file as follows:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

The code for using druid is as follows:

/**
 * Druid数据库连接池演示
 */
public class DruidDemo {
    
    

    public static void main(String[] args) throws Exception {
    
    
        //1.导入jar包
        //2.定义配置文件
        //3. 加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
        //4. 获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //5. 获取数据库连接 Connection
        Connection connection = dataSource.getConnection();
        System.out.println(connection); //获取到了连接后就可以继续做其他操作了

        //System.out.println(System.getProperty("user.dir"));
    }
}

5. JDBC practice

5.1 Requirements

Complete the operation of adding, deleting, modifying and checking product brand data

  • Query: query all data
  • Add: add brand
  • Modify: modify according to id
  • delete: delete by id

5.2 Case Implementation

5.2.1 Environment preparation

  • Database Tabletb_brand

    -- 删除tb_brand表
    drop table if exists tb_brand;
    -- 创建tb_brand表
    create table tb_brand (
        -- id 主键
        id int primary key auto_increment,
        -- 品牌名称
        brand_name varchar(20),
        -- 企业名称
        company_name varchar(20),
        -- 排序字段
        ordered int,
        -- 描述信息
        description varchar(100),
        -- 状态:0:禁用  1:启用
        status int
    );
    -- 添加数据
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
  • The entity class Brand under the pojo package

    /**
     * 品牌
     * alt + 鼠标左键:整列编辑
     * 在实体类中,基本数据类型建议使用其对应的包装类型
     */
    public class Brand {
          
          
        // id 主键
        private Integer id;
        // 品牌名称
        private String brandName;
        // 企业名称
        private String companyName;
        // 排序字段
        private Integer ordered;
        // 描述信息
        private String description;
        // 状态:0:禁用  1:启用
        private Integer status;
    
        public Integer getId() {
          
          
            return id;
        }
    
        public void setId(Integer id) {
          
          
            this.id = id;
        }
    
        public String getBrandName() {
          
          
            return brandName;
        }
    
        public void setBrandName(String brandName) {
          
          
            this.brandName = brandName;
        }
    
        public String getCompanyName() {
          
          
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
          
          
            this.companyName = companyName;
        }
    
        public Integer getOrdered() {
          
          
            return ordered;
        }
    
        public void setOrdered(Integer ordered) {
          
          
            this.ordered = ordered;
        }
    
        public String getDescription() {
          
          
            return description;
        }
    
        public void setDescription(String description) {
          
          
            this.description = description;
        }
    
        public Integer getStatus() {
          
          
            return status;
        }
    
        public void setStatus(Integer status) {
          
          
            this.status = status;
        }
    
        @Override
        public String toString() {
          
          
            return "Brand{" +
                    "id=" + id +
                    ", brandName='" + brandName + '\'' +
                    ", companyName='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    

5.2.2 Query all

 /**
   * 查询所有
   * 1. SQL:select * from tb_brand;
   * 2. 参数:不需要
   * 3. 结果:List<Brand>
   */

@Test
public void testSelectAll() throws Exception {
    
    
    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = "select * from tb_brand;";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    //5. 执行SQL
    ResultSet rs = pstmt.executeQuery();
    //6. 处理结果 List<Brand> 封装Brand对象,装载List集合
    Brand brand = null;
    List<Brand> brands = new ArrayList<>();
    while (rs.next()){
    
    
        //获取数据
        int id = rs.getInt("id");
        String brandName = rs.getString("brand_name");
        String companyName = rs.getString("company_name");
        int ordered = rs.getInt("ordered");
        String description = rs.getString("description");
        int status = rs.getInt("status");
        //封装Brand对象
        brand = new Brand();
        brand.setId(id);
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(ordered);
        brand.setDescription(description);
        brand.setStatus(status);

        //装载集合
        brands.add(brand);
    }
    System.out.println(brands);
    //7. 释放资源
    rs.close();
    pstmt.close();
    conn.close();
}

5.2.3 Add data

/**
  * 添加
  * 1. SQL:insert into tb_brand(brand_name, company_name, ordered, description, status) values(?,?,?,?,?);
  * 2. 参数:需要,除了id之外的所有参数信息
  * 3. 结果:boolean
  */
@Test
public void testAdd() throws Exception {
    
    
    // 接收页面提交的参数
    String brandName = "香飘飘";
    String companyName = "香飘飘";
    int ordered = 1;
    String description = "绕地球一圈";
    int status = 1;

    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = "insert into tb_brand(brand_name, company_name, ordered, description, status) values(?,?,?,?,?);";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    pstmt.setString(1,brandName);
    pstmt.setString(2,companyName);
    pstmt.setInt(3,ordered);
    pstmt.setString(4,description);
    pstmt.setInt(5,status);

    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

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

5.2.4 Modify data

/**
  * 修改
  * 1. SQL:

     update tb_brand
         set brand_name  = ?,
         company_name= ?,
         ordered     = ?,
         description = ?,
         status      = ?
     where id = ?

   * 2. 参数:需要,所有数据
   * 3. 结果:boolean
   */

@Test
public void testUpdate() throws Exception {
    
    
    // 接收页面提交的参数
    String brandName = "香飘飘";
    String companyName = "香飘飘";
    int ordered = 1000;
    String description = "绕地球三圈";
    int status = 1;
    int id = 4;

    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = " update tb_brand\n" +
        "         set brand_name  = ?,\n" +
        "         company_name= ?,\n" +
        "         ordered     = ?,\n" +
        "         description = ?,\n" +
        "         status      = ?\n" +
        "     where id = ?";

    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);

    //4. 设置参数
    pstmt.setString(1,brandName);
    pstmt.setString(2,companyName);
    pstmt.setInt(3,ordered);
    pstmt.setString(4,description);
    pstmt.setInt(5,status);
    pstmt.setInt(6,id);

    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

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

5.2.5 Delete data

/**
  * 删除
  * 1. SQL:
            delete from tb_brand where id = ?
  * 2. 参数:需要,id
  * 3. 结果:boolean
  */
@Test
public void testDeleteById() throws Exception {
    
    
    // 接收页面提交的参数
    int id = 4;
    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = " delete from tb_brand where id = ?";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    pstmt.setInt(1,id);
    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

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

Guess you like

Origin blog.csdn.net/whirlwind526/article/details/132078173