一、JDBC的概述

1.JDBC为访问不同的数据薛是供了统一的接口,为使用者屏蔽了细节问题。
2. Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。

 二。JDBC带来的好处

java程序可以直接对数据库进行调用,但是没有很好的移植性(对用于不同的数据库),所以不推荐

JDBC带来的好处:JDBC是java提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。

JDBC API:JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接,执行SQL语句,并得到返回结果等各类操作;

JDBC程序编写步骤

1、注册驱动 --- 加载Driver类

2、获取连接 --- 得到Connection

3、执行增删改查 --- 发送Sql给mysql执行

4、释放资源 --- 关闭相关连接

 获取数据库连接的5种方式:

方式1:使用(com.mysql.jdbc.Driver)com.mysql.cj.jdbc.Driver,属于静态加载,灵活性差,依赖性强

方式2:使用反射机制,属于静态加载

方式3:使用DriverManager替代driver进行统一管理

方式4:使用Class.forName自动完成注册驱动,简化代码

这种方式连接是使用得最多的(推荐使用)

在底层会完成注册:

提示:

(1)mysql驱动5.1.6可以无需Class.forName(“com.mysql.jdbc.Driver”);

(2)从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动jar包下META-INF\servicesljava .sql.Driver文本中的类名称去注册

(3)建议加上Class.forName(“com.mysql.jdbc.driver”),能够更加明确的感受到程序流程,利于掌握;

方式5:利用properties文件配置数据库需要的相关的配置

更加的灵活,可以直接通过properties配置文件修改数据库连接相关的数据

对方式5的实例:

//properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
user=root
password=123456
//连接数据库的相关操作
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; public class jdbc02 {
public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
//创建一个properties对象
Properties properties = new Properties();
//加载和获取创建的properties的相关数据
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); String sql = "insert into actor values (null,'王五','男','1975-11-23','110')"; //driver驱动,也可以不加,但是加上更容易读懂流程
Class.forName(driver);
//连接和执行操作
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
statement.executeUpdate(sql);
//关闭连接
System.out.println("连接"+connection);
statement.close();
connection.close(); }
}

三、RestSet【结果集】

基本介绍:

1.表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
2. ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前

3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回
false,因此可以在while循环中使用循环来遍历结果集

简单测试:

 四、Statement:

基本介绍:

1.Statement对象用于执行静态SQL语句并返回其生成的结果的对象
2.在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过

Statement【存在SQL注入】
PreparedStatement【预处理】
CallableStatement【存储过程】

3. Statement对象执行SQL语句,存在SQL注入风险

4.SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。

5.要防范SQL注入,只要用 PreparedStatement(从Statement扩展而来)取
代 Statement就可以了

import java.io.*;
import java.sql.*;
import java.util.Properties; public class jdbc02 {
public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
//创建一个properties对象
Properties properties = new Properties();
//加载和获取创建的properties的相关数据
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); String sql = "insert into actor values (null,'三毛','男','1975-11-23','110')";
String sql1 = "select id,name from actor"; //driver驱动,也可以不加,但是加上更容易读懂流程
Class.forName(driver);
//连接和执行操作
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
// statement.executeUpdate(sql); // String sql1 = "select id,name from actor";
ResultSet resultSet = statement.executeQuery(sql1);
while (resultSet.next()) {
int i = resultSet.getInt(1);
String string1 = resultSet.getString(2);
System.out.println(i+"=="+string1);
}
//关闭连接
resultSet.close();
System.out.println("连接"+connection);
statement.close();
connection.close(); }
}

PrepareStatement:

1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用
PreparedStatement对象的setXxx()方法来设置这些参数. setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2.调用executeQuery),返回ResultSet 对象
3.调用executeUpdate):执行更新,包括增、删、修改

预处理的好处:

1.不再使用+拼接sql语句,减少语法错误

2.有效的解决了sql注入问题!
3.大大减少了编译次数,效率较高

对preparestatement的测试代码,配置文件还是上面的配置文件

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties; public class PrepareStatement {
public static void main(String[] args) throws Exception { Properties properties = new Properties();
properties.load(new FileInputStream("src\\db.properties"));
String drive = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password"); //更新操作
// String sql = "update actor set phone = ? where name = ?";
//删除操作
// String sql = "delete from actor where name = ?";
// 添加操作
// String sql = "insert into actor values(null,?,?,?,?)";
//查询操作
String sql = "select * from actor"; Class.forName(drive); Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement(sql);
//更改操作
// preparedStatement.setString(1, "123456");
// preparedStatement.setString(2, "三毛");
//删除操作
// preparedStatement.setString(1, "二狗");
//添加操作
// preparedStatement.setString(1, "张三");
// preparedStatement.setString(2, "男");
// preparedStatement.setString(3, "1975-11-23 00:00:00");
// preparedStatement.setString(4,"456789");
// int i = preparedStatement.executeUpdate();
// System.out.println(i >0 ? "成功" : "失败"); //查询操作
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString(2));
} preparedStatement.close();
connection.close(); }
}

总结:

 五、事务:将多行代码当做SQL事务来处理,主要流程需要的关键代码:

connection.setAutoCommit(false);//取消自动提交的操作,取消之后,会在提及之后完成事务
connection.commit();提交事务
connection.rollback();//用于回退事务
批处理:

基本介绍:

1、当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允
许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

2、JDBC的批量处理语句包括下面方法:
addBatch():添加需要批量处理的SQL语句或参数executeBatch(:执行批量处理语句;
clearBatch():清空批处理包的语句
3、 JDBC连接MySQL时,如果要使用批处理功能,请再url中加参
数?rewriteBatchedStatements=true
4、批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

过程:

(1)将sql语句加入到批处理包中

preparedStatement.addBatch();
preparedStatement.addBatch(sql);

(2)执行sql和清空sql

//批量执行sql语句
preparedStatement.executeBatch();
//清除批量的sql语句
preparedStatement.clearBatch();

将 SQL加入到批处理包中源码所做的事情:

六、数据库连接池

 传统connection问题分析

1.传统的JDBC数据库连接使用 DriverManager来获取,每次向数据库建立
连接的时候都要将Connection 加载到内存中,再验证IP地址,用户名和密码(0.05s~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。2每一次数据库连接,使用完后都得断开,如果程序出现异常面未能关闭,将
导致数据库内存泄漏,最终将导致重启数据库。
3.传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致
内存泄漏,MySQL崩溃。
4.解决传统开发中的数据库连接问题,可以采用数据库连接池技术
(connection pool).

数据库连接池基本介绍:

1.预先在缓冲池中放入一定数量的连接,,当需
要建立数据库连接时,只需从“缓冲池”中取出一个,,使用完毕之后再放回去。
2.数据库连接池负责分配、管理和释放数据库
连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
3.当应用程序向连接池请求的连接数超过最大
连接数量时,这些请求将被加入到等待队列中

数据库连接池示意图:

数据库连接池种类:

1.JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource
只是一个接口,该接口通常由第三方提供实现
2.C3PO 数据库连接池,速度相对较慢,稳定性不错(hibernate, spring)

3.DBCP数据库连接池,速度相对c3p0较快,但不稳定
4. Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点

5.BoneCP数据库连接池,速度快
6.Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool
优点于身的数据库连接池

测试:C3P0连接池的连接(需要导入第三方库:c3p0的jar包)

第一个C3P0连接的配置文件还是上面的配置文件内容

第二个C3P0的连接需要有一个xml配置文件

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; public class ConDatasource {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\db.properties"));
String driver = properties.getProperty("driver");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url"); //建立comboPooledDataSource管理连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password); //设置初始化连接数和最大连接数
comboPooledDataSource.setInitialPoolSize(10);
comboPooledDataSource.setMaxPoolSize(50);
//这个方法就是从DataSource接口实现的
Connection connection = comboPooledDataSource.getConnection();
System.out.println("1连接成功");
connection.close(); } @Test
public void ConDatasource02() throws SQLException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("test_C3P0"); long start = System.currentTimeMillis();
System.out.println("测试连接5000次需要的时间");
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
// System.out.println("2连接成功");
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("花费时长:"+(end-start));
}
}
//第二种方式的xml文件
<c3p0-config> <named-config name="test_C3P0">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!-- url-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db?useSSL=false&amp;characterEncoding=utf8&amp;serverTimezone=UTC</property>
<!-- 用户名 -->
<property name="user">root</property>
<!-- 密码 -->
<property name="password">123456</property>
<!-- 每次增长的连接数-->
<property name="acquireIncrement">5</property>
<!-- 初始的连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">10</property> <!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property> <!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>

测试:Druid连接池的连接(需要第三方库druid的jar包)

package com.zjl.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.util.Properties; public class Druidsource {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));//如下定义的配置文件 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
long start = System.currentTimeMillis();
for (int i = 0;i < 500000;i++ ) {
Connection connection = dataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("Druid连接5000 次需要的时间:" + (end - start));//Druid连接500000 次需要的时间:625
}
}
//连接中需要的一个配置文件
druid.properties:放在src目录下

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
#url=jdbc:mysql://localhost:3306/girls
username=root
password=123456
#initial connection Size初始连接数
initialSize=10
#min idle connecton size最小等待连接数
minIdle=5
#max active connection size最大连接数
maxActive=20
#max wait time (5000 mil seconds)
# 最大等待时间,时间超过就结束这次连接等待下一次的连接
maxWait=5000
 

注意:对于c3p0和Druid他们的close()是按照第三方库的连接方式,仅仅是将从连接池引用的数据库连接断开(放弃引用)

重新将连接放回到连接池中,和原生 的jdbc连接中的close方法断开连接不同;

用Druid创建一个连接和断开的工具类;

package com.zjl.jdbc;

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; public class JDBCUtilsByDruid {
static DataSource ds;
static {
Properties properties = new Properties(); try {
properties.load(new FileInputStream("src\\druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//编写获取Connection的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
} 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);
}
}
}

七、Apache-DBUtils

1、问题引出:在使用Druid连接数据库,返回结果集之后,如果断开连接,结果集就不能够再使用。解决方法如图,将返回的结果集保存到一个泛型列表中,那么当数据库连接断开后,还是可以使用返回的结果集。

2、对Apache-DBUtils的基本介绍

1).commons-dbutils 是 Apache组织提供的一个开源 JDBC工具类库,它是对JDBC的封装,
使用dbutils能极大简化jdbc编码的工作量[真的]。
DbUtils类
(1). QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理

(2).使用QueryRunner类实现查询
(3). ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式

对该DBUtils进行测试:需要对应的jar包(commons-dbutils-1.7.jar)可以去:http://commons.apache.org/下载

相应的JDBCUtilsByDruid类是上面的测试类:

package com.zjl.jdbc;

import com.zjl.bean.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List; public class TestDBUtils {
public static void main(String[] args) throws Exception {
String sql = "select * from `actor`";
//从Druid中获取一个连接
Connection connection = JDBCUtilsByDruid.getConnection();
//引入DBUtils的jar包,并获得一个QueryRunner对象
QueryRunner queryRunner = new QueryRunner(); //利用QueryRunner对象就可以直接查询数据库,执行SQl语句,返回结果封装到ArrayList集合中
// connection是一个连接,sql是一个执行语句
//new BeanListHandler<>(Actor.class):在将resultSet中的结果以Actor对象方式封装到ArrayList
//底层使用反射机制,获取Actor类的属性,然后进行封装
//1就是给sql 语句中的?赋值,可以有多个值,因为是可变参数0bject... params
// List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
//如果要返回单个查询数据就使用BeanHandler<>(Actor.class),返回结果就会是单个对象或者为空
List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class));
//在底层会得到resultSet并在query中关闭,也会在底层使用preparedStatement并关闭
// JDBCUtilsByDruid.close(null, null, connection);
Iterator<Actor> iterator = list.iterator();
while (iterator.hasNext()) {
Actor next = iterator.next();
System.out.println(next);
}
//进行更新操作
String updateSql = "update `actor` set name = ? where id = ?";
int update = queryRunner.update(connection, updateSql, "王无无", 8);
System.out.println((update > 0) ? "更新成功" : "更新失败");
//进行删除操作
String delSql = "delete from `actor` where id = ?";
int update1 = queryRunner.update(connection, delSql, 10);
System.out.println((update > 0) ? "删除成功" : "删除失败"); //关闭资源
JDBCUtilsByDruid.close(null, null, connection);
} }

八、BasicDao--DAO和增删改查通用方法(DAO:data access object   数据访问对象)

基本说明:

1)、 DAO:data access object数据访问对象
2)、这样的通用类,称为 BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud操作。

3)、在BaiscDao的基础上,实现一张表对应一个Dao,更好的完成功能;

关系图如下:



java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、的更多相关文章

  1. 通过实现ServletContextListener接口创建数据库连接池(C3P0方式)

    使用Listener步骤 1. 定义Listener实现类 2. 在web.xml中配置(或使用Annotation) 使用C3P0方式创建数据库连接池需要添加的jar包 1.c3p0-0.9.5.j ...

  2. Java中数据库连接池原理机制的详细讲解以及项目连接数据库采用JDBC常用的几种连接方式

    连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...

  3. 网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别

    1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2 ...

  4. java基础 JDBC & Statement & PreparedStatement

    参考文章: http://blog.csdn.net/wang379275614/article/details/23393335 概念 JDBC-数据库连接,是由一些类和接口构成的API,是J2SE ...

  5. Lucene搜索方式大合集

    package junit; import java.io.File; import java.io.IOException; import java.text.ParseException; imp ...

  6. Jmeter连接数据库方式

    关系型数据库: 1.mysql: 方式:Database URL:jdbc:mysql://localhost:port/DBname?user=**&password=**&allo ...

  7. ipv6下jdbc的连接数据库方式

    ipv6下jdbc的连接数据库方式 MySQL: ipv4 Driver URL:           jdbc:mysql://127.0.0.1:3306/database   ipv6 Driv ...

  8. 基于已有集群动态发现方式部署 Etcd 集群

    etcd提供了多种部署集群的方式,在「通过静态发现方式部署etcd集群」 一文中我们介绍了如何通过静态发现方式部署集群. 不过很多时候,你只知道你要搭建一个多大(包含多少节点)的集群,但是并不能事先知 ...

  9. 基于 DNS 动态发现方式部署 Etcd 集群

    使用discovery的方式来搭建etcd集群方式有两种:etcd discovery和DNS discovery.在 「基于已有集群动态发现方式部署etcd集群」一文中讲解了etcd discove ...

随机推荐

  1. Nginx-正反向代理及负载均衡

    目录 正/反向代理 代理的方式 Nginx代理服务支持的协议 代理实战 部署web01 部署Lb01 Nginx代理常用参数 添加发往后端服务器的请求头信息 代理到后端的TCP连接.响应.返回等超时时 ...

  2. Azure Terraform(九)GitHub Actions 实现 Infra 资源的自动化部署

    思路浅析 使用 Terraform Code 部署 Azure 基础设施资源是特别受欢迎的,我曾经有写文章分享过利用 Azure DevOps 自动部署 Terraform Code 所描述的 Azu ...

  3. yum是什么?repo文件详解,epel简介,yum源的更换,repo和epel区别

    yum是什么?repo文件详解,epel简介,yum源的更换,repo和epel区别 简单概括: repo和epel的关系 repo是配置源的,即配置从哪里下载包(以及依赖关系)的. epel是作为桥 ...

  4. HDU 2673-shǎ崽 OrOrOrOrz(C语言描述)

    问题描述 问题是: 为您提供了一系列不同的整数, 请选择 "数字" 如下: 首先选择最大的, 然后是最小的, 然后是第二个最大的, 第二个最小的. 直到所有的数字被选中.例如, 给 ...

  5. 《剑指offer》面试题63. 股票的最大利润

    问题描述 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? 示例 1: 输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = ...

  6. Docsify部署IIS

    什么是Docsify? 一个神奇的文档网站生成器.docsify 可以快速帮你生成文档网站.不同于 GitBook.Hexo 的地方是它不会生成静态的 .html 文件,所有转换工作都是在运行时.如果 ...

  7. Cesium入门10 - 3D Tiles

    Cesium入门10 - 3D Tiles Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 我们团队有时把Ces ...

  8. Tomcat下载安装以及配置方法

    Tomcat环境变量配置方法 注意一定要在java环境配置成功之后再来配置tomcat.我这里仅展现在Windows系统下载的安装方法 Tomcat下载地址如下: https://tomcat.apa ...

  9. python for循环while循环数据类型内置方法

    while 条件: 条件成立之后循环执行的子代码块 每次执行完循环体子代码之后都会重新判断条件是否成立 如果成立则继续执行子代码如果不成立则退出 break用于结束本层循环 ### 一:continu ...

  10. Lesson3——Pandas Series结构

    1 什么是Series结构? Series 结构,也称 Series 序列,是 Pandas 常用的数据结构之一,它是一种类似于一维数组的结构,由一组数据值(value)和一组标签组成,其中标签与数据 ...