JDBC学习

背景:主机正在运行mysql服务

在cmd输入

mysql -u root -p

之后,输入密码(我的用户名是root,密码是root),成功登录到mysql。

输入:SHOW GLOBAL VARIABLES LIKE 'port'; 检查mysql服务的端口号

得到我的mysql服务的主机ip是localhost,端口号是3306,用户名是root,密码是root

Java操作数据库的方式:

1. JDBC

1.1 JDBC介绍

JDBC就是通过Java程序操作数据库。

  • JDBC:Java DataBase Connectivity。意思为Java数据库连接
  • JDBC是Java提供的一组独立于任何数据库管理系统的API
  • JDBC提供接口规范,由各个数据库厂商提供接口的实现,厂商提供的实现类封装成jar文件,也就是我们的数据库驱动jar包。
  • 学习JDBC,充分体现了面向接口编程的好处,程序员只关心标准和规范,而无需关注实现过程。

1.2 JDBC的核心组成

  • 接口规范(SUN公司提供):
    • 为了项目代码的可移植性,可维护性,SUN公司从最初就制定了Java程序连接各种数据库的统一接口规范。这样的话,不管是连接哪一种DBMS软件,Java代码可以保持一致性。
  • 实现规范(数据库厂商提供jar包):
    • 因为各个数据库厂商的DBMS软件各有不同,那么各自的内部如何通过SQL实现CRUD,只有数据库厂商清楚,因此把接口规范的实现交给各个数据库厂商自己实现。
    • 数据库厂商将实现的内容和过程封装成jar文件,我们程序员只需要将jar文件引入到项目中集成即可,就可以开发调用过程操作数据库了

例如:

Mysql数据库的jar包:mysql-connetor-jdbc.jar

SQLite数据库的jar包:sqlite-jdbc.jar

Oracle数据库的jar包:ojdbc8.jar

1.3 JDBC快速入门

(1)在数据库中添加数据

CREATE DATABASE atguigu;
USE atguigu;CREATE TABLE t_emp(emp_id INT AUTO_INCREMENT COMMENT '员工编号' PRIMARY KEY,emp_name VARCHAR(100) NOT NULL COMMENT '员工姓名',emp_salary DOUBLE(10,5) NOT NULL COMMENT '员工薪资',emp_age INT NOT NULL COMMENT '员工年龄');INSERT INTO t_emp (emp_name, emp_salary, emp_age) 
VALUES ('andy',777.77,32),('大风哥', 666.66, 41),('康师傅',111,23),('Gavin',123,26),('小鱼儿',123,28);SELECT * FROM t_emp;

(2)导入mysql-connector-java的jar包

    <dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency></dependencies>

(3)编写代码

package com.gtc.base;import java.sql.*;public class JdbcDemo01 {public static void main(String[] args) throws ClassNotFoundException, SQLException {// 1. 注册驱动 (注册mysql数据库的驱动)Class.forName("com.mysql.jdbc.Driver");// 2. 获取连接对象 (java程序连接mysql)String url = "jdbc:mysql://localhost:3306/atguigu";String username = "root";String password = "root";Connection connection = DriverManager.getConnection(url,username,password);//3. 获取执行SQL语句的对象Statement statement = connection.createStatement();//4. 编写SQL语句String sql = "select * from t_emp";//5. 执行SQL语句(返回结果集)ResultSet resultSet = statement.executeQuery(sql);//6. 处理结果,遍历resultSet结果集while (resultSet.next()) {int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");String empSalary = resultSet.getString("emp_salary");String emp_age = resultSet.getString("emp_age");System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+emp_age);}// 7. 释放三个资源resultSet.close();statement.close();connection.close();}
}

得到结果:

1.4 JDBC的核心API

(1)注册驱动Driver

Drive类位于mysql-connector-java包下的com.mysql.jdbc.Driver。其实现了SUN公司提供的Java接口。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {// 构造方法,加载类时自动注册驱动DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}

JDK6之后,可以不写注册驱动。

(2)Connection

  • Connection接口时JDBC API的重要接口,用于建立与数据库的通信通道。换而言之,Connection对象不为空,则代表一次数据库连接。
  • 在建立连接时,需要指定数据库URL、用户名、密码参数
  • Connection接口还负责管理事务,Connection接口提供了commit和rollback方法,用于提交事务和回滚事务。
  • 可以创建Statement对象,用于执行SQL语句并与数据库进行交互。在使用JDBC技术时,必须要先获取Connection对象,在使用完毕后,要释放资源,避免资源占用浪费及泄露。

(3)Statement

Statment用于执行SQL语句并与数据库进行交互。它是JDBC API中的一个重要接口,通过Statement对象,可以向数据库发送SQL语句并获取结果。

Statement接口在执行SQL语句时,会存在SQL注入的问题

SQL注入问题就是,我们在指定条件查询时加入“1=1”这样的sql语句,能够查询到所有记录。

例如:

select emp_id, emp_name form t_emp where emp_name='aaa' or '1' = '1';

此时,后面的or 1=1会导致,无论姓名是否存在,都可以查询到所有记录。

(4)PreparedStatement

  • PreparedStatement是Statement接口的子接口,用于执行预编译的SQL查询,作用如下:
    • 预编译SQL语句:在创建PreparedStatement时,就会预编译SQL语句,也就是SQL语句已经固定。
    • 防止SQL注入:PreparedStatement支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来,无论传递什么作为值。有效防止传入关键字或值导致的SQL注入问题

(5)ResultSet

  • Result是JDBC API中的一个接口,用于表示从数据库中执行查询语句所返回的结果集
  • 遍历结果:ResultSet可以使用next()方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为boolean类型,true代表有下一行结果,false则代表没有
  • 获取单列结果:可以通过getXxx的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取。

1.5 PreparedStatement实现CRUD

查询Retrieve:

public class JdbcOperation {/*** 查询单行单列数据* @throws SQLException*/@Testpublic void testQuerySingleRowAndCol() throws SQLException {// 1. 注册驱动(可以省略)// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句,得到PreparedStatementPreparedStatement preparedStatement = connection.prepareStatement("select count(*) as count from t_emp");// 4. 执行SQL语句,获取结果ResultSet resultSet = preparedStatement.executeQuery();// 5. 处理结果while (resultSet.next()) {int count = resultSet.getInt("count");System.out.println(count);}// 6. 释放资源resultSet.close();preparedStatement.close();connection.close();}/*** 查询单行多列* @throws SQLException*/@Testpublic void testQuerySingleRow() throws SQLException {// 1. 注册驱动// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_id=?");// 4. 为占位符?赋值, 并执行SQL语句preparedStatement.setInt(1,5);ResultSet resultSet = preparedStatement.executeQuery();// 5. 处理结果while (resultSet.next()) {int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");double empSalary = resultSet.getDouble("emp_salary");int empAge = resultSet.getInt("emp_age");System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);}// 6. 释放资源resultSet.close();preparedStatement.close();connection.close();}/*** 查询多行多列* @throws SQLException*/@Testpublic void testQueryMoreRow() throws SQLException {// 1. 注册驱动// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_age > 25");// 4. 执行SQL语句ResultSet resultSet = preparedStatement.executeQuery();// 5. 处理结果集(一次循环处理一行)while (resultSet.next()) {int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");double empSalary = resultSet.getDouble("emp_salary");int empAge = resultSet.getInt("emp_age");System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);}// 6. 释放资源resultSet.close();preparedStatement.close();connection.close();}
}

增加Create:

@Testpublic void testQueryAdd() throws SQLException {// 1. 注册驱动// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement("insert into t_emp(emp_name, emp_salary,emp_age) values(?,?,?)");// 4. 为占位符赋值, 并执行SQLpreparedStatement.setString(1,"rose");preparedStatement.setDouble(2,345.67);preparedStatement.setInt(3,45);int result = preparedStatement.executeUpdate(); // 执行新增SQL// 根据受影响行数,判断是否新增成功if (result > 0){System.out.println("success");}else {System.out.println("fail");}// 5. 释放资源preparedStatement.close();connection.close();}

修改Update:

@Testpublic void testUpdate() throws SQLException {// 1. 注册驱动// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement("update t_emp set emp_salary=? where emp_id=?");// 4. 占位符赋值preparedStatement.setDouble(1,888.88);preparedStatement.setInt(2,6);int result = preparedStatement.executeUpdate();// 根据受影响行数,判断是否新增成功if (result > 0){System.out.println("success");}else {System.out.println("fail");}// 5. 释放资源preparedStatement.close();connection.close();}

删除Delete:

 @Testpublic void testDelete() throws SQLException {// 1. 注册驱动// 2. 获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");// 3. 预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement("delete from t_emp where emp_id=?");// 4. 占位符赋值preparedStatement.setDouble(1,6);int result = preparedStatement.executeUpdate();// 根据受影响行数,判断是否新增成功if (result > 0){System.out.println("success");}else {System.out.println("fail");}// 5. 释放资源preparedStatement.close();connection.close();}

1.6 实体类和ORM思想

  • 在使用JDBC操作数据库时,我们会发现数据都是零散的,明明在数据库中是一行完整的数据,到了Java中变成了一个一个的变量,不利于维护和管理。而我们Java是面向对象的,一个表对应的是一个类,一行数据就对应的是Java中的一个对象,一个列对应是对象的属性,所以我们要把数据存储在一个载体里,这个载体就是实体类!
  • ORM(Object Relational Mapping思想),对象到关系数据库的映射,作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来,以面向对象的角度操作数据库中的数据,即一张表对应一个类,一行数据对应一个对象,一个列对应一个属性!
  • 当下JDBC中这种过程我们称其为手动ORM。后续我们也会学习ORM框架,比如MyBatis、JPA等。

(1)设计实体类Employee

package com.gtc.advanced.pojo;public class Employee {private Integer id; // 对应数据库中的emp_idprivate String name;// 对应数据库中的emp_nameprivate Double salary;// 对应数据库中的emp_salaryprivate Integer age;// 对应数据库中的emp_agepublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getSalary() {return salary;}public void setSalary(Double salary) {this.salary = salary;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Employee{" +"id=" + id +", name='" + name + '\'' +", salary='" + salary + '\'' +", age=" + age +'}';}
}

(2)ORM思想封装单个/多个对象

public class JDBCTest {/*** ORM思想封装单个对象* @throws SQLException*/@Testpublic void testORM() throws SQLException {Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_age, emp_salary from t_emp where emp_id=?");preparedStatement.setInt(1, 1);ResultSet resultSet = preparedStatement.executeQuery();Employee employee = null;if (resultSet.next()) {employee = new Employee();// 传统方法int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");int empAge = resultSet.getInt("emp_age");double empSalary = resultSet.getDouble("emp_salary");// 为对象的属性赋值(ORM思想体现)employee.setId(empId);employee.setName(empName);employee.setAge(empAge);employee.setSalary(empSalary);}System.out.println(employee);resultSet.close();preparedStatement.close();connection.close();}/*** ORM思想封装多个对象* @throws SQLException*/@Testpublic void testORMList() throws SQLException {Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_age, emp_salary from t_emp");ResultSet resultSet = preparedStatement.executeQuery();Employee employee = null;List<Employee> list = new ArrayList<Employee>();while (resultSet.next()) {employee = new Employee();// 传统方法int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");int empAge = resultSet.getInt("emp_age");double empSalary = resultSet.getDouble("emp_salary");// 为对象的属性赋值(ORM思想体现)employee.setId(empId);employee.setName(empName);employee.setAge(empAge);employee.setSalary(empSalary);list.add(employee);}System.out.println(list);resultSet.close();preparedStatement.close();connection.close();}
}

1.7 连接池

现有问题: 

  • 每次操作数据库都要获取新连接,使用完毕后就close释放,频繁的创建和销毁造成资源浪费。
  • 连接的数量无法把控,对服务器来说压力巨大

解决办法——连接池:

  • 连接池就是数据库连接对象的缓冲区,通过配置,有连接池负责创建连接、管理连接、释放连接等操作。预先创建数据库连接放入连接池,用户在请求时,通过池直接获取连接,使用完毕后,将连接池放回池中,避免了频繁的创建和销毁,同时解决了创建的效率。
  • 当池中无连接可用,且未达到上限时,连接池会新建连接。
  • 池中连接达到上限,用户请求等待,可以设置超时时间。

常见连接池:

JDBC的数据库连接池使用javax.sql.DataSource接口进行规范,所有的第三方连接池都实现此接口,自行添加具体实现!也就是说,所有连接池获取连接的和回收连接方法都一样,不同的只有性能和扩展功能!

  • Druid是阿里提供的数据库连接池,是集DBCP、C3P0、Proxool优点于一身的数据库连接池,性能、扩展性、易用性都更好,功能丰富。
  • Hikari取自日语,是光的意思,是SpringBoot2.x之后内置的一款连接池。

追求效率用Hikari,追求可扩展性用Druid

1.7.1 Druid连接池

硬编码实现:

public class DruidTest {public static void main(String[] args) throws SQLException {/*** 硬编码: 将连接池的配置信息和Java代码耦合在一起* 1. 创建DruidDataSource连接池对象* 2. 设置连接池的配置信息* 3. 通过连接池获取连接对象* 4. 回收连接【不是释放连接,而是将连接归还给连接池,给其他线程进行复用】*///1. 创建DruidDataSource连接池对象DruidDataSource ds = new DruidDataSource();//2.1 设置连接池的配置信息ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql://127.0.0.1:3306/atguigu");ds.setUsername("root");ds.setPassword("root");// 2.2 非必须设置的配置ds.setInitialSize(10);ds.setMaxActive(20);//3. 通过连接池获取连接对象Connection connection = ds.getConnection();//4. 基于Connection进行CRUD//4. 编写SQL语句Statement statement = connection.createStatement();String sql = "select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_name='康师傅'";//5. 执行SQL语句(返回结果集)ResultSet resultSet = statement.executeQuery(sql);//6. 处理结果,遍历resultSet结果集while (resultSet.next()) {int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");String empSalary = resultSet.getString("emp_salary");String emp_age = resultSet.getString("emp_age");System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+emp_age);}//5. 回收连接(不是关闭)connection.close();}
}

软编码实现:

在项目目录下创建resources文件夹,标识该文件夹为资源目录,创建db.properties配置文件,将连信息定义在该文件中。

propeties类型文件通常用于存储Key-Value键值对,且Key和Value均为字符串类型。

public class DruidSoftTest {public static void main(String[] args) throws Exception {// 1.创建一个Properties集合,用于存储外部配置文件的key和value值Properties prop = new Properties();// 2. 读取外部配置文件,获取输入流,加载到Properties集合里InputStream inputStream = DruidSoftTest.class.getClassLoader().getResourceAsStream("druid.properties");prop.load(inputStream);// 3. 基于Properties集合构建DruidDataSource连接池DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);// 4. 通过连接池获取连接对象Connection connection = dataSource.getConnection();// 5. CRUDStatement statement = connection.createStatement();String sql = "select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_name='康师傅'";ResultSet resultSet = statement.executeQuery(sql);while (resultSet.next()) {int empId = resultSet.getInt("emp_id");String empName = resultSet.getString("emp_name");String empSalary = resultSet.getString("emp_salary");String emp_age = resultSet.getString("emp_age");System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+emp_age);}// 6. 回收连接connection.close();}
}

1.7.2 Hikari连接池

1.8 工具类封装

/***  JDBC工具类 (V1.0)*      1. 维护一个连接池对象*      2. 对外提供在连接池中获取连接的方法*      3. 对外提供回收连接的方法*  注意:工具类仅对外提供共性的功能代码,所以方法均为静态方法!*/
public class JdbcUtil {// 创建连接池引用,因为要提供给当前项目的全局使用,所以创建是静态的private static DataSource dataSource;// 项目启动时,即创建连接池对象,赋值给dataSourcestatic {try{Properties properties = new Properties();InputStream inputStream = JdbcUtil.class.getClassLoader().getResourceAsStream("druid.properties");properties.load(inputStream);dataSource = DruidDataSourceFactory.createDataSource(properties);}catch (Exception e){throw new RuntimeException(e);}}// 对外提供在连接池中获取连接的方法public static Connection getConnection(){try {return dataSource.getConnection();} catch (SQLException e) {throw new RuntimeException(e);}}public static void release(Connection conn){try {conn.close();} catch (SQLException e) {throw new RuntimeException(e);}}
}

测试工具类是否能使用

public class JdbcUtilTest {@Testpublic void test() {Connection connection = JdbcUtil.getConnection();System.out.println("crud...");JdbcUtil.release(connection);}
}

1.9 DAO概念及搭建

  • DAO:Data Acess Object,数据访问对象
  • Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象。
  • 在Java操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是DAO层。
  • DAO层只关注对数据库的操作,供业务层Service调用。

BaseDAO概念

基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以我们可以抽取公共代码,给这些DAO的实现类抽取一个公共的父类,复用增删改查的基本操作,我们称为BaseDao

1.10 数据库事务操作

1.11 事务实现

2. MyBatis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23153.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端js进阶,ES6语法,包详细

进阶ES6 作用域的概念加深对js理解 let、const申明的变量&#xff0c;在花括号中会生成块作用域&#xff0c;而var就不会生成块作用域 作用域链本质上就是底层的变量查找机制 作用域链查找的规则是:优先查找当前作用域先把的变量&#xff0c;再依次逐级找父级作用域直到全局…

IDEA通过Maven使用JBLJavaToWeb插件创建Web项目

第一步&#xff1a;IDEA下载JBLJavaToWeb插件 File--->Settings--->Plugins--->Marketplace搜索: JBLJavaToWeb 第二步&#xff1a;创建普通Maven工程 第三步&#xff1a; 将普通Maven项目转换为Web项目

在VSCode中接入deepseek

注册就送14元2000万tokens。 https://cloud.siliconflow.cn/i/rnbA6i6U各种大模型 下面介绍我是如如接入vscode的 左边生成一个key&#xff0c;呆会vscode要用&#xff0c;不然401. 打开vscod&#xff0c;电脑能上网。下插件。 下好要配置 点它一下。 要配置&#xff0c;全…

Mac端homebrew安装配置

拷打了一下午o3-mini-high&#xff0c;不如这位博主的超强帖子&#xff0c;10分钟结束战斗 跟随该文章即可&#xff0c;2025/2/19亲测可行 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客文章浏览阅读10w次&#xff0c;点赞258次&#xff0c;收藏837次。一直觉得自己写…

安全启动(secure boot)怎么关闭_史上最全的各品牌机和组装机关闭安全启动教程

很多网友发现电脑BIOS设置中都有一个secure boot(安全启动)选项&#xff0c;而且一些预装win10或win11改Win7的教程中也有提到要把安全启动关闭&#xff0c;那么我们该怎么关闭安全启动呢&#xff1f;下面教大家各品牌机和组装机关闭安全启动教程。 secure boot该关还是开&…

C进阶 自定义类型

目录 前言 一 结构体 二 结构体的存储 三 位段 四 枚举 五 联合体 总结 前言 我们之前学习的int char double ......都是内置类型&#xff0c;但是我们今天所学习的是自定义类型&#xff0c;比如联合体&#xff0c;结构体&#xff0c;枚举 一 结构体 结构体是一…

STM32的HAL库开发---ADC采集内部温度传感器

一、STM32内部温度传感器简介 二、温度计算方法 F1系列&#xff1a; 从数据手册中可以找到V25和Avg_Slope F4、F7、H7系列只是标准值不同&#xff0c;自行查阅手册 三、实验简要 1、功能描述 通过ADC1通道16采集芯片内部温度传感器的电压&#xff0c;将电压值换算成温度后&…

【PyQt5】python可视化开发:PyQt5介绍,开发环境搭建快速入门

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Android 串口通信

引言 在iot项目中&#xff0c;Android 端总会有和硬件通信。 通信这里&#xff1a;串口通信&#xff0c;蓝牙通信或者局域网通信。 这里讲一下串口通信。 什么是串口&#xff1f; “串口”&#xff08;Serial Port&#xff09;通常是指一种用于与外部设备进行串行通信的接口。…

跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围

一 查看springboot自带的tomcat版本&#xff1a; 可直接在项目中找到Maven Dependencies中找到tomcat版本 二、查看SpringBoot内置tomcat版本的支持范围 我这边是跟据maven仓库查看的 首先跟据链接打开maven仓库&#xff1a;https://mvnrepository.com/ 然后搜索&#xff1a…

磐维数据库双中心容灾流复制集群搭建

1. 架构 磐维数据库PanWeiDB V2.0.0基于gs_sdr工具&#xff0c;在不借助额外存储介质的情况下实现跨Region的异地容灾。提供流式容灾搭建&#xff0c;容灾升主&#xff0c;计划内主备切换&#xff0c;容灾解除、容灾状态监控等功能。 2. 部署双中心磐维集群 2.1. 主集群 角色…

Spring事务原理 二

在上一篇博文《Spring事务原理 一》中&#xff0c;我们熟悉了Spring声明式事务的AOP原理&#xff0c;以及事务执行的大体流程。 本文中&#xff0c;介绍了Spring事务的核心组件、传播行为的源码实现。下一篇中&#xff0c;我们将结合案例&#xff0c;来讲解实战中有关事务的易…

【机器学习】【KMeans聚类分析实战】用户分群聚类详解——SSE、CH 指数、SC全解析,实战电信客户分群案例

1.引言 在实际数据分析中&#xff0c;聚类算法常用于客户分群、图像分割等场景。如何确定聚类数 k 是聚类分析中的关键问题之一。本文将以“用户分群”为例&#xff0c;展示如何通过 KMeans 聚类&#xff0c;利用 SSE&#xff08;误差平方和&#xff0c;也称 Inertia&#xff…

20-R 绘图 - 饼图

R 绘图 - 饼图 R 语言提供来大量的库来实现绘图功能。 饼图&#xff0c;或称饼状图&#xff0c;是一个划分为几个扇形的圆形统计图表&#xff0c;用于描述量、频率或百分比之间的相对关系。 R 语言使用 pie() 函数来实现饼图&#xff0c;语法格式如下&#xff1a; pie(x, l…

搭建 Hadoop 3.3.6 伪分布式

搭建 Hadoop 3.3.6 伪分布式 IP 192.168.157.132 初始化操作 更改yum源 # 1_1.安装Wget yum install wget# 1_2.备份CentOS-Base.repo文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_bak# 2.下载阿里yum源配置 wget -O /etc/yum.repos.d/Cen…

python电影数据分析及可视化系统建设

博主介绍&#xff1a;✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

手机壁纸设计中,金属质感字体可以为壁纸增添独特的视觉效果和高端感

在手机壁纸设计中&#xff0c;金属质感字体可以为壁纸增添独特的视觉效果和高端感。以下是一些关于金属质感字体在手机壁纸设计中的应用建议和案例分析&#xff1a; 1. 金属质感字体的特点 视觉冲击力强&#xff1a;金属质感字体具有独特的光泽和质感&#xff0c;能够在视觉上…

使用ezuikit-js封装一个对接摄像头的组件

ezuikit-js 是一个基于 JavaScript 的视频播放库&#xff0c;主要用于在网页中嵌入实时视频流播放功能。它通常用于与支持 RTSP、RTMP、HLS 等协议的摄像头或视频流服务器进行交互&#xff0c;提供流畅的视频播放体验。 主要功能 多协议支持&#xff1a;支持 RTSP、RTMP、HLS …

PHP post 数据丢失问题

max_input_vars是PHP配置选项之一&#xff0c;用于设置一个请求中允许的最大输入变量数。它指定了在处理POST请求或者通过URL传递的参数时&#xff0c;PHP脚本能够接收和处理的最大变量数量。 max_input_vars的默认值是1000&#xff0c;意味着一个请求中最多可以包含1000个输入…

jenkins docker容器中安装python3.9环境

在运维过程中&#xff0c;不过避免的需要使用到python&#xff0c;在jenkins 的docker容器中&#xff0c;是没有python环境的&#xff0c;需要我们自己手动安装一下。 查看是否有工具apt-get 直接输入apt-get 然后回车&#xff0c;出现以下内容&#xff0c;表示支持apt-get命令…