Java back-end top-down approach-exploring JDBC

Java back-end top-down approach-exploring JDBC

(1) What is JDBC

After learning for so long, we finally got out of the core part of the java backend and reached the side knowledge points of java. In other words, the following content is no longer the exclusive content of the java backend, and ordinary java programs may also be used frequently.

Not much nonsense, this time I talked about JDBC, the full name of which is Java Database Connectivity, which is an application program interface used to regulate how client programs access the database in the Java language. Since it is dealing with the database, it is obviously very important, because the back-end development is mainly responsible for business and data, business refers to logic, and data naturally refers to the content stored in the database, JDBC is between business and data Bridge.

Insert picture description here

JDBC is an API used to connect to a database in Java language programming. JDBC is a specification, it provides a set of interfaces, allowing a portable access to the underlying database API. Use the JDBC driver to access the database and store data in the database. Simply put, it is an abstraction of the process of accessing the database. We don't need to write different codes according to different databases. We only need to care about our business logic.

The java application we wrote is first connected to the JDBC Driver through the JDBC API. These JDBC drivers are provided by major database manufacturers for JDBC. We can download the jar package online to use, and then connect to ours through the JDBC driver. The database is very simple and fast. With JDBC, we can perform corresponding operations on almost all databases that are common on the market with only a set of APIs, which greatly reduces our learning costs.

(2) How to use JDBC

Let's take a look at the simplest example:

package com.demo;

import java.sql.*;

public class JDBCTest {
    
    
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
    
    
        Class.forName("com.mysql.jdbc.Driver");

        String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
        String userName = "root";
        String password = "19710825@Apple";
        Connection connection = DriverManager.getConnection(url, userName, password);

        String sql = "select * from testtable";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        while(resultSet.next()){
    
    
            System.out.println(resultSet.getString("name"));
        }
        preparedStatement.close();
        connection.close();
    }
}

First of all, we must understand the process of using JDBC. First, we need to load the driver class, and then create a Connection object through DriverManager. The creation of the Connection object requires three parameters: connection string, database user name and password. Then write the SQL statement we need, get the preparedStatement object through the Connection object, and then execute the SQL to get the data we need through the return value. Finally, don't forget to close the preparedStatement and Connection to release resources.

From then on, we can clearly see the convenience brought by JDBC. For example, we suddenly want to change a database, but the original business logic remains unchanged. In other words, our Connection object has changed (the Connection of different databases is definitely different). From the code point of view, we only need to modify the driver class, connection string, user name and password, that is, all connections with Connection Related things need to change, but our business logic can meet our needs without any modification.

We can find a detail. If we need to execute a lot of SQL, then our Connection object has been created and released repeatedly, which will cause a lot of resource overhead, which is very detrimental to the performance of our application. of. Therefore, we have to think of ways to change, so the technology of database connection pool was born (it can be seen that any technology is produced for a reason, and it must be to solve a specific problem in the development process), the specific details I will talk about it in other articles, so I won’t repeat it here.

(3) Why use preparedStatement

We used preparedStatement in the code above, in fact, it inherited from Statement and is a subclass of it. So why do we try to use preparedStatement instead of Statement?

First of all, we can look at this issue from the Java object-oriented inheritance relationship. As we all know, subclasses inherit all methods of the parent class (except final), and they can also have their own methods, that is, these own methods are given to subclasses. It has more powerful functions than the parent class, and it feels a little bit more blue than blue, and the waves behind the Yangtze River push forward waves.

So the question is, what functions and features does preparedStatement have? There are probably three items:

  1. Improve the performance of executing statements
  2. Better readability and maintainability
  3. With higher security

Let's talk about the first point, good performance. PreparedStatement can use placeholders and is pre-compiled. Batch processing is more efficient than Statement. Our SQL statement can be written like this:

String sql = "update user set username = ? where id = ?";

one of them? It stands for placeholders. Everyone remembers the placeholders %s and %d in the String.format() method, or the placeholders in the printf() function in the C language. They are almost The same effect is to occupy a position and then fill in the corresponding value.

Following the steps written at the beginning of the article, the next step is:

PreparedStatement preparedStatement = connection.prepareStatement(sql);

Here is the precompilation we are going to talk about. We can see that we passed the SQL parameters. Note that at this time we have not filled the placeholders with the required values, so it is called precompilation, which can also be regarded as a SQL statement. "Template", we can form different SQL statements by filling it with different values. This is the reason why PreparedStatement performs better in batch processing. Just like what we usually do, if we have a template, we can quickly make what we want according to our actual needs (typical cases: PPT templates, paper templates).

After the precompilation is over, we need to assign values ​​to the placeholders. Assignment is also very simple:

preparedStatement.setString(1, "jack");
preparedStatement.setInt(2, 15);

The first parameter in the parameters is 1 and 2, which represent the position of the question mark. If there is only one question mark in the SQL statement, there is no need to declare this parameter. The second parameter represents the value we want to assign. Therefore, with the help of templates and fill values, we obtain such a SQL statement:

update user set username = "jack" where id = 15

This is the second feature we wrote above: better readability and maintainability. With templates, we can put aside the values ​​and focus on logic, and the templates also make the code reusable, and it is very convenient to modify the logic if necessary. From this we can find that we need to pay attention to the development from concrete to abstract, abstracting features from entities is a necessary skill for every developer.

Finally, we come to the third point, high security. Using PreparedStatement can prevent SQL injection attacks. The so-called SQL injection refers to inserting SQL commands into Web form submissions or entering the query string of a domain name or page request, ultimately achieving the purpose of deceiving the server and executing malicious SQL commands. SQL injection is very clever. Generally, a certain conditional statement of SQL is true by injecting a true statement. If we use Statement, because we cannot use placeholders, in order to achieve the purpose of code reuse, we will definitely use string splicing, for example:

String sql = "select * from user where name = " + x + "and password = " + y;

In this statement, x and y are variables. Some people may think that this is not the same as the placeholders before. We can set the values ​​of x and y as needed. However, there are huge hidden dangers in this. Assuming this is a login function, there are two input boxes, the input results will be passed to x and y, we need to enter the correct user name and password to get the user's information. The hacker does not know the user's password, but he can assign values ​​to x and y like this:

select * from user where name = 'Tom' and password = '123456' or 1 = 1

Obviously, the hacker entered Tom in one input box, and the other entered '123456' or 1 = 1. Observe carefully, after the hacker has such a great operation, the judgment condition of the password is directly rendered useless by this 1 = 1. The hacker can just enter a password to make this judgment condition stand and obtain the data!

Why is preparedStatement inherently immune to SQL injection? Let's take a look at the above injecting things, and also in time '123456' or 1 = 1. Obviously, the hacker truncated the statement with quotation marks, so that a statement was added to the SQL, that is, or 1 = 1. This statement should obviously not appear. How can we avoid it? I wanted to enter a string, but it turned into a string plus a SQL statement! The easiest thing to think of is that we inject this paragraph into quotation marks outside, and escape all the quotation marks inside, like "\'123456\' or 1 = 1", so that it becomes a whole string, also There will be no more sabotage. That's right, preparedStatement does it!

Therefore, just because of this possible hidden danger, it is enough for us to completely abandon Statement. However, there is one condition that we can still use Statement, that is, our SQL statements do not need to be reused, that is, when there is no string splicing. However, preparedStatement that cannot be achieved by Statement can be achieved, as can preparedStatement that can be achieved by Statement. Then why do we still use Statement? Are you right?

PS: Attention! When using preparedStatement, there is a kind of SQL injection that cannot be prevented (I also heard people say it recently). Here I make a key reminder:% in fuzzy query. You can study in this direction. But this problem is not particularly critical, because it is difficult to cause damage to the database data.

(4) JDBC and transactions

The database transaction (Transaction) is an operation sequence composed of several SQL statements. The specific introduction I will introduce in the future "Database System Principles" topic, here is mainly to tell you how to use. Friends who have never heard of business can skip this paragraph or go online to learn about the characteristics of business.

You may be wondering, doesn't the transaction need to be committed? Doesn't it need to roll back? Why is the above code not reflected? Because transactions are committed by default in JDBC, if we need to customize transactions, we must first turn off this setting.

Then, if the SQL statements are all executed correctly, the transaction needs to be committed. If something goes wrong, we have to roll back the transaction. Finally, whether the transaction is committed or rolled back, we have to close the database connection. This forms the basic template of one of our affairs:

try {
    
    
    // 关闭自动提交:
    connection.setAutoCommit(false);
    // 执行多条SQL语句:
    ......(省略)
    // 没有异常,提交事务:
    connection.commit();
} catch (SQLException e) {
    
    
    // 遇到异常,回滚事务:
    connection.rollback();
} finally {
    
    
    // 关闭连接:
    connection.close();
}

The key code to open the transaction is connection.setAutoCommit(false), which means to close the automatic commit. The code that commits the transaction calls connection.commit() after executing the specified SQL statements. It should be noted that the transaction cannot always succeed. If the transaction fails to commit, an SQL exception will be thrown (or it may be thrown when the SQL statement is executed). At this time, we must catch the exception and call connection.rollback() to roll back the transaction. Finally, close the database connection in finally.

In fact, by default, after we get the Connection connection, we are always in "auto-commit" mode, that is, every SQL executed is automatically executed as a transaction, which is why we did not write commit before: because of the default There are such "implicit transactions". As long as the autoCommit of Connection is turned off, multiple statements can be executed in one transaction, and the transaction ends with the commit() method.

June 17, 2020

Guess you like

Origin blog.csdn.net/weixin_43907422/article/details/106390816