您的位置:首页 > 编程语言 > Java开发

JavaWeb学习的第五天(数据库连接池_C3P0_Druid_DruidUtil工具类_Spring JDBC)

2020-01-15 07:22 561 查看

一、不使用连接池获取连接对象的耗时验证

1.解释为什么使用JDBC操作数据库会消耗CPU大量时间

//在没有学连接池之前,所有的使用JDBC操作数据库的案例基本上都是一个套路
/*1.获取连接对象--2.执行sql语句--3.关闭连接*/
/*获取连接对象这个操作是非常耗时的(以前使用jdbc操作数据库的弊端)*/
//验证三大主要步骤所需要消耗的时间
//每创建一个connection需要消耗大量的时间,而且每次使用完之后就关闭了这个connection,释放资源
//下一次创建connection又要消耗大量的时间,周而复始,就会大量消耗CPU的时间

Mysql需要用的jar包---mysql-connector-java-5.1.37-bin.jar

链接:https://pan.baidu.com/s/1kexluH1eqkkEqA-_3R75UA
提取码:6gjb

2.代码验证

package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class C3P0Demo1 {
public static void main(String[] args) {
//在没有学连接池之前,所有的使用JDBC操作数据库的案例基本上都是一个套路
/*获取连接对象--执行sql语句--关闭连接*/
//使用JDBC去操作数据库
Connection connection=null;
PreparedStatement preparedStatement=null;
//导入jar包
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象
long time1 = System.currentTimeMillis();
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/student02", "root","123");
long time2 = System.currentTimeMillis();
System.out.println("创建连接对象需要消耗的时间为"+(time2-time1));
//定义一个sql语句
String sql="update account set balance=2500 where id=?";
//获取预编译对象
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,1);
//执行sql语句
preparedStatement.executeUpdate();
long time3 = System.currentTimeMillis();
System.out.println("执行sql语句需要消耗的时间为"+(time3-time2));
} catch (Exception e) {
e.printStackTrace();
} finally {
long time4 = System.currentTimeMillis();
//释放资源
try {
if(preparedStatement!=null){
preparedStatement.close();
preparedStatement=null;
}
if(connection!=null){
connection.close();
connection=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
long time5 = System.currentTimeMillis();
System.out.println("释放资源需要消耗的时间为"+(time5-time4));
}
}
}

3.运行过程截图

二、数据库连接池

1.为什么会存在数据库连接池??

1.1 从上述实例中我们可以看出每用完连接之后就把连接干掉了,这样非常的繁琐,而且每向系统申请一个连接对象都需要消耗cpu大量的时间
1.2 所以需要进行优化--想连接对象使用完之后能否用某个东西先储存起来,下次要用的时候直接拿出来就可以了,不需要再重新创建连接对象
1.3 某个东西---容器,放的就是连接对象  容器---池子  因为放的是连接对象,所以就叫做连接池
1.4 连接池里面可以一次性储存多个连接对象(在系统初始化的时候),需要用的时候从连接池中拿一个连接对象出来,用完就丢到连接池里面
1.5 为了书写的习惯,所以归还连接对象给连接池的方法也是调用close()
1.6 连接池:sun公司写的一套规范(接口)--DataSource--连接池
1.7 具体的实现还是由数据库生产厂商编写实体类,这些实体类就是jar包
1.8 DBCP C3P0 Druid(阿里巴巴提供)---数据库连接池技术
1.9 基本实现--生成标准的connection对象

2.数据库连接池系统解释

2.1 概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
2.2 好处:
1. 节约资源
2. 用户访问高效
2.3 实现:
1. 标准接口:DataSource  javax.sql包下的
1. 方法:
* 获取连接:getConnection()
* 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

2. 一般我们不去实现它,有数据库厂商来实现
1. C3P0:数据库连接池技术
2. Druid:数据库连接池实现技术,由阿里巴巴提供的

三、C3P0:数据库连接池技术

1.使用步骤

1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,
1.1 不要忘记导入数据库驱动jar包(mysql-connector-java-5.1.37-bin.jar)
2. 定义配置文件:
2.1 名称: c3p0.properties 或者 c3p0-config.xml
2.2 路径:直接将文件放在src目录下即可。
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection

C3P0的配置文件内容如下所示:

<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!--  连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/student02</property>
<property name="user">root</property>
<property name="password">123</property>

<!-- 连接池参数 -->
<!-- 默认初始化连接对象个数 -->
<property name="initialPoolSize">5</property>
<!-- 连接池最大连接数 -->
<property name="maxPoolSize">10</property>
<!-- 超时时间 -->
<property name="checkoutTimeout">3000</property>
</default-config>

<named-config name="otherc3p0">
<!--  连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/student02</property>
<property name="user">root</property>
<property name="password">123</property>

<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>

需要导入的两个C3P0的jar包和一个配置文件

链接:https://pan.baidu.com/s/1KYJLQ7UEEQxIncakg0ZwSQ
提取码:5vjq
复制这段内容后打开百度网盘手机App,操作更方便哦

2.代码演示

package com.bianyiit.cast;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class C3P0LianJieChiDemo1 {
public static void main(String[] args) throws SQLException {
//使用C3P0连接池的步骤
/*注意:mysql的驱动包一定要别忘了,也要导进来*/
//1.导入两个C3P0连接池的jar包(mchange-commons-java-0.2.12)(c3p0-0.9.5.2)
//配置文件configuration,两种方式--使用xml的方式,很少用properties
//2.在项目的classpath路径下(项目的src下面)导入配置文件
//3.生成连接池对象 DataSource (接口) CombolPooledDataSource
DataSource ds=new ComboPooledDataSource(); //自动去加载配置文件,不需要写代码实现
//4.创建连接对象 getConnection()
Connection connection = ds.getConnection();
//System.out.println(connection);
//5.定义一个sql语句
String sql="select * from account";
//6.获取预编译对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//7.执行sql语句
ResultSet resultSet = preparedStatement.executeQuery();
//8.控制台输出
while(resultSet.next()){
String name = resultSet.getString("name");
System.out.println(name);
}
}
}

3.不使用系统默认的C3P0连接池,而是使用其它的C3P0连接池

package com.bianyiit.cast;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class C3P0LianJieChiDemo2 {
public static void main(String[] args) throws SQLException {
DataSource ds=new ComboPooledDataSource("otherc3p0");
for (int i = 0; i < 5; i++) {
Connection connection = ds.getConnection();
System.out.println(connection);
/*if(i==5){
connection.close();  //归还连接对象,而不是清除连接对象
}*/
}
//在配置文件中可以配置多个C3P0连接池,满足不同的客户需求
}
}

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

1.Druid 阿里巴巴提供的一个性能非常稳定,功能很强大的一个连接池,推荐使用

2.Druid的jar包和对应的配置文件

链接:https://pan.baidu.com/s/17YJIbt_bYFm7V6abbN0qDw
提取码:tcli
复制这段内容后打开百度网盘手机App,操作更方便哦

3.Druid配置文件中的具体内容

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/student02
username=root
password=123
#初始化时连接池中连接对象的个数
initialSize=5
#最大的连接对象的个数
maxActive=10
#超时时间(延迟三秒报错)
maxWait=3000

4.使用Druid连接池的具体步骤

1.导入Druid的jar包
2.导入配置文件(Druid的配置文件跟C3P0的配置文件有所区别)
/*Druid的配置文件不能被连接池对象自动加载,需要手动加载
关于路径问题:Druid配置文件可以放任意的位置,建议还是放在classpath下面,也就是输入src下面
Druid配置文件是一个properties文件*/
3.创建连接池对象 DataSource 需要一个工厂类DruidDataSourceFactory去创建对象
//注意:需要把配置文件加载进来
4.通过getConnection获取连接对象
//执行sql语句
//归还连接对象

5.代码演示

package com.bianyiit.cast;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

public class DruidDemo1 {
public static void main(String[] args) throws Exception {
//Druid 阿里巴巴提供的一个性能非常稳定,功能很强大的一个连接池,推荐使用
//如何使用Druid连接池
//1.导入Druid的jar包
//2.导入配置文件(Druid的配置文件跟C3P0的配置文件有所区别)
/*Druid的配置文件不能被连接池对象自动加载,需要手动加载
关于路径问题:Druid配置文件可以放任意的位置,建议还是放在classpath下面,也就是输入src下面
Druid配置文件是一个properties文件
* */
//3.创建连接池对象 DataSource 需要一个工厂类DruidDataSourceFactory去创建对象
//注意:需要把配置文件加载进来
//加载配置文件
Properties ps = new Properties();
FileInputStream is=new FileInputStream("D:\\学习专用代码库\\StudyCode\\database2\\src\\druid.properties");
//InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
ps.load(is);
DataSource ds=DruidDataSourceFactory.createDataSource(ps);
//4.通过getConnection获取连接对象
Connection connection = ds.getConnection();
System.out.println(connection);
//执行sql语句
//归还连接对象
//connection.close();
}
}

五、将Druid重复使用得内容抽取成一个Druid工具类

1.DruidUtils工具类

package com.bianyiit.cast;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

//Druid连接池的工具类
/*
* 1.获取连接池对象
* 2.获取连接对象
* 3.归还连接对象的方法
* 4.静态代码块(因为在创建连接池对象之前就需要加载好配置文件中的所有信息)
* */
public class DruidUtils {
private static DataSource ds;
//用来加载配置文件并创建好一个连接池对象
static {
Properties ps=new Properties();
try {
ps.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ps);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//有没有必要提供一个获取连接池对象的方法??---框架中可能只需要连接池对象,不需要连接对象
public static DataSource getDataSource(){
return ds;
}
//归还连接对象的方法
//有一种是有结果集的连接(查询),
public static void close(PreparedStatement psmt, Connection con, ResultSet rs){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
if(rs!=null){
rs.close();
rs=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//有一种没有结果集的连接(增删改)
public static void close(PreparedStatement psmt, Connection con){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

2.使用DruidUtils做一个具体案例

package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.PreparedStatement;

//使用工具类做个案例:往account表中添加一行数据
public class DruidDemo3 {
public static void main(String[] args) {
Connection connection=null;
PreparedStatement preparedStatement=null;
try {
connection = DruidUtils.getConnection();//获取连接对象
//通过连接对象获取预编译对象
String sql="insert into account(id,name,balance)values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,4);
preparedStatement.setString(2,"王五");
preparedStatement.setDouble(3,1200);
preparedStatement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//归还连接对象
DruidUtils.close(preparedStatement,connection);
}
}
}

六、Spring JDBC

1.JDBCTemplate:Spring框架对于JDBC的操作sql语句的一种封装

2.Spring框架提供的一个封装类,里面有很多的方法可以简化sql语句的编写

3.注意:JDBCTemplate依赖于连接池才能使用

4.使用JDBCTemplate的步骤

1. 导入jar包
2. 创建JdbcTemplate对象。依赖于连接池对象DataSource
2.1 创建ds对象
DataSource ds = DruidUtils.getDataSource();
2.2 JdbcTemplate template = new JdbcTemplate(ds);

4. 调用JdbcTemplate的方法来完成CRUD的操作
3.1	update():执行DML语句。增、删、改语句
3.2 queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
//注意:这个方法查询的结果集长度只能是1
3.3	queryForList():查询结果将结果集封装为list集合
//注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
3.4	query():查询结果,将结果封装为JavaBean对象
//query的参数:RowMapper
1. 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
2. new BeanPropertyRowMapper<类型>(类型.class)
3.5	queryForObject:查询结果,将结果封装为对象
//一般用于聚合函数的查询

JDBCTemplate的五个jar包

链接:https://pan.baidu.com/s/1hIsvl83CMvQkeqA957mjyA
提取码:hc9w
复制这段内容后打开百度网盘手机App,操作更方便哦

DruidUtils工具类

package com.bianyiit.cast;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

//Druid连接池的工具类
/*
* 1.获取连接池对象
* 2.获取连接对象
* 3.归还连接对象的方法
* 4.静态代码块(因为在创建连接池对象之前就需要加载好配置文件中的所有信息)
* */
public class DruidUtils {
private static DataSource ds;
//用来加载配置文件并创建好一个连接池对象
static {
Properties ps=new Properties();
try {
ps.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ps);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//有没有必要提供一个获取连接池对象的方法??---框架中可能只需要连接池对象,不需要连接对象
public static DataSource getDataSource(){
return ds;
}
//归还连接对象的方法
//有一种是有结果集的连接(查询),
public static void close(PreparedStatement psmt, Connection con, ResultSet rs){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
if(rs!=null){
rs.close();
rs=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//有一种没有结果集的连接(增删改)
public static void close(PreparedStatement psmt, Connection con){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

5.代码演示

package com.bianyiit.cast;

import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

public class DruidDemo2 {
public static void main(String[] args) {
//如何使用Spring对JDBC的封装--操作如下步骤
//1.导入五个jar包
//创建ds对象
DataSource ds = DruidUtils.getDataSource();
//2.创建用于简化sql语句的JDBCTemplate对象,必须依赖于连接池对象
JdbcTemplate jdbcTemplate=new JdbcTemplate(ds);
//定义一个sql语句
String sql="UPDATE denglu set password=? where username=?";
//3.执行sql语句
int i = jdbcTemplate.update(sql, 998998, "猪八戒");
System.out.println(i);
}
}

七、连接池综合练习—建议使用Druid工具类和Spring对JDBC的封装类

1.需求

1. 修改1号数据的 salary 为 10000
2. 添加一条记录
3. 删除刚才添加的记录
4. 查询id为1的记录,将其封装为Map集合
5. 查询所有记录,将其封装为List
6. 查询所有记录,将其封装为Emp对象的List集合
7. 查询总记录数

2.代码演示--不写主方法,使用Junit单元测试完成

package com.bianyiit.cast;

import com.bianyiit.domian.Employee;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/*1. 修改1号数据的 salary 为 10000
2. 添加一条记录
3. 删除刚才添加的记录
4. 查询id为1的记录,将其封装为Map集合
5. 查询所有记录,将其封装为List
6. 查询所有记录,将其封装为Emp对象的List集合
7. 查询总记录数*/
public class DruidDemo4 {
//实体类与数据库的关联  表--类  每一条数据--对象  字段--属性
//第一步:创建JDBCTemplate 对象
private JdbcTemplate jdbcTemplate = new JdbcTemplate(DruidUtils.getDataSource());
//1.修改1号数据的 salary 为 10000
@Test
public void test1(){
//定义sql语句
String sql="update emp set salary=? where id=?";
//执行sql语句
int update = jdbcTemplate.update(sql, 80, 1);
System.out.println(update);
}
//2. 添加一条记录
@Test
public void test2(){
//定义sql语句
String sql="insert into emp value(?,?,?,?,?,?)";
//执行sql语句
int update = jdbcTemplate.update(sql,9,"沙和尚","男","7777",null,2);
System.out.println(update);
}
//3.删除刚才添加的记录
@Test
public void test3(){
//定义sql语句
String sql="delete from emp where id=?";
//执行sql语句
int update = jdbcTemplate.update(sql,9);
System.out.println(update);
}
//4.查询id为1的记录,将其封装为Map集合
@Test
public void test4(){
//定义sql语句
String sql="select * from emp where id=?";
//执行sql语句
Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(sql,1);
System.out.println(stringObjectMap);
//注意:此方法的结果集只能是一条数据!
}
//5. 查询所有记录,将其封装为List
@Test
public void test5(){
//定义sql语句
String sql="select * from emp";
//执行sql语句
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
//6. 查询所有记录,将其封装为Emp对象的List集合
@Test
public void test6(){
//定义sql语句
String sql="select * from emp";
//执行sql语句
List<Employee> list = jdbcTemplate.query(sql, new RowMapper<Employee>() {
@Override
public Employee mapRow(ResultSet resultSet, int i) throws SQLException {
//通过结果集获取字段的每一个值
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String gender = resultSet.getString("gender");
String salary = resultSet.getString("salary");
Date join_date = resultSet.getDate("join_date");
String dept_id = resultSet.getString("dept_id");

//创建员工对象
Employee employee = new Employee();
employee.setId(id);
employee.setName(name);
employee.setGender(gender);
employee.setSalary(salary);
employee.setDate(join_date);
employee.setDept_id(dept_id);
return employee;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
}
//7.优化
@Test
public void test7(){
//定义sql语句
String sql="select * from emp";
//执行sql语句
List<Employee> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Employee>(Employee.class));
for (Employee employee : list) {
System.out.println(employee);
}
//注意:类中的属性要使用包装类修饰
}
//8. 查询总记录数--聚合函数
@Test
public void test8(){
//定义sql语句
String sql="select count(id) from emp";
//执行sql语句
Long count = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(count);
}
}

最后小编教大家如何往IDEA里面导入jar包和配置文件,并创建DruidUtils工具类。

第一步:在你的模块/项目下面新建一个libs文件夹


第二步:下载对应的jar包,具体的链接地址已经在本文中标注好了

第三步:复制下载好的jar包,保存到libs目录下


第四步:添加依赖,首先右击jar包,选择Add as Library,然后选择要导入的模块/项目,点击OK



第五步:将下载好的配置文件复制粘贴进src目录下


第六步:创建一个工具类DruidUtils

package com.bianyiit.cast;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

//Druid连接池的工具类
/*
* 1.获取连接池对象
* 2.获取连接对象
* 3.归还连接对象的方法
* 4.静态代码块(因为在创建连接池对象之前就需要加载好配置文件中的所有信息)
* */
public class DruidUtils {
private static DataSource ds;
//用来加载配置文件并创建好一个连接池对象
static {
Properties ps=new Properties();
try {
ps.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(ps);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//有没有必要提供一个获取连接池对象的方法??---框架中可能只需要连接池对象,不需要连接对象
public static DataSource getDataSource(){
return ds;
}
//归还连接对象的方法
//有一种是有结果集的连接(查询),
public static void close(PreparedStatement psmt, Connection con, ResultSet rs){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
if(rs!=null){
rs.close();
rs=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//有一种没有结果集的连接(增删改)
public static void close(PreparedStatement psmt, Connection con){
try {
if(psmt!=null){
psmt.close();
psmt=null;
}
if(con!=null){
con.close();
con=null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
飞奔的嗨少 发布了74 篇原创文章 · 获赞 11 · 访问量 3035 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: