Grupo de conexiones Java-JDBC+C3P0

1.JDBC

Conector de base de datos Java

JDBC es la abreviatura de Java Database Connection Technology, que brinda la capacidad de conectarse a varias bases de datos de uso común.

2. Plantilla de programación JDBC

1. Cargue el controlador JDBC

​ Class.forName(clase de controlador JDBC);

  1. Crear una conexión con la base de datos.

    Conexión con=DriverManager.getConnection(URL, nombre de usuario de la base de datos, contraseña);

    URL: tipo de base de datos, donde se encuentra el servicio de base de datos, recuerde la dirección IP, número de puerto del servicio, almacén de datos predeterminado, parámetros de configuración

  2. Cree un objeto de declaración a través del objeto de conexión para enviar la declaración SQL y obtener el resultado devuelto

  3. Procese el conjunto de resultados, el conjunto de resultados de la consulta es ResultSet, y la adición, eliminación, modificación y consulta devuelven un valor int para expresar el número de filas afectadas

  4. liberar recursos

1. Cómo descargar el paquete del controlador jdbc

  1. https://mvnrepository.com/
  2. Escribe mysql en el cuadro de búsqueda
  3. Encontré el nombre: MySQL Connector/J
  4. Seleccione la versión correspondiente
  5. Haga clic en el número de versión para ingresar y podrá elegir jar para descargar o importar mediante otros métodos.

2. Código de caso

import java.sql.*;

public class Test {
    
    

    public static void main(String[] args) {
    
    

        //1. 注册驱动
        try {
    
    
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            System.err.println("mysql驱动加载异常!");
            e.printStackTrace();
        }

        //2. 连接数据库
        String url = "jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
        String userName = "root";
        String pwd = "cxk666";
        Connection connection = null;
        try {
    
    
            connection = DriverManager.getConnection(url,userName,pwd);
        } catch (SQLException e) {
    
    
            System.err.println("数据库连接出现异常!");
            e.printStackTrace();
        }

        //3. 操作数据库
        Statement statement = null;
        ResultSet resultSet = null;
        try {
    
    
            statement = connection.createStatement();
            //查询返回结果集
            resultSet = statement.executeQuery("select * from student");
        } catch (SQLException e) {
    
    
            System.err.println("操作数据库异常!");
            e.printStackTrace();
        }

        //4. 处理数据
        try{
    
    
            while(resultSet.next()){
    
    
                String s_id = resultSet.getString("s_id");
                System.out.print(s_id+"\t");

                String s_name = resultSet.getString("s_name");
                System.out.print(s_name+"\t");
                System.out.println();
            }
        }catch (SQLException e){
    
    
            System.err.println("数据处理异常");
            e.printStackTrace();
        }


        //5. 关闭资源
        try {
    
    
            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
    
    
            System.err.println("连接关闭异常");
            e.printStackTrace();
        }

    }

}

nombre del método ilustrar
ResultSet ejecutarQuery (cadena sql ) Ejecute la consulta SQL y obtenga el objeto ResultSet
int ejecutarActualización (cadena sql) Se pueden realizar operaciones de inserción, eliminación, actualización y otras, y el valor de retorno es el número de filas afectadas por la operación.
ejecución booleana (cadena sql **) ** Puede ejecutar cualquier instrucción SQL y luego obtener un valor booleano que indique si se debe devolver ****ResultSet

3. El método JDBC-execute ejecuta las declaraciones de adición, eliminación, modificación y consulta.

//execute 方法执行:增、删、改返回的都是false,执行查询语句返回的是true
boolean execute = statement.execute(sql);//一般不用于查询
/* 注册驱动、创建连接的方法和2.代码案例中一致 **/

//3. 插入数据
     String sql = "INSERT INTO `student` ( `s_id`, `s_name`, `s_birth`, `s_sex` )\n" +
             "VALUES\n" +
             "\t( '09', '旭宝宝', '1990-01-01', '男' );\n";

     //3.1 获取statement对象
     Statement statement = null;
     try {
     
     
         statement = connection.createStatement();

         // execute 方法执行:增、删、改返回的都是false,执行查询语句返回的是true
         boolean execute = statement.execute(sql);

         System.out.println(execute);

     } catch (SQLException e) {
     
     
         System.err.println("数据插入错误!");
         e.printStackTrace();
     }

/* 关闭连接操作省略 */

4. JDBC-executeUpdate ejecuta declaraciones de adición, eliminación y modificación

// executeUpdate:返回值是受影响的行数,可以使用在增、删、改语句,不能使用于查询语句
int i = statement.executeUpdate(sql);
//3. 更新数据
        String sql = "update student set s_name='卢本伟' where s_sex='人妖';";

        //3.1 获取statement对象
        Statement statement = null;
        try {
            statement = connection.createStatement();

            // executeUpdate:返回值是受影响的行数,可以使用在增、删、改语句,不能使用于查询语句
            int i = statement.executeUpdate(sql);

            System.out.println(i);

        } catch (SQLException e) {
            System.err.println("数据插入错误!");
            e.printStackTrace();
        }

5. Método JDBC-query declaración-executeQuery

// executeQuery:只能运用于查询语句,返回的是查询结果集
ResultSet resultSet = statement.executeQuery(sql);
 //3. 操作数据库
        Statement statement = null;
        ResultSet resultSet = null;
        try {
    
    
            statement = connection.createStatement();
            //查询返回结果集
            resultSet = statement.executeQuery("select * from student");
        } catch (SQLException e) {
    
    
            System.err.println("操作数据库异常!");
            e.printStackTrace();
        }

        //4. 处理数据
        try{
    
    
            while(resultSet.next()){
    
    
                String s_id = resultSet.getString("s_id");
                System.out.print(s_id+"\t");

                String s_name = resultSet.getString("s_name");
                System.out.print(s_name+"\t");
                System.out.println();
            }
        }catch (SQLException e){
    
    
            System.err.println("数据处理异常");
            e.printStackTrace();
        }

5.1 Método de operación del objeto ResultSet

nombre del método ilustrar
booleano siguiente() Mueva el cursor hacia abajo una línea desde la posición actual
booleano anterior() Mover el cursor hacia arriba una línea desde la posición actual
cierre vacío() Cierre el objeto ****ResultSet

Cómo obtener campos:

Obtener tipo de datos (nombre de campo \ valor del número de serie del campo)

Método de valor:
1. Orden de los campos: 1 representa la primera columna

2. Valor del nombre del campo: cómo escribir la proyección en el resultado de la consulta y cómo escribir el nombre del campo

Los tipos de datos comunes de MySQL coinciden con los métodos JDBC:

getInt : int\tinyint\bigint

getDouble: flotante\doble\deccamial

getString: char\varchar\text\longText

getDate: fecha\hora\fechahora\marca de tiempo (java.sql.Date extiende java.util.Date)

while(resultSet.next()){
    
    
    
                String string = resultSet.getString("s_name");

                System.out.println(string);
            }

3. Problema de inyección SQL

¿Qué es la inyección SQL?

Inyecte signos de puntuación o símbolos especiales en los parámetros para que el backend java ejecute excepciones de declaraciones SQL

Problemas de seguridad existentes:

1. 数据泄露和遗失
1. 会让数据库操作全部崩溃
// 输入用户名和密码
        String sys_userName = "yyy";
        String sys_pwd = "' or 1=1 or ''='";

        //3. 操作数据库
        Statement statement = null;
        ResultSet resultSet = null;

        String sql = "select * from sys_user where userName = '"+sys_userName+"' and pwd='"+sys_pwd+"'";
        
        //select * from sys_user where userName = 'yyy' and pwd='' or 1=1 or ''=''
        
        System.out.println("sql:"+sql);
        try {
            statement = connection.createStatement();
            //查询返回结果集
            resultSet = statement.executeQuery(sql);
        } catch (SQLException e) {
            System.err.println("操作数据库异常!");
            e.printStackTrace();
        }

Solución al problema de inyección SQL

1. Solución: talla única

Está prohibido permitir a los usuarios ingresar en el sistema: caracteres especiales como espacios en blanco, tabulaciones, signos de puntuación, etc.

2. Solución: interfaz PreparedStatement

Instrucciones:

  1. El objeto de conexión llama al método prepareStatement para crear un objeto PreparedStatement: tenga en cuenta que llamar al método prepareStatement envía SQL al objeto para su precompilación.
  2. Al insertar parámetros, asegúrese de que haya un marcador de posición en la cadena SQL y agregue parámetros de acuerdo con el orden de los marcadores de posición.
  3. Reglas para llamar al método set: establecer tipo de datos (número de marcador de posición, valor de parámetro) Nota: llame al método set correspondiente según el tipo de datos de la base de datos, y el número del marcador de posición comienza desde 1 de izquierda a derecha
  4. Ejecutando sql: si agrega, elimina o modifica, se llama al método ejecutarUpdate o ejecutar sin parámetros ; se llama al método ejecutarQuery sin parámetros para realizar consultas
// 输入用户名和密码
        String sys_userName = "yyy";
        String sys_pwd = "' or 1=1 or ''='";

        //3. 操作数据库
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        String sql = "select * from sys_user where userName = ? and pwd= ?";
        try {
    
    
            //1. 创建 PreparedStatement 对象- 把sql提交给对象进行预编译
            statement = connection.prepareStatement(sql);

            //2. 参数插入
            statement.setString(1,sys_userName);// 给第一个站位符填值
            statement.setString(2,sys_pwd);// 给第二个站位符填值

            //查看sql
            String s = statement.toString();
            System.out.println("sql:"+s);

            //查询返回结果集 - 调用无参方法-不需要传入sql
            resultSet = statement.executeQuery();
        } catch (SQLException e) {
    
    
            System.err.println("操作数据库异常!");
            e.printStackTrace();
        }

4. La interfaz PreparedStatement se utiliza en el proceso de desarrollo y no se utilizará el método de interfaz Statement.

5. Encapsulación de herramientas JDBC

código java

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

/**
 * JDBC工具类
 */
public class MyJDBCUtil {
    
    

    private static String userName;//数据库用户名
    private static String pwd;//数据库密码
    private static String connectionURL;//数据库连接URL地址

    private MyJDBCUtil(){
    
    }

    static{
    
    
        //1.驱动注册
        try {
    
    
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            System.err.println("mysql驱动加载异常!");
            e.printStackTrace();
        }

        //2. 从配置文件中读取用户名和密码配置
        InputStream is = MyJDBCUtil.class.getResourceAsStream("database.properties");
        Properties properties = new Properties();
        try {
    
    
            properties.load(is);
        } catch (IOException e) {
    
    
            System.err.println("mysql配置加载异常!");
            e.printStackTrace();
        }

        String p_userName = (String) properties.get("userName");
        String p_pwd = (String) properties.get("pwd");
        String p_mysqlURL = (String) properties.get("mysqlURL");

        userName = p_userName;
        pwd = p_pwd;
        connectionURL = p_mysqlURL;
    }

    /**
     * 获取数据库连接
     * @return 数据库连接对象 Connection
     */
    public static Connection getConnection(){
    
    

        Connection connection = null;
        try {
    
    
            connection = DriverManager.getConnection(connectionURL, userName, pwd);
        } catch (SQLException e) {
    
    
            System.err.println("mysql连接异常!");
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 查询之后的关闭操作
     * @param statement 操作对象
     * @param resultSet 查询结果集
     * @param connection 连接对象
     */
    public static void close(ResultSet resultSet,Statement statement,Connection connection){
    
    
        try {
    
    
            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
    
    
            System.err.println("连接关闭异常");
            e.printStackTrace();
        }
    }

    /**
     * 增删改之后关闭
     * @param statement 操作对象
     * @param connection 连接对象
     */
    public static void close(Statement statement,Connection connection){
    
    
        try {
    
    
            statement.close();
            connection.close();
        } catch (SQLException e) {
    
    
            System.err.println("连接关闭异常");
            e.printStackTrace();
        }
    }

}

archivo de configuración

userName = root
pwd = cxk666
mysqlURL = jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai

6. Requisitos de estructura del kit de desarrollo a nivel empresarial

El propósito de la distinción: permitir a los desarrolladores aclarar los recursos de contenido del proyecto (herramientas, códigos comerciales, interfaces, dependencias relacionadas)

src
    -- 项目根包:一般是公司域名反写
    	-- 业务包1
    		-- 代码功能包
    	-- 业务包2
    
src
    com.huawei   -- 根目录包结构
    	sys  -- 系统管理业务包
    		utils -- 系统管理业务中的工具类包
    		service -- 系统管理业务中的接口
    			impl -- 系统管理业务中的接口的实现类
    	student
    		...

7. Objeto VO\DTO\BO\PO

VO (Ver objeto): objeto de vista, que se utiliza para guardar los datos pasados ​​por el componente de vista o el objeto que pasa datos a la vista.

DTO (Objeto de transferencia de datos): aceite universal, adecuado para todos los procesos de transferencia de datos entre servicios

BO (Business Object): objeto de negocio, utilizado para transferir valores entre negocios de código java.

PO (objeto persistente): objeto persistente, el objeto está en correspondencia uno a uno con los campos de la base de datos y el objeto modificado describe los datos de la tabla de la base de datos.

/* 对应数据库student表的po对象 */
package com.huawei.sys.POs;

import java.io.Serializable;
import java.util.Date;

public class StudentPO implements Serializable {
    
    

    private String sID;
    private String sName;
    private Date sBirth;
    private String sSex;

    public String getsID() {
    
    
        return sID;
    }

    public void setsID(String sID) {
    
    
        this.sID = sID;
    }

    public String getsName() {
    
    
        return sName;
    }

    public void setsName(String sName) {
    
    
        this.sName = sName;
    }

    public Date getsBirth() {
    
    
        return sBirth;
    }

    public void setsBirth(Date sBirth) {
    
    
        this.sBirth = sBirth;
    }

    public String getsSex() {
    
    
        return sSex;
    }

    public void setsSex(String sSex) {
    
    
        this.sSex = sSex;
    }
}

8. Grupo de conexiones JDBC

8.1 Grupo de conexiones manuales

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

/**
 * JDBC工具类
 */
public class MyJDBCUtil {

    private static String userName;//数据库用户名
    private static String pwd;//数据库密码
    private static String connectionURL;//数据库连接URL地址

    private static LinkedList<Connection> connectorPool; // 连接池

    private MyJDBCUtil(){}

    static{
        //1.驱动注册
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.err.println("mysql驱动加载异常!");
            e.printStackTrace();
        }

        //2. 从配置文件中读取用户名和密码配置
        InputStream is = MyJDBCUtil.class.getResourceAsStream("database.properties");
        Properties properties = new Properties();
        try {
            properties.load(is);
        } catch (IOException e) {
            System.err.println("mysql配置加载异常!");
            e.printStackTrace();
        }

        String p_userName = (String) properties.get("userName");
        String p_pwd = (String) properties.get("pwd");
        String p_mysqlURL = (String) properties.get("mysqlURL");
        int initPoolSize = Integer.valueOf((String) properties.get("initPoolSize"));

        userName = p_userName;
        pwd = p_pwd;
        connectionURL = p_mysqlURL;

        //初始化连接池
        connectorPool = (LinkedList<Connection>) Collections.synchronizedList(new LinkedList<Connection>());
        for(int i=0;i<initPoolSize;i++){
            Connection connection = null;
            try {
                connection = DriverManager.getConnection(connectionURL, userName, pwd);
            } catch (SQLException e) {
                System.err.println("mysql连接异常!");
                e.printStackTrace();
            }
            connectorPool.addLast(connection);
        }

        //启动一个线程监测每个连接是否正常能够访问数据库
        new Thread(()->{
            
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                for(int i=0;i<initPoolSize;i++){
                    Connection connection = connectorPool.get(i);
                    Statement statement = null;
                    try {
                        statement = connection.createStatement();
                        statement.execute("select count(*) from dual");
                    } catch (SQLException e) {
                        Connection newConnection = null;
                        try {
                            newConnection = DriverManager.getConnection(connectionURL, userName, pwd);
                        } catch (SQLException e2) {
                            System.err.println("mysql连接异常!");
                            e2.printStackTrace();
                        }
                        connectorPool.remove(i);
                        connectorPool.addLast(newConnection);
                    }
                    
                }
            }
            
        },"poolThread").start();
        // 使用sql:select count(*) from dual; 监测与服务器的连接是否正常,以及测试速度

    }

    /**
     * 获取数据库连接
     * @return 数据库连接对象 Connection
     */
    public static synchronized Connection getConnection(){
        
        Connection last = connectorPool.getLast();
        if(last == null){
            System.err.println("连接池连接暂无,通过创建连接获取新接连");
            Connection connection = null;
            try {
                connection = DriverManager.getConnection(connectionURL, userName, pwd);
            } catch (SQLException e) {
                System.err.println("mysql连接异常!");
                e.printStackTrace();
            }
            return connection;
        }

        return last;

    }

    /**
     * 查询之后的关闭操作
     * @param connection 连接对象
     */
    public static synchronized void close(Connection connection){
        connectorPool.add(connection);
    }

}

8.2 Uso de la versión mysql del grupo de conexiones C3P0

1. Primero descargue el paquete jar de c3p0: paquete mchange-commons-java y paquete c3p0

2. Inicialice el objeto de fuente de datos del grupo de conexiones:

​ ComboPooledDataSource dataSource = nuevo ComboPooledDataSource();

3. Utilice C3P0

8.2.1 Inicializar el grupo de conexiones en el bloque de código estático (no recomendado)

package com.huawei.sys.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * C3P0连接池工具类
 */
public class MyC3P0Util {
    
    
    // 连接池数据源对象
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    private MyC3P0Util(){
    
    }

    static{
    
    
        //1. 注册驱动
        try {
    
    
            dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        } catch (PropertyVetoException e) {
    
    
            System.err.println("驱动注册异常");
            e.printStackTrace();
        }
        //2. 设置url 用户名 密码
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai");
        dataSource.setUser("root");
        dataSource.setPassword("cxk666");
    }

    /**
     * C3P0连接池-获取连接的方法
     * @return
     */
    public static Connection getConnection(){
    
    
        Connection connection = null;
        try {
    
    
            connection = dataSource.getConnection();
        } catch (SQLException e) {
    
    
            System.err.println("获取连接异常!");
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * C3P0归还连接的方法
     */
    public static void close(Connection con){
    
    
        try {
    
    
            con.close();// C3P0中并不会关闭,是将连接归还到连接池(代理模式:mchange-commons)
        } catch (SQLException e) {
    
    
            System.err.println("归还连接异常!");
            e.printStackTrace();
        }
    }

}

8.2.2 Utilice el archivo de configuración de propiedades para configurar la inicialización del grupo de conexiones C3P0 (recomendado)

Ventajas: separación de configuración y código, y c3p0 completa automáticamente la configuración sin escribir manualmente ningún código de inicialización

Contenido del archivo de configuración

Nota: El nombre del archivo de configuración debe llamarse: c3p0.properties y debe colocarse en el directorio src, no en la estructura del paquete.

c3p0.driverClass=com.mysql.cj.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
c3p0.user=root
c3p0.password=cxk666
# 初始化连接池的大小
c3p0.initialPoolSize=3  
# 最大连接时间
c3p0.maxIdleTime=60 
# 最大连接池大小
c3p0.maxPoolSize=20 

Contenido del código de clase de herramienta Java

package com.huawei.sys.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * C3P0连接池工具类
 */
public class MyC3P0Util {
    
    
    // 连接池数据源对象
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    private MyC3P0Util(){
    
    }

    //不再需要静态代码块了,当项目启动,数据源对象初始化时会自动找到配置文件初始化连接池

    /**
     * C3P0连接池-获取连接的方法
     * @return
     */
    public static Connection getConnection(){
    
    
        Connection connection = null;
        try {
    
    
            connection = dataSource.getConnection();
        } catch (SQLException e) {
    
    
            System.err.println("获取连接异常!");
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * C3P0归还连接的方法
     */
    public static void close(Connection con){
    
    
        try {
    
    
            con.close();// C3P0中并不会关闭,是将连接归还到连接池(代理模式:mchange-commons)
        } catch (SQLException e) {
    
    
            System.err.println("归还连接异常!");
            e.printStackTrace();
        }
    }

}

8.2.3 Múltiples fuentes de datos utilizan el archivo de configuración -xml

¿Múltiples fuentes de datos?

​ Es posible que un proyecto requiera flexibilidad en múltiples configuraciones de bases de datos al mismo tiempo.

Nota: Solo se puede seleccionar uno de los métodos de configuración que utilizan propiedades y el método de configuración que utiliza xml.

Utilice la configuración xml: el nombre del archivo debe llamarse: c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 默认使用的数据源配置 -->
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/javatest?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai
        </property>
        <property name="user">root</property>
        <property name="password">cxk666</property>
    </default-config>

    <!-- 多数据源-其他数据源的配置方法 -->
    <!-- 其他数据源一定要指定name属性 -->
    <named-config name="tengxunyun" >
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://XXXXXXX:3306/XXXX?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai
        </property>
        <property name="user">XXXXX</property>
        <property name="password">XXXX</property>
    </named-config>

</c3p0-config>

Cuando varias fuentes de datos inicializan el objeto de fuente de datos:

 // 构造器中指定一个数据源的名称,对应的是xml文件中   named-config 标签的 name属性值
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("tengxunyun");

Usar caso de grupo de conexiones

public static void main(String[] args) throws SQLException {
    
    

        //1. 调用编写的工具类通过C3P0获取连接
        Connection connection = MyC3P0Util.getConnection();

        //2. 创建操作对象查询数据
        Statement statement = connection.createStatement();

        ResultSet set = statement.executeQuery("select s_name from student");

        while(set.next()){
    
    
            String s_name = set.getString("s_name");
            System.out.println(s_name);
        }

        //3. 归还连接(代理完成归还,并不是关闭连接)
        connection.close();//归还连接

    }

Supongo que te gusta

Origin blog.csdn.net/gjb760662328/article/details/129164590
Recomendado
Clasificación