当前位置: 首页 > news >正文

JDBC详解——增删改查(CRUD)、sql注入、事务、连接池

1. 概念:

  • Java DataBase Connectivity, Java 数据库连接, Java语言操作数据库

  • JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

  • 接口都有调用者和实现者,面向接口调用,面向接口写实现类,这都属于面向接口编程。

  • 为什么要面向接口编程?

  • 解耦合:降低程序的耦合性,提高程序的扩展力,多态就是典型的面向接口(面向抽象)编程,而不是面向具体编程。

  • image-20230215172306812

2. 快速入门:

  • 步骤:

  1. 导入驱动jar包 mysql-connector-java-8.0.w-bin.jar 1.复制mysql-connector-java-8.0.22-bin.jar到项目的lib目录下 2.右键-->Add As Library

  2. 注册驱动

  3. 获取数据库连接对象 Connection

  4. 定义sql

  5. 获取执行sql语句的对象 Statement

  6. 执行sql,接受返回结果

  7. 处理结果

  8. 释放资源

代码示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
public class Simple01 {public static void main(String[] args) throws ClassNotFoundException, SQLException {// 1. 导入驱动jar包 mysql-connector-java-8.0.w-bin.jar//      1.复制mysql-connector-java-8.0.22-bin.jar到项目的lib目录下//      2.右键-->Add As Library// 2. 注册驱动Class.forName("com.mysql.jdbc.Driver");//Class.forName("com.mysql.cj.jdbc.Driver");// 3. 获取数据库连接对象 ConnectionConnection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");//Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo?user=root&password=root");//Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbcDemo?user=root&password=root");
​// 4. 定义sqlString sql = "insert into student values (null,'赵六')";// 5. 获取执行sql语句的对象 StatementStatement statement = connection.createStatement();// 6. 执行sql,接受返回结果int count = statement.executeUpdate(sql);// 7. 处理结果System.out.println(count > 0 ? "插入成功" : "插入失败");// 8. 释放资源statement.close();connection.close();}
}

3. 详解各个对象:

3.1 DriverManager:驱动管理对象

  • 功能:

  1. 注册驱动:告诉程序该使用哪一个数据库驱动jar static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。 写代码使用: Class.forName("com.mysql.jdbc.Driver");

    查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块

     static {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException("Can't register driver!");}}
    //注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。
    //8.022数据库驱动程序改为:com.mysql.cj.jdbc.Driver
  2. 获取数据库连接:

    • 方法

      static Connection getConnection(String url, String user, String password) 
    • 参数:

      • url:指定连接的路径

      • 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称

      • 例子:jdbc:mysql://localhost:3306/jdbcDemo

        • 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据

        • 库名称,例子:jdbc:mysql:///jdbcDemo

  • user:用户名

  • password:密码

3.2 Connection:数据库连接对象

  • 功能:

    • 获取执行sql 的对象

    • Statement createStatement()

    • PreparedStatement prepareStatement(String sql)

  • 管理事务:

    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

    • 提交事务:commit()

    • 回滚事务:rollback()

3.3 Statement:数据库连接对象

  • 执行sql

    • boolean execute(String sql) :可以执行任意的sql 这个不常用 了解

    • int executeUpdate(String sql) :

    执行DML(insert、update、delete)语句、

    执行DDL (create,alter、drop)语句,很少用,都用sql语句创建。

    返回值:int count = statement.executeUpdate(sql);

    count是影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0 的则执行成功,反之,则失败。

  • ResultSet executeQuery(String sql) :

    执行DQL(select)语句

3.4 执行DML语句

  • Account表 添加一条记录

  • Account表 修改一条记录

  • Account表 删除一条记录

3.5 添加一条记录

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
public class SimpleInsert {public static void main(String[] args) {Connection connection = null;Statement statement = null;try {// 注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 获取数据库连接对象connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");// 获取执行sql语句对象 Statementstatement = connection.createStatement();// 定义sql 执行并接收返回结果String sql = "insert into account values(null,'王五' , 23000)";int count = statement.executeUpdate(sql);// 处理结果System.out.println(count > 0 ? "插入成功" : "插入失败");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {// 释放资源if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

3. 6 修改一条记录

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
public class SimpleUpdate {public static void main(String[] args) {Connection connection = null;Statement statement = null;try {// 注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 获取数据库连接对象connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");// 获取执行sql语句对象 Statementstatement = connection.createStatement();// 定义sql 执行并接收返回结果String sql = "update account set balance = 20000 where id = 2";int count = statement.executeUpdate(sql);// 处理结果System.out.println(count > 0 ? "修改成功" : "修改失败");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {// 释放资源if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

3.7 删除一条记录

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
public class SimpleDelete {public static void main(String[] args) {Connection connection = null;Statement statement = null;try {// 注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 获取数据库连接对象connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");// 获取执行sql语句对象 Statementstatement = connection.createStatement();// 定义sql 执行并接收返回结果String sql = "delete from account where id = 3";int count = statement.executeUpdate(sql);// 处理结果System.out.println(count > 0 ? "删除成功" : "删除失败");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {// 释放资源if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

3.8 执行DDL语句

代码示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
public class CreateTable05 {// DDL:数据定义语言:创建一个表、视图、操作列// DML:数据操作语言:对表进行增 删 改。insert delete update// DQL:数据查询语言:对表进行查询 select from where// DCL:数据控制语言:对数据库进行授权或者控制
​public static void main(String[] args) {Statement stmt = null;Connection conn = null;try {// 1.注册驱动// 2.定义sqlString sql = "create table student(id int , name varchar(20))";// 3.获取连接数据库的对象 Connectionconn = DriverManager.getConnection("jdbc:mysql:///DB_JDBC_01", "root", "root1234");// 4.获取操作sql的对象 Statementstmt = conn.createStatement();// 5.执行sql影响的行数int count = stmt.executeUpdate(sql);// 6.处理结果System.out.println(count);// DDL 返回结果就是0 不需要判断
​} catch (SQLException e) {e.printStackTrace();} finally {// 7.释放资源// stmt.close();if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

4 ResultSet:结果集对象,封装查询结果

4.1 ResultSet概述

  • boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),

  • 如果是最后一行末尾,则返回false,如果不是最后一行末尾则返回true

* getXxx(参数):获取数据

* Xxx:代表数据类型 如: int getInt() , String getString()

* 参数:

1. int:代表列的编号,从1开始 如: getString(1) getString(“name”)

2. String:代表列名称。 如: getDouble("balance") getDouble(1)

* 注意:

* 使用步骤:

1. 游标向下移动一行

2. 判断是否有数据

3. 获取数据

//循环判断游标是否是最后一行末尾。
while(rs.next()){
//获取数据
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}

4.2 执行DQL语句:

代码示例:

import java.sql.*;
​
public class SimpleSelect {public static void main(String[] args) {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {
​//  注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//  建立连接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");// 获取操作sql的对象 Statementstatement = connection.createStatement();// 定义sqlString sql = "select * from account ";
​// 执行sql影响的行数resultSet = statement.executeQuery(sql);
//            System.out.println(resultSet.next());// 处理结果// 循环判断游标是否是最后一行while (resultSet.next()) {
//                int id = resultSet.getInt("id");
//                String name = resultSet.getString("name");
//                double balance = resultSet.getDouble("balance");int id = resultSet.getInt(1);String name = resultSet.getString(2);double balance = resultSet.getDouble(3);System.out.println("id:" + id + "    " + "name:" + name + "     " + "balance:" + balance);}
​
​} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {// 释放资源if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}
​if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}
​if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}
​}}
​
}

4. 3 查询练习:

  • 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。

1. 定义Emp类

2. 定义方法 public List<Emp> findAll(){}

3. 实现方法 select * from emp;

代码示例:

-- 员工表
CREATE TABLE emp (id INT PRIMARY KEY, -- 员工idename VARCHAR(50), -- 员工姓名job_id INT, -- 职务idmgr INT , -- 上级领导joindate DATE, -- 入职日期salary DECIMAL(7,2) -- 工资
​
);
-- 添加员工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary) VALUES 
(1001,'孙悟空',4,1004,'2000-12-17','8000.00'),
(1002,'卢俊义',3,1006,'2001-02-20','16000.00'),
(1003,'林冲',3,1006,'2001-02-22','12500.00'),
(1004,'唐僧',2,1009,'2001-04-02','29750.00'),
(1005,'李逵',4,1006,'2001-09-28','12500.00'),
(1006,'宋江',2,1009,'2001-05-01','28500.00'),
(1007,'刘备',2,1009,'2001-09-01','24500.00'),
(1008,'猪八戒',4,1004,'2007-04-19','30000.00');
​
SELECT * FROM emp;
package com.whitecamellia.entity;
​
import java.util.Date;
​
public class Emp {private Integer id;private String eName;private Integer jobId;private Integer mgr;private Date joinDate;private Double salary;
​public Integer getId() {return id;}
​public void setId(Integer id) {this.id = id;}
​public String geteName() {return eName;}
​public void seteName(String eName) {this.eName = eName;}
​public Integer getJobId() {return jobId;}
​public void setJobId(Integer jobId) {this.jobId = jobId;}
​public Integer getMgr() {return mgr;}
​public void setMgr(Integer mgr) {this.mgr = mgr;}
​public Date getJoinDate() {return joinDate;}
​public void setJoinDate(Date joinDate) {this.joinDate = joinDate;}
​public Double getSalary() {return salary;}
​public void setSalary(Double salary) {this.salary = salary;}
​@Overridepublic String toString() {return "Emp{" +"id=" + id +", eName='" + eName + '\'' +", jobId=" + jobId +", mgr=" + mgr +", joinDate=" + joinDate +", salary=" + salary +'}';}
}
package com.whitecamellia;import com.whitecamellia.entity.Emp;import java.sql.*;
import java.util.ArrayList;
import java.util.List;public class FindAllEmp {public static void main(String[] args) {List<Emp> all = findAll();for (Emp emp : all) {System.out.println(emp);}}public static List<Emp> findAll() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;List<Emp> list = new ArrayList<>();try {Class.forName("com.mysql.cj.jdbc.Driver");connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcDemo", "root", "root");statement = connection.createStatement();String sql = "select * from emp";resultSet = statement.executeQuery(sql);while (resultSet.next()) {Integer id = resultSet.getInt(1);String eName = resultSet.getString(2);Integer jobId = resultSet.getInt(3);Integer mgr = resultSet.getInt(4);Date joinDate = resultSet.getDate(5);Double salary = resultSet.getDouble(6);Emp emp = new Emp();emp.setId(id);emp.seteName(eName);emp.setJobId(jobId);emp.setMgr(mgr);emp.setJoinDate(joinDate);emp.setSalary(salary);list.add(emp);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();} finally {if (connection != null) {try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (resultSet != null) {try {resultSet.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}return list;}
}

5. JDBC工具类

5.1 JDBCUtils

  • 抽取JDBC工具类 : JDBCUtils

* 目的:简化书写

* 分析:

1. 注册驱动也抽取

2. 抽取一个方法获取连接对象

* 需求:不想传递参数(麻烦),还得保证工具类的通用性。

* 解决:配置文件

jdbc.properties

url=
​
user=
​
password=

3. 抽取一个方法释放资源

代码示例:

package com.whitecamellia.util;import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;public class jdbcUtils {private static String url;private static String user;private static String password;private static String driver;/*** 文件读取 只需要读取一次 即可 使用静态代码块*/static {// 1.创建Properties集合类Properties properties = new Properties();try {// 获取src路径下的文件的方式--->ClassLoader 类加载器// 获取字符串的路径String path = jdbcUtils.class.getClassLoader().getResource("jdbc.properties").getPath();properties.load(new FileInputStream(path));// System.out.println(path);// 获取数据 赋值url = properties.getProperty("url");user = properties.getProperty("user");password = properties.getProperty("password");driver = properties.getProperty("driver");// 获取驱动Class.forName(driver);
//            System.out.println(url);
//            System.out.println(user);
//            System.out.println(password);
//            System.out.println(driver);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 获取连接** @return 连接对象* @throws SQLException*/public static Connection getConnection() {try {return DriverManager.getConnection(url, user, password);} catch (SQLException throwables) {throwables.printStackTrace();}return null;}/*** 释放资源*** @param resultSet* @param connection* @param statement*/public static void close(Connection connection, Statement statement, ResultSet resultSet) {if (connection != null) {try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (resultSet != null) {try {resultSet.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}/*** 释放资源*** @param connection* @param statement*/public static void close(Connection connection, Statement statement) {if (connection != null) {try {connection.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}

5.2 用户登入练习:

  • 需求:

1. 通过键盘录入用户名和密码

2. 判断用户是否登录成功

* select * from user where username = "" and password = "";

* 如果这个sql有查询结果,则成功,反之,则失败

代码示例:

-- 创建数据库表 user
​
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
password VARCHAR(32)
);
​
INSERT INTO USER VALUES(NULL,'zhangsan','123');
INSERT INTO USER VALUES(NULL,'lisi','1234');
package com.whitecamellia;
​
import com.whitecamellia.util.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
​
/*** 练习: 需求:* 1. 通过键盘录入用户名和密码* 2. 判断用户是否登录成功*/
public class Login {public static void main(String[] args) {// 1.键盘录入,接受用户名和密码Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();// 2.调用方法boolean flag = new Login().login(username, password);// 3.判断结果,输出不同语句if (flag)System.out.println("登录成功!");elseSystem.out.println("用户名或密码错误!");
​}
​/*** 登入方法** @param username* @param password* @return*/public boolean login(String username, String password) {if (username == null || password == null)return false;Connection conn = null;Statement stmt = null;ResultSet rs = null;// 和数据库进行验证try {// 1.建立连接conn = JdbcUtils.getConnection();// 2.定义sqlString sql = "select * from user where username  ='" + username + "' and password= '" + password + "' ";System.out.println("sql:" + sql);// select * from user where username ='s' and password = 'a' or 'a' = 'a'// 3.获取执行sql的对象stmt = conn.createStatement();// 4.执行查询rs = stmt.executeQuery(sql);// 5.判断return rs.next();} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.close(conn, stmt, rs);}return false;}
}

5.3 SQL注入问题

  • PreparedStatement

PreparedStatement:执行sql的对象

1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题

1. 输入用户随便,输入密码:a' or 'a' = 'a

2. sql:select * from user where username = 'fhdsjkf' and password = a' or 'a' = 'a

由于前面的用户名和密码不匹配结果是false 但是后面的or 是true,结果就是true

2. 解决sql注入问题:使用PreparedStatement对象来解决

3. 预编译的SQL:参数使用?作为占位符

4. 步骤:

1. 导入驱动jar包 mysql-connector-java-8.0.22-bin.jar

2. 注册驱动

3. 获取数据库连接对象 Connection

4. 定义sql

注意:sql的参数使用?作为占位符。

如:select * from user where username = ? and password = ?;

5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)

6. 给?赋值:

* 方法: setXxx(参数1,参数2)

* 参数1:?的位置编号 从1 开始

* 参数2:?的值

7. 执行sql,接受返回结果,不需要传递sql语句

8. 处理结果

9. 释放资源

代码示例:
package com.whitecamellia;import com.whitecamellia.util.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;/*** 练习: 需求:* 1. 通过键盘录入用户名和密码* 2. 判断用户是否登录成功*/
public class LoginOk {public static void main(String[] args) {// 1.键盘录入,接受用户名和密码Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();// 2.调用方法boolean flag = new LoginOk().login(username, password);// 3.判断结果,输出不同语句if (flag)System.out.println("登录成功!");elseSystem.out.println("用户名或密码错误!");}/*** 登入方法** @param username* @param password* @return*/public boolean login(String username, String password) {if (username == null || password == null)return false;Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;// 和数据库进行验证try {// 1.建立连接conn = JdbcUtils.getConnection();// 2.定义sql 参数赋值修改成?String sql = "select * from user where username = ? and password = ? ";System.out.println("sql:" + sql);// 3.获取执行sql的对象ps = conn.prepareStatement(sql);//  3.1 依次给 ?号赋值 先执行sql对象再赋值ps.setString(1, username);ps.setString(2, password);// 4.执行查询rs = ps.executeQuery();// 5.判断return rs.next();} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils.close(conn, ps, rs);}return false;}
}

6 JDBC控制事务:

概念:

  1. 事务:

    一个包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

  2. 操作:

1. 开启事务

2. 提交事务

3. 回滚事务

  1. 使用Connection对象来管理事务

* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

* 在执行sql之前开启事务

* 提交事务:commit()

* 当所有sql都执行完提交事务

* 回滚事务:rollback()

* 在catch中回滚事务

代码示例:

-- 举例:
CREATE TABLE account1 (id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR (10),balance DOUBLE
);
-- 添加数据
INSERT INTO account1 (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
​
SELECT * FROM account1;
​
-- 恢复默认 
UPDATE account1 set  balance = 1000;
package com.whitecamellia;import com.whitecamellia.util.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class TransAction {public static void main(String[] args) {Connection connection = null;PreparedStatement ps1 = null;PreparedStatement ps2 = null;try {// 1.数据库连接connection = JdbcUtils.getConnection();//2. 开启事务connection.setAutoCommit(false); //3.定义sql语句String sql1 = "update account1 set balance = balance - ? where id = ?";String sql2 = "update account1 set balance = balance + ? where id = ?";// 4.获取执行sql语句对象ps1 = connection.prepareStatement(sql1);ps2 = connection.prepareStatement(sql2);// 5.设置参数ps1.setDouble(1, 500);ps1.setInt(2, 1);ps2.setDouble(1, 500);ps2.setInt(2, 2);// 6. 执行sql语句ps1.executeUpdate();// int a = 3 / 0;// 模拟异常ps2.executeUpdate();connection.commit(); // 事务提交} catch (SQLException throwables) {if (connection != null) {try {connection.rollback(); // 事务回滚} catch (SQLException e) {e.printStackTrace();}}throwables.printStackTrace();} finally {//7. 释放连接JdbcUtils.close(connection, ps1);JdbcUtils.close(null, ps2);}}
}

7 数据库连接池

7.1 概念:

  • 其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

  • 普通方式

image-20230216162331338

  • 使用连接池

image-20230216162435750

  • 好处:

    • 节约资源

    • 用户访问高效

  • 可以用数据库连接池来管理Connection,这可以重复使用Connection。

    有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。

    当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给连接池,池就可以再利用这个Connection对象了。

    池参数(所有池参数都有默认值):

    • 初始大小

    • 最小空闲连接数

    • 增量:一次创建的最小单位

    • 最大空闲连接数

    • 最大连接数

    • 最大的等待时间

    • ……

    四大连接参数:

    • Driver

    • url

    • 用户名

    • 密码

    常见的开源连接池:

    • DBCP

    • C3P0

    • Druid

7.2 实现:

  • 标准接口:

    • 标准接口:DataSource javax.sql包下的,这是官方提供的,提供了获取数据库连接的方法

  • 方法

    获取连接:getConnection()

    归还连接:Connection.close()。

    如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,

    则不会再关闭连接了。而是归还连接

  • 数据库厂商实现

    • 一般我们不去实现它,有数据库厂商来实现

    • C3P0:数据库连接池技术,相对比较老旧

    • Druid:数据库连接池实现技术,由阿里巴巴提供的

7.3 C3P0

  • C3P0数据库连接池技术

步骤:

  1. 导入jar包 (两个) c3p0-0.9.5.2.jar和mchange-commons-java-0.2.12.jar ,

    不要忘记导入数据库驱动jar包,mysql-connector-java-8.0.22-bin

  2. 定义配置文件:

    名称: c3p0.properties 或者 c3p0-config.xml,二者都可以

    路径:直接将文件放在src目录下即可。

  3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

  4. 获取连接:getConnection

代码示例:
package com.whitecamellia;import com.mchange.v2.c3p0.ComboPooledDataSource;import java.sql.Connection;
import java.sql.SQLException;public class C3P0Test {public static void main(String[] args) throws SQLException {// test1();// 使用方式test2();//测试}public static void test1() throws SQLException {//1.创建数据库连接池对象ComboPooledDataSource ds = new ComboPooledDataSource();//2.获取连接对象Connection connection = ds.getConnection();//3.输出打印System.out.println(connection);//4.归还连接对象connection.close();//  c3p0默认不会把连接回收到连接池中,需要手动归还close}public static void test2() throws SQLException {ComboPooledDataSource ds = new ComboPooledDataSource();for (int i = 1; i <= 11; i++) {Connection connection = ds.getConnection();System.out.println(i + " : " + connection);if (i == 5) {connection.close();}// connection.close();//c3p0默认不会把连接回收到连接池中,需要手动归还close}}
}

7.4 Druid

  • Druid:数据库连接池实现技术,由阿里巴巴提供的

  • 步骤:

  1. 导入jar包 druid-1.0.9.jar

  2. 定义配置文件:

    • 是properties形式的

    • 可以叫任意名称,可以放在任意目录下

  3. 加载配置文件 Properties

  4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory

  5. 获取连接:getConnection

代码示例:
package com.whitecamellia;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;public class DruidTest {public static void main(String[] args) throws Exception {//1.导入jar包//2.导入配置文件Properties properties = new Properties();String path = DruitTest.class.getClassLoader().getResource("druid.properties").getPath();properties.load(new FileInputStream(path));//3.加载配置文件DataSource ds = DruidDataSourceFactory.createDataSource(properties);//4.测试for (int i = 1; i <= 11; i++) {Connection connection = ds.getConnection();System.out.println(i + " : " + connection);if (i == 5) {connection.close();}// 5. 归还连接对象 connection.close();}}
}

7.5 定义工具类

  1. 定义一个类 JDBCUtils

  2. 提供静态代码块加载配置文件,初始化连接池对象

  3. 提供方法

    • 获取连接方法:通过数据库连接池获取连接

    • 释放资源

    • 获取连接池的方法

代码示例:
package com.util;
​
​
import com.alibaba.druid.pool.DruidDataSourceFactory;
​
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
​
/*** 连接池JDBCUtils工具类*/
public class JDBCUtils {
​//1.定义成员变量 DataSourceprivate static DataSource ds;
​static {try {//1.加载配置文件Properties pro = new Properties();InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");pro.load(is);//2.获取DateSourceds = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}
​/*** 获取连接*/public static Connection getConnections() throws SQLException {return ds.getConnection();}
​
​/*** 释放资源** @param stmt* @param conn*/public static void close(Statement stmt, Connection conn) {close(null, stmt, conn);}
​/*** 释放资源** @param rs* @param stmt* @param conn*/public static void close(ResultSet rs, Statement stmt, Connection conn) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}
​if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}
​if (conn != null) {try {conn.close();//归还连接} catch (SQLException e) {e.printStackTrace();}}}
}

相关文章:

JDBC详解——增删改查(CRUD)、sql注入、事务、连接池

1. 概念&#xff1a; Java DataBase Connectivity&#xff0c; Java 数据库连接&#xff0c; Java语言操作数据库 JDBC本质&#xff1a;其实是官方&#xff08;sun公司&#xff09;定义的一套操作所有关系型数据库的规则&#xff0c;即接口。各个数据库厂商去实现这套接口&…...

K-means算法通俗原理及Python与R语言的分别实现

K均值聚类方法是一种划分聚类方法&#xff0c;它是将数据分成互不相交的K类。K均值法先指定聚类数&#xff0c;目标是使每个数据到数据点所属聚类中心的总距离变异平方和最小&#xff0c;规定聚类中心时则是以该类数据点的平均值作为聚类中心。 01K均值法原理与步骤 对于有N个…...

使用 db2diag 工具来分析 db2diag 日志文件

供数据库和系统管理员使用的主日志文件为管理通知日志。db2diag 日志文件旨在供 IBM 软件支持机构用于进行故障诊断。 管理通知日志消息也以标准化消息格式记录到 db2diag 日志文件。 db2diag 工具用于对 db2diag 日志文件中的大量信息进行过滤和格式化。过滤 db2diag 日志文…...

在Pytorch中使用Tensorboard可视化训练过程

这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 本节课我们来讲一下如何在pytouch当中去使用我们的tensorboard 对我们的训练过程进行一个可视化 左边有一个visualizing models data and training with tensorboard 主要是这么一个教程 那么这里…...

Redis 命令全解析之 Hash类型

文章目录 ⛄介绍⛄命令⛄RedisTemplate API⛄应用场景 ⛄介绍 Hash类型&#xff0c;也叫散列&#xff0c;其value是一个无序字典&#xff0c;类似于Java中的 HashMap 结构。 String结构是将对象序列化为JSON字符串后存储&#xff0c;当需要修改对象某个字段时很不方便&#xf…...

postgresql数据库配置主从并配置ssl加密

1、先将postgresql数据库主从配置好 参考&#xff1a;postgresql主从配置 2、在主节点配置ssl加密&#xff0c;使用navicat测试是否可以连接 参考&#xff1a;postgresql配置ssl 3、正常连接无误后&#xff0c;将root.crt、server.crt、server.key复制到从数据库节点的存储…...

IO多路转接之select

IO多路转接之select 1. IO多路转接&#xff08;复用&#xff09;2. select2.1 函数原型2.2 细节描述 3. 并发处理3.1 处理流程3.2 通信代码 原文链接 1. IO多路转接&#xff08;复用&#xff09; IO多路转接也称为IO多路复用&#xff0c;它是一种网络通信的手段&#xff08;机…...

linux如何删除大文件的第一行(sed)

可以用sed命令实现&#xff1a; 删除文档的第一行 1. sed -i 1d <file>删除文档的最后一行 1. sed -i $d <file>在文档指定行中增加一行 # 示例如下&#xff1a; echo "1"; echo "2"; echo "4"; echo "5"; # 想要在echo…...

Navicat 技术指引 | 适用于 GaussDB 分布式的备份/还原功能

Navicat Premium&#xff08;16.3.3 Windows 版或以上&#xff09;正式支持 GaussDB 分布式数据库。GaussDB 分布式模式更适合对系统可用性和数据处理能力要求较高的场景。Navicat 工具不仅提供可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结…...

【广州华锐互动VRAR】VR戒毒科普宣传系统有效提高戒毒成功率

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为人们的生活带来了前所未有的便利。在教育科普领域&#xff0c;VR技术的应用也日益广泛&#xff0c;本文将详细介绍广州华锐互动开发的VR戒毒科普宣传系统&#xff0…...

守护安全,六氟化硫气体泄漏报警装置校准服务

在电力工业中&#xff0c;六氟化硫&#xff08;SF6&#xff09;气体是一种重要的介质&#xff0c;它用作封闭式中、高压开关的灭弧和绝缘气体。六氟化硫气体的卓越性能实现了装置经济化、低维护化的操作。与普通装置相比&#xff0c;可以节省最多90&#xff05;的空间。 六氟化…...

概率测度理论方法(第 2 部分)

一、说明 欢迎回到这个三部曲的第二部分&#xff01;在第一部分中&#xff0c;我们为测度论概率奠定了基础。我们探索了测量和可测量空间的概念&#xff0c;并使用这些概念定义了概率空间。在本文中&#xff0c;我们使用测度论来理解随机变量。 作为一个小回顾&#xff0c;在第…...

实战:Docker Compose 下 Nginx、Java、Mysql 和 Redis 服务协同部署(包含解决浏览器访问Linux部署服务器本地资源问题)

1. 背景 在该实战中&#xff0c;我们将探讨如何使用Docker Compose协同部署Nginx、Java、Mysql和Redis服务&#xff0c;实现一个视频上传与展示的应用。具体需求如下&#xff1a; Java应用负责上传视频和图片资源到Nginx目录下&#xff0c;作为资源服务器。Nginx服务作为静态…...

Docker 设置国内镜像源

Docker 设置国内镜像源 您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器 具体配置如下&#xff1a; {"registry-mirrors" : ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://docker.mirro…...

通信协议 远程调用RPC

1.通讯协议 所有的HDFS通讯协议都是建立在TCP/IP协议之上。 客户端通过一个可配置的TCP端口连接到Namenode&#xff0c;通过ClientProtocol协议与Namenode交 互。而Datanode使用DatanodeProtocol协议与Namenode交互。 一个远程过程调用(RPC)模型被抽象出来封装ClientProtoc…...

决策树 算法原理

决策树 算法原理 决策树的原理 决策树: 从训练数据中学习得出一个树状结构的模型 决策树属于判别模型 决策树是一种树状结构&#xff0c;通过做出一系列决策 (选择) 来对数据进行划分&#xff0c;这类似于针对一系列问题进行选择。 决策树的决策过程就是从根节点开始&#…...

Git全局设置命令---设置提交人邮箱

介绍 使用git命令设置提交人邮箱。 命令 git config --global user.email "xxxxxxxx.com"...

3DCAT+上汽奥迪:打造新零售汽车配置器实时云渲染解决方案

在 5G、云计算等技术飞速发展的加持下&#xff0c;云渲染技术迎来了突飞猛进的发展。在这样的背景下&#xff0c;3DCAT应运而生&#xff0c;成为了业内知名的实时云渲染服务商之一。 交互式3D实时云看车作为云渲染技术的一种使用场景&#xff0c;也逐步成为一种新的看车方式&a…...

物联网+AI智慧工地云平台源码(SaaS模式)

智慧工地云平台充分运用数字化技术&#xff0c;聚焦施工现场岗位一线&#xff0c;依托物联网、互联网、AI等技术&#xff0c;围绕施工现场管理的人、机、料、法、环五大维度&#xff0c;以及施工过程管理的进度、质量、安全三大体系为基础应用&#xff0c;实现全面高效的工程管…...

python打开相机,用鼠标左键框选矩形区域,支持一次框选多个矩形区域,通过鼠标右标清除上一次画的矩形。

方案一 import cv2# Global variables rectangles [] current_rectangle [] drawing False# Mouse callback function def mouse_callback(event, x, y, flags, param):global rectangles, current_rectangle, drawingif event cv2.EVENT_LBUTTONDOWN:drawing Truecurren…...

卷积之后通道数为什么变了

通道数增多与卷积之后得到的图像特征数量有关 卷积层的作用本来就是把输入中的特征分离出来变成新的 feature map&#xff0c;每一个输出通道就是一个卷积操作提取出来的一种特征。在此过程中ReLU激活起到过滤的作用&#xff0c;把负相关的特征点去掉&#xff0c;把正相关的留…...

ubuntu18.04安装opencv-4.5.5+opencv_contrib-4.5.5

一、安装opencv依赖 sudo apt-get install build-essential sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-d…...

实验3.5 路由器的单臂路由配置

实验3.5 路由器的单臂路由配置 一、任务描述二、任务分析三、具体要求四、实验拓扑五、任务实施1.SWA的基本配置2.RA的基本配置3.在RA上查看接口状态 六、任务验收七、任务小结 一、任务描述 某公司对部门划分了需VLAN之后&#xff0c;发现两个部门之间无法通信&#xff0c;但…...

nodejs微信小程序+python+PHP的基于大数据的家电销售分析系统设计与实现-计算机毕业设计推荐django

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…...

Windows server flask

1、Windows server 通过python的flask执行命令 from flask import Flask, request, abort import subprocess from flask_basicauth import BasicAuth app Flask(__name__) # 获取url是进行账号密码认证&#xff0c;设置url的账号密码 app.config[BASIC_AUTH_USERNAME] 账号…...

maven工程的pom.xml文件中增加了依赖,但偶尔没有下载到本地仓库

maven工程pom.xml文件中的个别依赖没有下载到本地maven仓库。以前没有遇到这种情况&#xff0c;今天就遇到了这个问题&#xff0c;把解决过程记录下来。 我在eclipse中编辑maven工程的pom.xml文件&#xff0c;增加对mybatis的依赖&#xff0c;但保存文件后&#xff0c;依赖的j…...

Navicat 技术指引 | 适用于 GaussDB 分布式的用户/权限功能

Navicat Premium&#xff08;16.3.3 Windows 版或以上&#xff09;正式支持 GaussDB 分布式数据库。GaussDB 分布式模式更适合对系统可用性和数据处理能力要求较高的场景。Navicat 工具不仅提供可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结…...

基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期神经网络的新鲜度等级预测

目录 背影 支持向量机SVM的详细原理 SVM的定义 SVM理论 粒子群算法原理 SVM应用实例,基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期神经网络的新鲜度等级预测 代码 结果分析 展望 完整代码:基于支持向量机SVM的新鲜度等级预测,基于自适应粒子群优化长短期…...

麒麟系统系统添加路由

系统添加路由 一、路由的解释&#xff1a; 路由工作在OSI参考模型第三层——网络层的数据包转发设备&#xff08;TCP/IP&#xff09;路由器根据收到数据包中的网络层地址以及路由器内部维护的路由表决定输出端口以及下一跳地址&#xff0c;并且重写链路层数据包头实现转发数据…...

考研真题数据结构

【2021年山西大学真题】将二叉树中所有非终端结点的左右子树交换位置&#xff0c;可以得到原二叉树的 镜像二叉树&#xff0c;如图。假设二叉树的存储形式为&#xff08;lchild&#xff0c;data&#xff0c;rchild&#xff09;&#xff0c;给出求镜像二叉树的算法: &#xff0…...

python爬取 HTTP_2 网站超时问题的解决方案

问题背景 在进行网络数据爬取时&#xff0c;使用 Python 程序访问支持 HTTP/2 协议的网站时&#xff0c;有时会遇到超时问题。这可能会导致数据获取不完整&#xff0c;影响爬虫程序的正常运行。 问题描述 在实际操作中&#xff0c;当使用 Python 编写的爬虫程序访问支持 HTT…...

学会用bash在linux写脚本 (二)

接着上一章继续 数值的对比 判断语句 循环语句 22.5 比较、对比、判断 在写脚本时&#xff0c;有时需要做一些比较&#xff0c;例如&#xff0c;两个数字谁大谁小&#xff0c;两个字符串是否相同等。 做对比的表达式有[]、[[]]、test&#xff0c;其中[]和 test这两种表达式的…...

QML中Dialog获取close与open状态

1.新建MyDialog.qml import QtQuick 2.15import QtQuick.Dialogs 1.2Dialog {id: rootvisible: falsetitle: qsTr("弹出对话框")width: 250height: 200} 2.main.qml中调用MyDialog import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15…...

用C语言实现队列的顺序结构

用C语言实现队列的初始化、队列的判空操作、入队操作、出队运算、取队头元素运算、顺序打印队列。 #include<stdio.h> #define QueueSize 100 typedef char ElemType; typedef struct//队列结构体 {ElemType data[QueueSize];//保存队中元素int front, rear;//队头和队尾…...

Vue 子路由页面发消息给主路由页面 ,实现主页面显示子页面的信息

需求 子页面进入后&#xff0c;能在主页面显示子页的相关信息&#xff0c;比如说主页面的菜单激活的是哪个子页面的菜单项 如上图&#xff0c;当刷新浏览器页面时&#xff0c;让菜单的激活项仍保持在【最近浏览】。 实现方式&#xff1a; 在子页面的create事件中增加&#xff…...

AR技术详解

1.AR技术平台 1.手机端 2.AR眼镜端 3.WebAR。 2.AR基础技术应用 1.平面检测技术 2.模型识别技术 3.图片识别技术 4.AR云&#xff08;云锚点&#xff09;技术 5.人脸检测技术 3.主要AR技术SDK 1.苹果ARKit&#xff0c;谷歌ARCore。 优点&#xff1a;推荐使用Unity开发&#xf…...

h5或uniapp或微信小程序,实现左上角返回到指定页面,侧滑左滑返回指定页面,安卓物理返回键返沪指定页面解决思路的思考

h5或uniapp或微信小程序&#xff0c;实现左上角返回到指定页面&#xff0c;侧滑左滑返回指定页面&#xff0c;安卓物理返回键返沪指定页面 uniapp开发app,(非微信小程序)uniapp写的微信小程序 uniapp开发app,(非微信小程序) 自定义的左上角返回按钮 <i class"iconfon…...

轻量封装WebGPU渲染系统示例<43>- PBR材质与阴影实(源码)

原理简介: 1. 基于rendering pass graph实现。 2. WGSL Shader 基于文件系统和宏机制动态组装。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/PBRShadowTest.ts 当前示例运行效果: 此示例基于此渲染系统实现&a…...

macOS Big Sur/Mac电脑安装vscode显示您没有权限来打开应用程序‘Visual Studio Code‘ 请联系您的电脑或网络管理员问题修复

错误方法 首先我以为我的权限不足。&#xff0c;需要去用户群组里设置。结果根本不是这个的问题。 1.在系统偏好设置->用户与群组检查了一下我的用户是不是管理员 结果发现是管理员 2.根据苹果提示&#xff0c;右键我的文件夹->显示简介->最下面的共享与权限 解锁&…...

jsp 如何批量改随机人名

对比图 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%> <%page import"java.sql.ResultSet"%> <%page import"java.sql.PreparedStatement"%> <%page import&qu…...

android项目实战之编辑器集成

引言 项目需要用到编辑器&#xff0c;采用RichEditor&#xff0c;如下效果 实现 1. 引入库2 implementation jp.wasabeef:richeditor-android:2.0.0 2. XML <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width&q…...

JAVA程序如何打jar和war问题解决

背景: 近期研究一个代码审计工具 需要jar包 jar太多了 可以将jar 打成war包 首先看下程序目录结构 pom.xml文件内容 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"ht…...

Microsoft 365 Copilot正式上线,如何稳定访问体验?

如果将微软对人工智能的投资看成一场豪赌&#xff0c;Microsoft Copilot无疑是现阶段最受瞩目的赌注。2023年9月正式发布的Microsoft Copilot是一种基于大型语言模型&#xff08;LLM&#xff09;和微软图形&#xff08;Microsoft Graph&#xff09;的数据和人工智能&#xff08…...

【安卓】安卓xTS之Media模块 学习笔记(3) VTS测试

1. 背景 接下来进行正式的VTS测试。本章节还是以Media模块相关进行介绍。 VTS主要测的是内核和HAL层&#xff0c;media的hal层是以openMax&#xff08;即将废弃&#xff0c;今日2023.12&#xff09; 和 Codec2 (后续主流) 接口为主。 这里我们只看Codec2的要求&#xff0c;CDD…...

Go实现http同步文件操作 - 增删改查

http同步文件操作 - 增删改查 http同步文件操作 - 增删改查1. 前置要求1.1. 构建结构体 文件名 文件内容1.1.1. 页面结构体1.1.2. 为Page结构体绑定方法&#xff1a;Save1.1.3. 对Page结构体支持页面内容查看方法&#xff0c;同时提供页面文件是否存在的方法 1.2. 简单验证上面…...

Spring Boot整合 Spring Security

Spring Boot整合 1、RBAC 权限模型 RBAC模型&#xff08;Role-Based Access Control&#xff1a;基于角色的访问控制&#xff09; 在RBAC模型里面&#xff0c;有3个基础组成部分&#xff0c;分别是&#xff1a;用户、角色和权限&#xff0c;它们之间的关系如下图所示 SELECT…...

浅谈低代码

低代码开发是近年来迅速崛起的软件开发方法&#xff0c;让编写应用程序变得更快、更简单。有人说它是美味的膳食&#xff0c;让开发过程高效而满足&#xff0c;但也有人质疑它是垃圾食品&#xff0c;缺乏定制性与深度。你认为低代码到底是美以下方向仅供参考。味的膳食还是垃圾…...

Innodb-ruby深入探索Innodb存储结构

达在之前已经分享过Innodb数据存储结构知识&#xff0c;但是都是基于理论原理知识理解&#xff0c;今天利用Innodb文件解析工具ruby进行探索Innodb真实的存储结构。 索引原理过程&#xff1a;【Mysql】 InnoDB引擎深入 - 数据页 | 聚集索引_innodb的聚集索引的数据插入_Surviv…...

Echarts的使用 笔记

1.数据可视化前言 1.1.什么是数据可视化 数据可视化&#xff1a; 就是把数据以更加直观的方式进行呈现. 1.2.数据可视化的好处 清晰有效地传达与沟通信息更容易洞察隐藏在数据中的信息 2.ECharts的基本使用 2.1.ECharts官网 ECharts是百度公司开源的一个使用 JavaScript 实…...

信息系统工程的基本概念

系统是由相互作用和相互依赖的若干部分&#xff0c;按一定规律结合成的、具有特定功能的有机整体。系统有下述特性&#xff1a; &#xff08;1&#xff09;集合性。系统是由许多元素有机地组成的整体。每个元素服从整体&#xff0c;追求全局最优。 &#xff08;2&#xff09;相…...