Learn Java step by step Chapter 25 JDBC and database connection pool

Chapter 25 JDBC and database connection pool

821. Schematic diagram of JDBC

  • JDBC provides a unified interface for accessing different databases and shields the use details for users. Java programmers can use JDBC API to connect to any database system that provides jdbc driver, so as to complete various operations on the database

  • The Java designer defines the interface specification for operating the database, which is implemented by their respective database manufacturers. Java programmers only need to program for this set of interfaces.

822. JDBC Simulation Implementation

823. JDBC quick start

  • JDBC API is a series of interfaces. It unifies and standardizes the connection between application and database, executes SQL statements, and obtains return results. The relevant interfaces and classes are in Java SQL and javax SQL package

  • JDBC programming steps:

  1. Register Driver: load Driver class
  2. Get Connection: get Connection object
  3. Execute SQL: get Statement object
  4. Release resources
  • Database connection method 1:
package p823;

import com.mysql.jdbc.Driver;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
* Connect to database in static loading mode
* @author Spring-_-Bear
* @version 2021-11-08 20:56
*/
public class Jdbc01 {
   public static void main(String[] args) throws SQLException {
       // Database connected to: jdbc:mysql: / / host IP address: port / db_name
       String url = "jdbc:mysql://localhost:3306/temp";
       // Set user name and password
       Properties properties = new Properties();
       properties.setProperty("user", "springbear");
       properties.setProperty("password","123");
       
       // Load driver: new com mysql. jdbc. Driver()
       Driver driver = new Driver();
       // Get connection
       Connection connect = driver.connect(url, properties);

       // SQL statement
       String insert = "INSERT INTO actor VALUES (NULL,'Zhang San','male','1970-01-01','10086');";

       // Get an object that executes a static SQL statement and returns the results it generates
       Statement statement = connect.createStatement();
       // Returns the number of rows affected
       int rows = statement.executeUpdate(insert);

       System.out.println("Returns the number of rows affected = " + rows);

       statement.close();
       connect.close();
   }
}

824. Database connection mode 2

/**
* Mode 1 belongs to static loading, with poor flexibility and strong dependence. Mode 2 is considered to use reflection mechanism 
*/
public void connect02() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
   // Database connected to: jdbc:mysql: / / host IP address: port / db_name
   String url = "jdbc:mysql://localhost:3306/temp";
   // Set user name and password
   Properties properties = new Properties();
   properties.setProperty("user", "springbear");
   properties.setProperty("password","123");

   // Load class information
   Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
   // Get class instance
   Driver driver = (Driver)aClass.newInstance();
   // Get connection
   Connection connect = driver.connect(url, properties);
}

825. Database connection mode 3

/**
* Replace Driver with Driver manager for unified management
*/
public void connect03() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
   // Load class information
   Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
   // Get class instance
   Driver driver = (Driver)aClass.newInstance();

   String url = "jdbc:mysql://localhost:3306/temp";
   String user = "springbear";
   String pwd = "123";

   // Register driver
   DriverManager.registerDriver(driver);
   // Get connection
   Connection connection = DriverManager.getConnection(url, user, pwd);
}

826. Database connection mode 4

/**
* Use class Forname auto complete registration driver
*/
public void connect04() throws ClassNotFoundException, SQLException {
   // Load class information and automatically complete the registration during the process of loading Driver
   Class.forName("com.mysql.jdbc.Driver");
   /*
    * static {
    *      try {
    *          DriverManager.registerDriver(new Driver());
    *      } catch (SQLException var1) {
    *          throw new RuntimeException("Can't register driver!");
    *      }
    * }
    */
   
   String url = "jdbc:mysql://localhost:3306/temp";
   String user = "springbear";
   String pwd = "123";

   // Get connection
   Connection connection = DriverManager.getConnection(url, user, pwd);
}

827. Database connection mode 5

  • mysql-connector-java-5.1.37-bin.jar driver file 5.1 Class is not required after 6 Forname ("com.mysql.jdbc.Driver") can also get a connection directly. Reason: jdbc4 has been used since jdk5, so it is no longer necessary to explicitly call class Forname() registers the driver, but automatically calls meta-inf \ services \ Java. Inf under the driver jar package sql. Register the class name in the driver text
/**
* On the basis of mode 4, the configuration file is used for connection, which is more flexible
*/
public void connect05() throws IOException, ClassNotFoundException, SQLException {
   // Read information from configuration file
   Properties properties = new Properties();
   properties.load(new FileInputStream("src\\mysql.properties"));
   String user = properties.getProperty("user");
   String password = properties.getProperty("password");
   String driver = properties.getProperty("driver");
   String url = properties.getProperty("url");

   // Load the class information, automatically register the driver and obtain the connection
   Class.forName(driver);
   Connection connection = DriverManager.getConnection(url, user, password);
}

828. ResultSet bottom layer

  • ResultSet: indicates the result set of the data table read from the database. The ResultSet object maintains a cursor pointing to the current data row. Initially, the cursor is positioned before the first line. It has a next method to move the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it often uses a while loop to traverse the result set
  • com. mysql. jdbc. There is a rowData (Interface) type field under the jdbc42 resultset class. There is an ArrayList type collection rows in the rowData, and there is an internalRowData of byte [] type in the rows. Where the data is really stored

829. SQL injection

  • Statement object, which is used to execute static SQL statements and return the generated results
  • There are three ways to operate the database after the connection is established:
  1. Statement: SQL injection exists
  2. PreparedStatement: preprocessing
  3. CallableStatement: used to execute database stored procedures
  • SQL injection is to use some systems to inject illegal SQL statement segments or commands into the data input by users without sufficient inspection of the data input by users, so as to maliciously attack the database
package p823;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

/**
* @author Spring-_-Bear
* @version 2021-11-09 09:48
*/
public class SqlInjection {
   public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
       // Get the user name and password that the user wants to query
       // Input userName = 1' or
       // Input pwd = or '1' = '1
       Scanner scanner = new Scanner(System.in);
       System.out.print("Input the name that you want to query:");
       String userName = scanner.nextLine();
       System.out.print("Input the password that you want to query:");
       String pwd = scanner.nextLine();

       // Load profile
       Properties properties = new Properties();
       properties.load(new FileInputStream("config\\temp.properties"));

       // Load the driver class information and automatically register the driver
       Class.forName(properties.getProperty("driver"));
       // Get connection
       Connection connection = DriverManager.getConnection(properties.getProperty("url"), properties);
       Statement statement = connection.createStatement();

       String select = "SELECT * FROM admin WHERE name='" + userName + "' AND pwd= '" + pwd + "'";
       ResultSet resultSet = statement.executeQuery(select);
       while (resultSet.next()) {
           userName = resultSet.getString(1);
           pwd = resultSet.getString(2);
           System.out.println(userName + "\t" + pwd);
       }

       resultSet.close();
       statement.close();
       connection.close();
   }
}

830. Statement

831. Preprocessing query

  • The parameters in the SQL statement executed by PreparedStatement are represented by question marks (?), and the setXxx() method of PreparedStatement object is called to set these parameters. The setXxx() method has two parameters. The first parameter is the index of the parameter in the SQL statement to be set, starting from 1. The second parameter is to set the value of the parameter in the SQL statement
  • Benefits of pretreatment:
String select = "SELECT * FROM admin WHERE name = ? AND pwd= ?";
// SQL statement preprocessing
PreparedStatement preparedStatement = connection.prepareStatement(select);
preparedStatement.setString(1, userName);
preparedStatement.setString(2, pwd);

// Execute the SQL statement to get the result set
ResultSet resultSet = preparedStatement.executeQuery();

832. Pretreatment DML

833. JDBC API

Interface nameMethod namefunction
ConnectioncreateStatement()Create an object that executes a static SQL statement
createPreparedStatement(sql)Get SQL statement preprocessing object
StatementexecuteUpdate(sql)Execute the DML statement and return the number of affected rows
executeQuery(sql)Execute DQL statement and return result set
execute(sql)Execute any SQL statement and return a Boolean value
PreparedStatementexecuteUpdate(sql)Execute the DML statement and return the number of affected rows
executeQuery(sql)Execute DQL statement and return result set
execute(sql)Execute any SQL statement and return a Boolean value
setXxx(index,value)Set values in SQL statements
setObject(index,value)Set values in SQL statements
ResultSetnext()Move down one row and return false at the end of the table
previous()Move up one line and return false to the header
getXxx(index || colLabel)Gets the value of the specified column
getObject(index || colLabel)Gets the value of the specified column

834. JDBC Utils development

package utils;


import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
* Database connection and resource closing tools
*
* @author Spring-_-Bear
* @version 2021-11-09 11:40
*/
public class JdbcUtils {
   private static String driver;
   private static String url;
   private static String user;
   private static String password;
   private static String path = "config\\temp.properties";

   /**
    * Read file information and initialize fields
    */
   static {
       Properties properties = new Properties();
       try {
           properties.load(new FileInputStream(path));
           driver = properties.getProperty("driver");
           url = properties.getProperty("url");
           user = properties.getProperty("user");
           password = properties.getProperty("password");
       } catch (IOException e) {
           // In actual development, such compilation exceptions will be converted into running exceptions, which can be handled by the caller, which is more convenient
           throw new RuntimeException(e);
       }
   }

   /**
    * Get a connection to the database
    *
    * @return Database connection object
    */
   public static Connection getConnection() {
       try {
           return DriverManager.getConnection(url, user, password);
       } catch (SQLException e) {
           // In actual development, such compilation exceptions will be converted into running exceptions, which can be handled by the caller, which is more convenient
           throw new RuntimeException(e);
       }
   }

   /**
    * Close corresponding resources
    *
    * @param resultSet  none
    * @param statement  none
    * @param connection none
    */
   public static void close(ResultSet resultSet, Statement statement, Connection connection) {
       try {
           if (resultSet != null) {
               resultSet.close();
           }
           if (statement != null) {
               statement.close();
           }
           if (connection != null) {
               connection.close();
           }
       } catch (SQLException e) {
           // In actual development, such compilation exceptions will be converted into running exceptions, which can be handled by the caller, which is more convenient
           throw new RuntimeException(e);
       }
   }
}

835. JDBC Utils DML

836. JDBC Utils query

837. Introduction to services

  • In the JDBC program, when a Connectioon object is created, the transaction is automatically committed by default: each time an SQL statement is executed, if the execution is successful, it will be automatically committed to the database instead of rolling back
  • You can call the setAutoCommit(false) method of the Connection interface to cancel the auto commit transaction
  • After all the SQL statements are executed successfully, the commit() method is called to commit the transaction. When one of the operations fails or an exception occurs, the rollback() method is called to roll back the transaction

838. Transaction processing

public void transaction() {
   Connection connection = null;
   PreparedStatement preparedStatement = null;
   String sub = "UPDATE account SET balance = balance - 100 WHERE id = 1";
   String add = "UPDATE account SET balance = balance + 100 WHERE id = 2";

   try {
       // Get connection
       connection = JdbcUtils.getConnection();
       // Turn off auto commit to turn on transactions
       connection.setAutoCommit(false);
       // Execute SQL
       preparedStatement = connection.prepareStatement(add);
       preparedStatement.executeUpdate();
       int temp = 1 / 0;
       preparedStatement = connection.prepareStatement(sub);
       preparedStatement.executeUpdate();
       // Commit transaction
       connection.commit();
       System.out.println("All SQL The operation is successful. Commit the transaction!");
   } catch (SQLException | ArithmeticException e) {
       try {
           // If an exception occurs, undo the operation and roll back the transaction
           System.out.println("Exception occurred during program execution, roll back all operations!!!");
           connection.rollback();
       } catch (SQLException ex) {
           ex.printStackTrace();
       }
       e.printStackTrace();
   } finally {
       JdbcUtils.close(null, preparedStatement, connection);
   }
}

839. Batch applications

  • When you need to insert or update records in batches, you can use the batch update mechanism of Java, which allows multiple statements to be submitted to the database for batch processing at one time. Generally, it is more efficient than submitting processing alone
Method namefunction
addBatch()Add SQL statements or parameters that require batch processing
executeBatch()Batch send execution
clearBatch()Empty batch package
  • When JDBC connects to MySQL, if batch processing is required, you need to add parameters to the url:
url = "jdbc:mysql://localhost:3306/temp?rewriteBatchedStatements=true"
  • Batch processing is often used together with PreparedStatement, which can not only reduce the compilation times, but also reduce the running times, and greatly improve the efficiency
preparedStatement.addBatch();
if (i % 1000 == 0) {
   preparedStatement.executeBatch();
   preparedStatement.clearBatch();
}

840. Batch source code analysis

/**
* The first time an ArrayList < elementdata > is created
* elementData => Object[] The preprocessed SQL statements will be stored
* When the elementDate is full, it will be expanded by 1.5 times
* When the specified capacity is reached, it will be sent to MySQL for execution
* Batch processing will reduce the network overhead of sending SQL statements and reduce the number of compilations, so as to improve efficiency
* @throws SQLException none
*/
public void addBatch() throws SQLException {
   synchronized(this.checkClosed().getConnectionMutex()) {
       if (this.batchedArgs == null) {
           this.batchedArgs = new ArrayList();
       }

       for(int i = 0; i < this.parameterValues.length; ++i) {
           this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);
       }

       this.batchedArgs.add(new com.mysql.jdbc.PreparedStatement.BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));
   }
}

841. Analysis of disadvantages of traditional links

  • The traditional JDBC database Connection is obtained by using DriverManager. Each time a Connection is established to the database, the Connection needs to be loaded into memory, and then the IP address, user name Whether the password (time-consuming 0.05s ~ 1s) is correct. When you need to connect to the database, you will request a Connection from the database. Frequent request operations will occupy too many system resources and easily cause the server to crash
  • Every time the database connection is used, it must be disconnected in time. If the program fails to close normally due to exceptions, it will lead to database memory leakage and eventually database crash and restart
  • The traditional method of obtaining connections cannot control the number of connections created. If there are too many connections, it may also lead to memory leakage and MySQL crash

842. Principle of database connection pool

  • Put a certain number of connections in the buffer pool in advance. When you need to establish a database connection, just take one from the "buffer pool" and return it to the buffer pool after use (and continuously open the connection with the database)
  • Database connection pool is responsible for allocating, managing and releasing database connections. It allows applications to reuse an existing database connection instead of re establishing one
  • When the number of connections requested by the application from the connection pool exceeds the maximum number of connections, these requests will be added to the waiting queue
  • The database connection pool of JDBC uses javax sql. DataSource is only an interface, and the specific implementation of the interface is left to the third party
Connection poolcharacteristic
C3P0The speed is relatively slow and the stability is good (hibernate and spring are used at the bottom)
DruidThe database connection pool provided by Alibaba integrates the advantages of DBCP, C3P0 and Proxool
ProxoolIt has the function of monitoring the status of the connection pool, and its stability is slightly worse than that of C3P0
BoneCPFast speed
DBCPThe speed is faster than C3P0, but unstable

843. C3P0 mode 1

// Create data source object
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
// Setting related information
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(pwd);
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setMaxPoolSize(50);
// Get connection
Connection connection = comboPooledDataSource.getConnection();
connection.close();

844. C3P0 mode 2

// Set c3p0 config Copy the XML file to the project src directory
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("spring_bear");
Connection connection = comboPooledDataSource.getConnection();
connection.close();

845. Druid connection pool

// Load profile
Properties properties = new Properties();
properties.load(new FileInputStream("config\\druid.properties"));
// Create a new connection pool
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// Get connection
Connection connection = dataSource.getConnection();
connection.close();

846. Druid tools

package utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

/**
* Druid Connection pool
*
* @author Spring-_-Bear
* @version 2021-11-09 22:17
*/
public class JdbcUtilsByDruid {
   static DataSource dataSource;
   static String path = "config\\druid.properties";

   static {
       Properties properties = new Properties();
       try {
           properties.load(new FileInputStream(path));
           dataSource = DruidDataSourceFactory.createDataSource(properties);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   /**
    * Returns a database connection from the Druid connection pool
    *
    * @return Connection
    * @throws SQLException none
    */
   public static Connection getConnection() throws SQLException {
       return dataSource.getConnection();
   }

   /**
    * Close the connection and return the connection to the connection pool
    *
    * @param resultSet  none
    * @param statement  none
    * @param connection none
    */
   public static void close(ResultSet resultSet, Statement statement, Connection connection) {
       try {
           if (resultSet != null) {
               resultSet.close();
           }
           if (statement != null) {
               statement.close();
           }
           if (connection != null) {
               connection.close();
           }
       } catch (SQLException e) {
           throw new RuntimeException(e);
       }
   }
}

847. ApDBUtils export

  • After closing the connection, the resultSet result set cannot continue to be used; However, many times we want to continue to use the queried data after closing the connection. The way the resultSet stores the query results is not conducive to data management; When obtaining data from the resultSet result set, the operation method is not clear enough, and the getXxx() method is error prone and ambiguous
  • Define a class that corresponds to the fields of the database table one by one. Such a class is generally called JavaBean or PoJo or Domain
  • Encapsulate the field value of the returned result set into the object of the user-defined class, and put several such objects into the set to directly access the set, so as to obtain the query results of the database table

848. Complete the packaging in a native way

849. ApDBUtils query

  • Commons dbutils is an open source JDBC tool class provided by Apache organization. It encapsulates JDBC. Using dbutils can greatly simplify the amount of JDBC coding
  • QueryRunner class encapsulates the execution of SQL and is thread safe. It can add, delete, modify, query and batch processing
  • The resultsethandler interface is used to handle Java sql. Resultset, which converts the queried data into another form
Interface namefunction
ArrayHandlerConverts the first row of data in the result set to an array of objects
ArrayListHandlerConvert each row in the result set into an array and store it in the List
BeanHandlerEncapsulate the first row of data in the result set into a corresponding JavaBean instance
BeanListHandlerEncapsulate each row of data in the result set into the corresponding JavaBean instance and store it in the List
ColumnListHandlerStore a column of data in the result set in the List
KeyedHandler(name)Encapsulate each row of data into a map, and then store the map into another map
MapHandlerEncapsulate the data of the first row of the result set into the Map. key is the column name and value is the corresponding value
MapListHandlerEncapsulate each row of data in the result set into a Map and then store it in a List
public void testApache() throws SQLException {
   // Get connection
   Connection connection = JdbcUtilsByDruid.getConnection();
   // Get the query object implemented by Apache
   QueryRunner queryRunner = new QueryRunner();
   String select = "SELECT * FROM cost WHERE id >= ? AND id <= ?";
   List<Fishing> fishings = queryRunner.query(connection, select, new BeanListHandler<>(Fishing.class), 1, 10);
   for (Fishing fishing : fishings) {
       System.out.println(fishing);
   }
   JdbcUtilsByDruid.close(null, null, connection);
}

850. ApDBUtils source code analysis

  • When creating a JavaBean class, the data type of the field of the class is forced to use the wrapper class corresponding to the eight basic data types, because the field value in the MySQL database table may be empty, and only the reference data type of Java has NULL value

851. ApDBUtils query 2

852. ApDBUtilsDML

853. BasicDAO issues

  • Apache dbutils + Druid connectionpoll simplifies JDBC development, but it still has the following shortcomings:
  1. SQL statements are fixed and cannot be passed in through parameters. They are not universal and need to be improved to facilitate CRUD operation
  2. For the query SELECT operation, if there is a return value and the return type cannot be determined, it needs to be solved by using generics
  3. In the future, there will be many tables in the database, and the business requirements are complex. It is impossible to rely on only one Java class
  • Solution: a JavaBean class is designed for each table, and a class Dao specially operating it is designed for each database table. The common parts of all specific Dao classes are abstracted from the parent class BasciDao, so as to make better use of polymorphism to complete functions
  • DAO (data access object): an object that accesses database data
  • When creating a JavaBean class, you must give a parameterless constructor to facilitate the reflection mechanism to obtain this class information

854. BasicDAO analysis

855. BasicDAO implementation 1

package dao.dao;


import dao.utils.JdbcUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
* Encapsulates operations on database tables
*
* @author Spring-_-Bear
* @version 2021-11-10 11:03
*/
public class BasicDao<T> {
   QueryRunner queryRunner = new QueryRunner();

   /**
    * DML operation
    *
    * @param sql    SQL sentence
    * @param params SQL Value of parameter in
    * @return Number of rows affected
    */
   public int update(String sql, Object... params) {
       Connection connection = null;
       try {
           connection = JdbcUtilsByDruid.getConnection();
           return queryRunner.update(connection, sql, params);
       } catch (SQLException e) {
           // The compilation exception is converted into a running exception for the convenience of the caller
           throw new RuntimeException(e);
       } finally {
           JdbcUtilsByDruid.close(null, null, connection);
       }
   }

   /**
    * Query multiple rows
    *
    * @param sql    SQL sentence
    * @param clazz  Class object of concrete class
    * @param params SQL Concrete value in statement
    * @return The result set queried from the database is encapsulated in ArrayList
    */
   public List<T> getMultiRows(String sql, Class<T> clazz, Object... params) {
       Connection connection = null;
       try {
           connection = JdbcUtilsByDruid.getConnection();
           return queryRunner.query(connection, sql, new BeanListHandler<T>(clazz), params);
       } catch (SQLException e) {
           // The compilation exception is converted into a running exception for the convenience of the caller
           throw new RuntimeException(e);
       } finally {
           JdbcUtilsByDruid.close(null, null, connection);
       }
   }

   /**
    * Query a row
    *
    * @param sql    SQL sentence
    * @param clazz  Class object of concrete class
    * @param params SQL Concrete value in statement
    * @return A row of data queried from the database
    */
   public T getOneRow(String sql, Class<T> clazz, Object... params) {
       Connection connection = null;
       try {
           connection = JdbcUtilsByDruid.getConnection();
           return queryRunner.query(connection, sql, new BeanHandler<T>(clazz), params);
       } catch (SQLException e) {
           // The compilation exception is converted into a running exception for the convenience of the caller
           throw new RuntimeException(e);
       } finally {
           JdbcUtilsByDruid.close(null, null, connection);
       }
   }

   /**
    * Query single row and single column
    *
    * @param sql    SQL sentence
    * @param params SQL Concrete value in statement
    * @return A cell data queried from the database
    */
   public Object getOneObj(String sql, Object... params) {
       Connection connection = null;
       try {
           connection = JdbcUtilsByDruid.getConnection();
           return queryRunner.query(connection, sql, new ScalarHandler(), params);
       } catch (SQLException e) {
           // The compilation exception is converted into a running exception for the convenience of the caller
           throw new RuntimeException(e);
       } finally {
           JdbcUtilsByDruid.close(null, null, connection);
       }
   }
}

856. BasicDAO implementation 2

857. JDBC connection pool

Keywords: Java Database MySQL

Added by aubeasty on Thu, 23 Dec 2021 16:10:27 +0200