欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

mysql常用命令、库操作汇总

程序员文章站 2022-04-08 11:18:25
MySQL  数据库(DataBase,DB):指长期保存在计算机的存储设备上,按照一定规则组织起来,可以被各种用户或应用共享的数据集合。(7文件系统) 数据库管理系...

MySQL 

数据库(DataBase,DB):指长期保存在计算机的存储设备上,按照一定规则组织起来,可以被各种用户或应用共享的数据集合。(7文件系统)

数据库管理系统(DataBase Management System,DBMS):指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。用户通过数据库管理系统访问数据库中的数据。

数据库软件应该为数据库管理系统,数据库是通过数据库管理系统创建和操作的。

数据库:存储、维护和管理数据的集合。

1登录Mysql: mysql -u root -p abc

2* 卸载

1.停止mysql服务 ??net stop mysql ??????启动mysql服务 ?net start mysql

2.卸载mysql

3.找到mysql 安装目录下的 my.ini ??datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/"

3* 修改密码

运行cmd

* 安装成功了打开cmd ?--> mysql -uroot -p你的密码

* 修改mysql root用户密码

1) 停止mysql服务 运行输入services.msc 停止mysql服务

或者 cmd --> ?net stop mysql

2) 在cmd下 输入 mysqld --skip-grant-tables 启动服务器 光标不动 (不要关闭该窗口)

3) 新打开cmd 输入mysql -u root -p 不需要密码

use mysql;

update user set password=password('abc') WHERE User='root';

4) 关闭两个cmd窗口 在任务管理器结束mysqld 进程

5) 在服务管理页面 重启mysql 服务

密码修改完成

数据库中一行记录与对象之间的关系。 列:字段 行:一条记录(实体) ?这样就很方便用java语言获取数据

public class User{ private int id; private String name; private int age; }

三、sql概述 SQL:Structure Query Language。(结构化查询语言)

4、Sql的分类

DDL**(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等; CREATE create、 ALTER alter、DROP drop

DML***(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据); ??? INSERT insert、 UPDATE update、 DELETE delete

DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;

DQL*****(Data Query Language):数据查询语言,用来查询记录(数据)。

1库--操作4

1增3 创建 create ?语法 ?create database 数据库名 [character set 字符集][collate ?校对规则]

(database/databases 关键字只在对数据库的操作时见到)

create database mydb1;

Create database mydb2 character set gbk;

Create database mydb3 character set gbk collate gbk_chinese_ci;

2删1 drop

前面创建的mydb3数据库 Drop database mydb3;

3改1??这里改动的是字符集 ?alter

查看服务器中的数据库,并把mydb2的字符集修改为utf8; alter database mydb2 character set utf8;

4查4 show 4

?1查看当前数据库服务器中的所有数据库show databases;

?2查看前面创建的mydb2数据库的定义信息:查数据库创建语句 Show create database mydb2;

?3查看当前使用的数据库 语法select database();

5切换数据库use mydb2;

2表--操作4

在创建表之间一定要指定数据库. use 数据库名 ???最后一个字段不加 逗号

*语法:

create table 表名(

字段1 字段类型,

字段2 字段类型,

...

字段n 字段类型

);

1 常用数据类型:10

int:整型

float:浮点型:float(5,2)--> 999.99, -999.99 表示浮点型数长度为5 小数位为2 ?一般不需要这样指定长度。

double:浮点型,例如double(5,2)表示最多5位,其中必须有2位小数,即最大值为999.99;

char:固定长度字符串类型; char(10) ?'abc ??????' ??申请的速度快 ?但是费内存

varchar:可变长度字符串类型;varchar(10) 'abc' ?这个与char相比较 ?比如给定的长度是10 ?但是就用了5 那5个就会不分配 省内存

text:字符串类型;

blob:字节类型;

date:日期类型,格式为:yyyy-MM-dd;

time:时间类型,格式为:hh:mm:ss

timestamp:时间戳类型 yyyy-MM-dd hh:mm:ss ?会自动赋值

datetime:日期时间类型 yyyy-MM-dd hh:mm:ss-

decimal(7,2), 数的长度是7,有两位是小数点

2 约束种类4

1 not null; 非空 ??

2 unique;唯一约束, 后面的数据不能和前面重复

3 primary key;主键约束(非空+唯一); ?id:作为数据的唯一标识,通常给id int类型设置主键约束,auto_increment ?null

4 auto_increment;自动增长列 ,一定是和主键一起使用的。

3 增1

2.1.创建表 对表结构的操作(table/tables关键字只会出现在对表结构的操作sql语句中)

不能创建同名称的表 ??创建表的时候必须有字段 ??没字段就是一个空表 没有意义

删除表 ?要是删除表的最后一个字段 ?只能用drop删除 ??用删除列的方式不能删除表的最后一个字段 那样那个表就是一个空表了 没有意义

create table student(

id int primary key auto_increment,

name varchar(10),

score double,

address varchar(10)

);

添加主建约束的方式

第一种添加方式:第一种添加方式:此种方式优势在于,可以创建联合主键

CREATE TABLE student(Id int primary key,Name varchar(50));

第二种添加方式:

CREATE TABLE student(id int, Name varchar(50), Primary key(id) );

CREATE TABLE student(id int,Name varchar(50),Primary key(id,name));

第三种添加方式:

CREATE TABLE student(Id int,Name varchar(50)); ALTER TABLE student ??ADD ?PRIMARY KEY (id);

创建 索引

普通索引 ??添加INDEX

ALTER TABLE `table_name` ADD INDEX index_name ( `column` ) ?这是修改然后加上索引

直接通过create index的方式

CREATE FULLTEXT INDEX ft_email_name ON `student` (`name`)

也可以在创建索引的时候指定索引的长度:

CREATE FULLTEXT INDEX ft_email_name ON `student` (`name`(20)) 直接创建索引

?

主键索引 ??添加PRIMARY KEY

ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )

唯一索引 ???添加UNIQUE

ALTER TABLE `table_name` ADD UNIQUE ( `column` )

全文索引 ???添加FULLTEXT

ALTER TABLE `table_name` ADD FULLTEXT ( `column`)

如何添加多列索引

ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )

?

4 删1

1 删除表 drop table 表名;

5 改4 add ?change大 ?modify小 rename

?1增加列 alter table 表名 add 字段名 类型(长度) 约束;

?2修改字段 名称 类型 约束。alter table 表名 change 旧字段名 新字段名 类型 约束; 换成同一个名字也可以

?3修改列的类型和约束 alter table 表名 modify 字段名 类型 约束;

?4删除列 alter table 表名 drop 字段名;

?5 修改表名 rename table 旧表名 to 新表名

6 查3

1 查看当前数据库下的所有表show tables; ??显示所有的表名字

2 查看当前数据库某个表的结构 desc 表名; 显示表中 所有的字段 和属性

3 查看employee的表结构 ?show create table employee

3 数据--操作4 增改都不出现table

1增2

1增加数据 insert into 表名(字段1,字段2,字段3) values(值1,值2,值3);

2 insert into 表名 values(值1,值2,值3,值4);有几个字段就有几个值,如果不想给字段赋值,也要写空

注意:

- 没有赋值的列,系统自动赋为null

- 列名与列值的类型、个数、顺序要一一对应。

- 值不要超出列定义的长度。

- 如果插入空值,请使用null

- 插入的日期和字符串,使用引号括起来

2删2 delete where

1 delete from star;删除数据(一次至少删除一条数据,不能删除某条数据的某个字段) delete from 表名 [where 条件];不写条件表示将所有数据全部删除 ?表结构还在;删除后的数据可以找回

2 trancate 表名;删除表,trancate table star;并新建一张一样结构和名字的该表。

区别 - DELETE 删除表中的数据,表结构还在;删除后的数据可以找回

- TRUNCATE 删除是把表直接DROP掉,然后再创建一个同样的新表。删除的数据不能找回。执行速度比DELETE快。

3改1 update set where

1更新数据 update 表名 set 字段1=值1,字段2=值2 [where 条件];不写条件表示将所有数据字段1的值改成值1,字段2的值改成值2

?可以写成 ??字段1= 字段1+2000; 可以是+-*/ ??但是不能是+= ??前面的类型只能是数 ?要是字符串只显示后面的数值

日期查询

定义和用法

DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据。

语法

DATE_FORMAT(date,format)

date?参数是合法的日期。format?规定日期/时间的输出格式。

可以使用的格式有:

格式

描述

%a

缩写星期名

%b

缩写月名

%c

月,数值

%D

带有英文前缀的月中的天

%d

月的天,数值(00-31)

%e

月的天,数值(0-31)

%f

微秒

%H

小时 (00-23)

%h

小时 (01-12)

%I

小时 (01-12)

%i

分钟,数值(00-59)

%j

年的天 (001-366)

%k

小时 (0-23)

%l

小时 (1-12)

%M

月名

%m

月,数值(00-12)

%p

AM 或 PM

%r

时间,12-小时(hh:mm:ss AM 或 PM)

%S

秒(00-59)

%s

秒(00-59)

%T

时间, 24-小时 (hh:mm:ss)

%U

周 (00-53) 星期日是一周的第一天

%u

周 (00-53) 星期一是一周的第一天

%V

周 (01-53) 星期日是一周的第一天,与 %X 使用

%v

周 (01-53) 星期一是一周的第一天,与 %x 使用

%W

星期名

%w

周的天 (0=星期日, 6=星期六)

%X

年,其中的星期日是周的第一天,4 位,与 %V 使用

%x

年,其中的星期一是周的第一天,4 位,与 %v 使用

%Y

年,4 位

%y

年,2 位

实例

下面的脚本使用 DATE_FORMAT() 函数来显示不同的格式。我们可以使用 NOW() 来获得当前的日期/时

将数据库中存放的年月日时分秒字符串如20150119221048转换为2015-01-19 22:10:48

[sql]?view plain?copy?print?

1.?select??seq_no,show_mode,dev_id,dev_type,dev_attr,content_attr,???

2.?????????content_path,file_name,date_format(start_time,?'%Y-%m-%d?%H:%i:%s'),date_format(end_time,?'%Y-%m-%d?%H:%i:%s'),???

3.?????????regular_time,order_level,operator_level,order_state?from??order_execute_info??????

4.?????????where?dev_type?=?'0011'?order?by?dev_id?asc;??

?

?

?

4查11 select ?from where like

注意: 聚合函数前面不能有字段名,除非是用于分组的字段名 ??聚合函数不能用在 where后面

语法:先后顺序select [列名,列名] [*] [聚合函数][distinct 字段] from 表名 [WHERE --> group by -->having--> order by] ??

?

?

?

SQL UNION 操作符

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。

请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

SQL UNION 语法

SELECT column_name(s) FROM table_name1

UNION

SELECT column_name(s) FROM table_name2

注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

SQL UNION ALL 语法

SELECT column_name(s) FROM table_name1

UNION ALL

SELECT column_name(s) FROM table_name2

另外,UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。

使用 UNION 命令

实例

列出所有在中国和美国的不同的雇员名:

SELECT E_Name FROM Employees_China

UNION

SELECT E_Name FROM Employees_USA

UNION ALL

UNION ALL 命令和 UNION 命令几乎是等效的,不过 UNION ALL 命令会列出所有的值。

?

?

?

字段1 表示显示那个字段

顺序: select...from...where...group by...having...order by

from 表名 [where 条件]----->[group by 字段]----->[having 条件(分组后的条件)]----->[order by];

先分组 分组后聚合函数统计每组的数量

有分组 字段哪里就不能写*号

1 查询所有的列的记录 ?????select * from 表名;

2 查询某张表特定列的记录??select 字段名1,字段名2 from 表名;

3 去重查询 (distinct 字段) ??select distinct 字段名 from 表名; ?去重字段名只能写一个 ?要是,字段名2 ??后面的字段只是显示出来不具有去重原理

这是筛选某个字段重复 ?去除重复记录(两行或两行以上记录中系列的上的数据都相同) 上面可以多个字段,查询多个字段的值不同时重复

例如- 把年龄重复的给筛选 ?要查询的字段的数据一模一样才能去重

4 ?别名查询 (字段 as ?别名, as可以省略)??select 字段名1 as 姓名 from 表名; ?可以写多个 ?但是必须带引号

只是为了展示得更容易看懂一点,其实没啥作用- 查询明星名称和价格,明星价格通过别名‘身价’来显示

5 运算查询(+,-,*,/等)??select 字段名+10 ?from 表名; - 把明星名称,

和明星年龄+10查询出来 要是字符串+10 就只显示后面的10 没有意义运算查询字段字段之间是可以的?显示要求的新字段

6 条件查询7都是在where后面用的

l?注意 between...and...: 包含临界值 eg: between 3000 and 6000相当于: 3000<=price<=6000

l?1 In ??2 between and ?3 is null ?is not null ???4 and ?5 or ??6 not ?7通配符 like ?’%_’

l?- 查询id在1,5,10,15范围内的明星 select * from star where id in(1,5,10,15)

7 模糊查询,like和通配符一起使用: %;多位(0~n)_; 一位

8 排序; order by 列名 asc(默认升序可以不写) ?desc(降序)???????排序语句放在查询语句的最后面!

????1 Order by price 直接升序 ??order by price asc, age; ?2先升序 如果价格一样 按照age升序 ???3 order by asc, age desc; ?先升序如果价格一样按照 age 降序

?

9 聚合函数?(聚合函数前不能有字段名,如果一定要有,那么该字段名只能是用来分组的字段名)聚合函数是用来做纵向运算的函数 ?

如果前面有字段了只显示第一个字段的值 后面显示筛选值, ?后面可以有 as “最大值”

1.?count(*|字段);统计指定列不为NULL的记录行数 ??????,

2.?如果要统计表中的总记录数,那么count( *|不能为空的字段名)

3.?sum();计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0

4.?max();筛选指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算 abc的排序

5.?min();筛选指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算 如果有2个最小值一样 就显示出来第一个

6.?avg();计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0

10 分组查询,单独使用group by,只显示各个组的第一条数据()

?- group by结合group_concat()使用,可以展示每一组的数据集合,group_concat()中不能写*

??- select type,group_concat(name) from start group by type;分组查询select后面一定要跟上分组的字段名

解释 type 表示显示分组后 第一个name字段的 type ?????group_concat(name) 多显示组 这组字段为group_concat(name) 把所有人的姓名显示出来

查询所有的明星,按照type分组

select * from star group by type; ?//只显示每组中的第一条信息

select type,group_concat(*) from star group by type; //错误的写法

Select name from star group by type ?// 显示每组中的第一个姓名

select type,group_concat(name) from star group by type; //显示每组中每个人的姓名

?

- group by结合聚合函数使用(聚合函数前写得字段名必须是用于分组的字段名) ??用聚合函数都是用于数理统计的数, ?字段类型都是数据类型

??- 统计每一组的数据个数 ?select type,count(*) from product group by type;

??- 统计每一组的数据的总价格 ?select type,sum(price) from product group by type;

??- 统计每一组的数据中价格最小的那个 ???select type,min(price) from product group by type;

- 根据明星类别分组,统计不同明星类别的个数

- 根据明星类别分组,统计不同明星类别的总价格

11 分组后筛选(having)

- 根据明星类别分组,统计不同明星类别的个数,并且该明星类别数量大于2的

注意:

- having是分组后筛选

where和having的区别

- 1.having是在分组后对数据进行过滤.where是在分组前对数据进行过滤

- 2.having后面可以使用聚合函数(统计函数)where后面不可以使用聚合函数

- 3.having后面加的条件一定要与分组有关。

-?4.WHERE是分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分组;而HAVING是对分组后数据的约束。

?

自己 Select *, price>3000 from star1; 查询 身价大于3000的 后面会加一行 ??前面加的这个price>3000 是自加字段 这是一个boolean值 ?数据都显示的boolea值

?

比如:

一般条件放到 where后面 ?需要分组后的条件放到 having后面

select type,count(*) from star group by type having count(*)>2;

?分组后统计 每组的长度大于2

select type,count(*) from star where count(*)>2 group by type;

?Where后面不能加聚合函数 ?这个错误

select type,count(*) from star where age>30 group by type;

先把大于30岁的筛选出来再分组

select type,count(*) from star group by type having age>30;

自己理解 这个是年龄>30岁和这个分组没有关系 ?相当于冲突了 ?这个错误 ??一般后面跟聚合函数 ?与分组有关的条件

这样加的条件就和后面的没有关系了

小知识:

在mysql中,字符串类型和日期类型都要用单引号括起来。'tom' ?'2015-09-04'

空值:null

?

语法:

SELECT selection_list /*要查询的列名称*/

??FROM table_list /*要查询的表名称*/

??WHERE condition /*行条件*/

??GROUP BY grouping_columns /*对结果分组*/

??HAVING condition /*分组后的行条件*/

??ORDER BY sorting_columns /*对结果分组*/

??LIMIT offset_start, row_count /*结果限定*/

?

4 数据的完整性3

作用:保证用户输入的数据保存到数据库中是正确的。确保数据的完整性 = 在创建表时给表中添加约束

完整性的分类:> 实体完整性 ?> 域完整性 ?> 引用完整性

1、实体完整性

实体:即表中的一行(一条记录)代表一个实体(entity) 实体完整性的作用:标识每一行数据不重复。

约束类型: 主键约束(primary key) ?唯一约束(unique) ?自动增长列(auto_increment)

给主键添加自动增长的数值,列只能是整数类型,但是如果删除之前增长的序号,后面再添加的时候序号不会重新开始,而是会接着被删除的那一列的序号

CREATE TABLE student(Id int primary key auto_increment,Name varchar(50));

INSERT INTO student(name) values(‘tom’);

2、域完整性

域完整性的作用:限制此单元格的数据正确,不对照此列的其它单元格比较域代表当前单元格

域完整性约束:数据类型 非空约束(not null) 默认值约束(default) Check约束(mysql不支持) check();

1.1 数据类型:(数值类型、日期类型、字符串类型)1.2 非空约束:not null

1.3 默认值约束 default

CREATE TABLE student(Id int pirmary key,Name varchar(50) not null,Sex varchar(10) default ‘男’);

insert into student1 values(1,'tom','女');

insert into student1 values(2,'jerry',default);

3、引用完整性 添加外键

表和表之间存在一种关系,但是这个关系需要谁来维护和约束?

1外键约束外键作用:??保证引用完整性,也就是说数据的准确

注意??外键列的类型一定要和参照的主键的类型一致

l?1 省略外键名字 系统会自动为外键起名字 - alter table 表 add [constraint?外键名] foreign key(字段) references 表(字段);

l?2 给外键起一个名字 alter table product add constraint fk_p2c foreign KEY (p_pno) references category(c_cno);

l?3 删除外键去除关系 alter table product drop foreign key fk_p2c;

l?3 要是没有写外键名字 就要到数据库操作软件里面去找(资料) 外键的名字 ??然后删除

l?3 创建数据库的时候外键的名字不能相同

- 给商品表添加外键? alter table product add foreign key(cno) references category(cid);

1一对多(掌握) ?在多的一方创建一个字段作为外键,指向一的一方主键

2多对多(掌握) ?新建一张第三方表,至少包含两个字段,都作为外键,分别指向各自的主键

3一对一(了解) ?先当做一对多,在外键字段添加唯一约束。

5多表查询6

1?交叉查询???若干表没有条件的连接在一起

select a.*,b.* from a,b ;或者 select *from a,b;- 交叉查询其实是一种错误.数据有很多无用数据,叫笛卡尔积.

- 假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。

- 交叉查询产生这样的结果并不是我们想要的,那么怎么去除错误的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。

2?内连接查询(重点)

1 隐式内连接select a.*,b.* from a,b where 连接条件 或者:select * from a, b where 连接条件

2 显示内连接select a.*,b.* from a [inner] join b on 连接条件或者:select *from a [inner] join b on 连接条件 where 其它条件

- 使用主外键关系做为条件来去除无用信息.抓住主外键的关系,用主外键作为连接条件 ?b表里面的外键=a表里面主键

- 显示里面的,on只能用主外键关联作为条件,如果还有其它条件,后面加where

3 外连接(重点)

1左外连接 以join左边的表为主表,展示主表的所有数据,根据条件查询连接右边表的数据,若满足条件则展示,若不满足则以null显示

select a.*,b.* from a left [outer] join b on 条件??或者: select *from a表 left [outer] join b表 on 条件

2右外连接 以join右边的表为主表,展示它的所有数据,根据条件查询join左边表的数据,若满足则展示,若不满足则以null显示

select a.*,b.* from a right [outer] join b on 条件?或者:??select *from 表a right [outer] join 表b on 条件

4 子查询?

- 一个select语句中包含另一个完整的select语句。

- 子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。

1步骤解析??子查询这个iPhone 必须是唯一 ?否则产生错误, 子查询可以和 内外连接一起使用

- 第一步:查询Iphone5s的商品价格select price from product where pname = 'Iphone5';

- 第二步:查询价格高iPhone5s的商品信息 select *from product where price >(第一步语句作为条件)

2 例子

- 查询和方便面是同一类别的商品信息 SELECT *from product where cno = (SELECT cno from Product where pname ='方便面') and pname <> '方便面';

- 查询类别是手机数码的所有商品信息 select *from product where cno = ?(SELECT cid FROM category where cname ='手机数码');

5 联合查询(了解)

- 合并结果集就是把两个select语句的查询结果合并到一起

1语法- union:去除重复记录,例如:SELECT * FROM t1 UNION SELECT * FROM t2

- union all:不去除重复记录,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2

6 分页查询(掌握)

Limit优点 ??查到需要多少页数的数据后 ?就不再向后查询

- limit a,b; - a:从哪里开始(从0开始计数的)?偏移量 - b:一页显示数据的数量 ??固定值 前端或者安卓,ios

????a = (curPage-1)*b;// curPage当前页数 ?

一页显示3条数据: ?第1页: a = 0; b ?= 3;

第2页: a?= 3; b = 3;

第3页:a = 6; ?b ?= 3;

第四页:a=9,b=3.

8 JDBC的概念?day10

学习目的 ; 1自己创建jdbcUtils ??2用dbcp创建 dbcpUtils ???3用C3p0创建 C3P0Utils ??4直接使用框架DBUtils 操作数据库

在上面建的类都是?有这三个方法 ??1注册驱动 ?2获得链接 ??5关闭资源?

*单一职责、开放封闭、依赖倒置、迪米特法则、里氏替换、接口隔离

1 什么是JDBC - JDBC:java database connectivity sun公司为了简化和统一java连接数据库,定义的一套规范(API)

2 JDBC和数据库驱动的关系 - 接口(JDBC)与实现(驱动jar包)的关系

1开发第一个JDBC程序`开发步骤

① - 注册驱动(要引入驱动jar包)

1 registerDriver(Driver driver) ;注册驱动,Driver类中包含一个静态代码块

翻阅源码发现,通过API的方式注册驱动,Driver会new两次,所有推荐这种写法: Class.forName("com.mysql.jdbc.Driver");

② - 获得连接

1.2 getConnection(String url, String user, String password) ;与数据库建立连接

Jdbc:mysql://localhost:3306/web06_1; ??jdbc;协议 mysql:子协议 localhost:主机名 3306:端口号 web06_1:数据库名 ??eg:https://www.baidu.com

③ - 创建执行sql语句的对象

- 接口的实现在数据库驱动中。所有与数据库交互都是基于连接对象的。

2.1createStatement() ;创建执行sql语句对象

2.2prepareStatement(String sql) ;创建预编译执行sql语句的对象?.setInt(1,1) 设置第一个问号 ??setString(2,”李四”)设置第二个问号 ?setnull(3,null) 设置第三个问号为null

④ - 执行sql语句,处理结果

.java.sql.Statement接口

- 接口的实现在数据库驱动中

- 操作sql语句,并返回相应结果对象

1 ?Statement; 执行sql语句对象

- ResultSet ?executeQuery(String sql) 根据查询语句返回结果集。只能执行select语句。

- int executeUpdate(String sql) 根据执行的DML(insert update delete)语句,返回受影响的行数。

- boolean execute(String sql) ?此方法可以执行任意sql语句。返回boolean值,表示是否返回的是ResultSet结果集。仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;

2 得到结果集 java.sql.ResultSet接口 封装结果集,查询结果表的对象?用循环while 得到结果

- 提供一个游标,默认游 ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????指向结果集第一行之前。 把所有查询结果放到这个盒子里面 这是个集合或者什么 - 调用一次next(),游标向下移动一行。

- 提供一些get方法。

4.2ResultSet接口常用API

- boolean next() ;将光标从当前位置向下移动一行

- int getInt(int colIndex)以int形式获取ResultSet结果集当前行指定列号值

- int getInt(String colLabel)以int形式获取ResultSet结果集当前行指定列名值

- float getFloat(int colIndex)以float形式获取ResultSet结果集当前行指定列号值

- float getFloat(String colLabel)以float形式获取ResultSet结果集当前行指定列名值

- String getString(int colIndex)以String 形式获取ResultSet结果集当前行指定列号值

- String getString(String colLabel)以String形式获取ResultSet结果集当前行指定列名值

- Date getDate(int columnIndex); ?以Date 形式获取ResultSet结果集当前行指定列号值

- Date getDate(String columnName);以Date形式获取ResultSet结果集当前行指定列名值

⑤ - 关闭资源

- void close()关闭ResultSet 对象

2单元测试介绍

1. 介绍:JUnit是一个Java语言的单元测试框架。属于第三方工具,一般情况下需要导入jar包,不过,多数Java开发环境 已经集成了JUnit作为单元测试工具

2. 编写测试类,简单理解可以用于取代java的main方法

3. 在测试类方法上添加注解@Test

4. 注解修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。

5 添加eclipse中集成的Junit库,鼠标点击“@Test”,使用快捷键“ctrl + 1”,点击“Add Junit …”

6 使用:选中方法右键,执行当前方法;选中类名右键,执行类中所有方法(方法必须标记@Test)

7 常见使用错误,如果没有添加“@Test”,使用“Junit Test”进行运行,将抛异常

1 @Test 一定要写,并且就是@Test ?2方法一定要是public ?3不要返回值

?

3增强版本

1注册驱动加强

静态代码块 ?只要改类加载(改类种有语句运行,就运行这个)

1修改发现源码也是注册驱动这是这个代码 防止驱动开两次 就用反射 DriverManager.registerDriver(new Driver()); Class.forName("com.mysql.jdbc.Driver");

2执行sql语句的加强

2发现用Statement执行sql代码的时候 ?当输入的有 or id=1 ?就能正常通过 ??说明这个可以重改你的sql代码

String str = "select * from star1 where name='"+username+"'and price='"+password+"'";

Statement statement = connection.createStatement();

ResultSet resultSet = statement.executeQuery(str);

ResultSet resultSet = statement.executeQuery(str);

?

prepareStatement这个类extend Statement 类 这个首先把sql代码预编译 每个问号都是占位符 ?用户不能修改sql语句 ?这连个都是接口

String str = "select * from star1 where name= ? and price= ?";

PreparedStatement prepareStatement = connection.prepareStatement(str);

prepareStatement.setString(1, username);

prepareStatement.setInt(2, 5000);

ResultSet resultSet = prepareStatement.executeQuery();

3硬编码读取配置文件

1用字节流 2用类加载器 都是读到properties对象种 ??3种是直接从包下得到资源包 ?都是key value的形式

在静态块中来读流,读取配置文件中的数据

Properties properties = new Properties();

将数据加载进properties对象

1第一种读取配置文件的方法加载到properties中 (只能在java工程中用,对于web工程路径要改变)

FileInputStream in = new FileInputStream(new File("src/jdbcconfig.properties"));

2 第二种读取配置文件的方法 ?获取类的加载器只能用于获取src下面的文件

ClassLoader classLoader = JDBCUtil.class.getClassLoader();

InputStream ?in = classLoader.getResourceAsStream("jdbcconfig.properties"); ?//得到资源把资源转化成流

 

properties.load(in); ?//从输入流中读取到properties里面

要从properties对象中获取数据

url = properties.getProperty("url");

user = properties.getProperty("user");

password = properties.getProperty("password");

driverStr = properties.getProperty("driverStr");

 

3第三种读取配置文件的方法 ?只能用于获取src下面的 以.properties结尾的文件

ResourceBundle bundle = ResourceBundle.getBundle("jdbcconfig");

url = bundle.getString("url");

user = bundle.getString("user");

password = bundle.getString("password");

driverStr = bundle.getString("driverStr");

9 JDBC连接池

1.为什么使用连接池重写工具类

- Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了.每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中.每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.

.0队列和堆栈的区别

- 队列:先进先出,从头部移出数据,从尾部添加数据。吃了拉出来 - 堆栈:后进先出,从尾部添加数据,从尾部移出数据。吃了吐出来

1装饰着

1 编写连接池条件:1.装饰者和被装饰者实现的是同一个接口(或者继承了同一个类) 2.装饰者里面要拿到被装饰者类的引用

自己理解: 同一个父亲 ??1里面一个子类有全套的实现方法 ????2另一个子类改变第一个子类的某个方法 ??达到不同的效果

2 装饰着的理解: 把类1中的参数传到 类2中(这种传递的是引用类型,是实参,两个类公用的同一个参数,无论那个类里面对这个参数进行更改,这两个类都的参数都更改)

3 传参问题?直接匿名函数有参构造传值, ?2个功能 ?1向集合里面添加对象, 2匿名对象传对象, 3匿名对象传 本身增加的集合

现在传输的是个实际参数 ?是地址值 ??不管前后加了多少 ?我那个类里面就有多少. ??目的只是传输的地址值 不是传输的数量

4 使用连接池的步骤编码

//声明一个连接池,存放连接

static LinkedList pool = new LinkedList<>();

//类加载完毕,池子中就会有5个连接

static{

for(int i=0;i<5;i++){

try {

pool.add(new MyConnection(JDBCUtil.getConnection(), pool));

} catch (SQLException e) {

e.printStackTrace();

}

}

}

5 编写连接池遇到的问题

- 如果新建了connection,用完之后怎么判别是原池子中的connection(需要放回去),还是新建的connection(需要销毁)。

解决办法(自定义一个Connection,重写close方法)

- 继承 条件:可以控制父类的构造

- 装饰者模式 目的:改写已存在的类的某个方法或某些方法,装饰设计模式(包装模式)

1. 编写一个类实现一个接口,为被包装类

2. 编写一个类,实现与被包装类相同的接口。(具备相同的行为)

3. 定义一个被包装类类型的变量。

4. 定义构造方法,把被包装类类的对象注入,给被包装类变量赋值。

5. 对于不需要改写的方法,调用被包装类类原有的方法。

6. 对于需要改写的方法,写自己的代码。

- 动态代理

2 datasource接口概述

- Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商(用户)需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池! - 常见的连接池:DBCP、C3P0。 ??自己写用DriverManager 自己创建链接 ???用连接池就用DataSource

3 DBCP 增删改查

1使用步骤 ???总共有3个类组成 ??

1测试执行sql语句类

2 自己创建的DBCPUtil类 用于创建链接 得到连接池 ?关闭资源

3 DBCPUtil jar包导入两个

:Apache推出的Database Connection Pool 核心API: - basicDatasource - basicDatasourceFactory

2老师使用步骤

1- 添加jar包 ?commons-dbcp-1.4.jar ?commons-pool-1.5.6.jar

2- 添加配置文件到src目录

3- 编写数据源工具类

????4.1通过配置文件来编写public class DBCPUtils {

static DataSource ds;

static { //只需要初始化一次

try {

Properties properties = new Properties();

ClassLoader classLoader = DBCPUtil.class.getClassLoader();

InputStream in = classLoader.getResourceAsStream("dbcpconfig.properties");

properties.load(in);

//得到dbcp对象

ds= BasicDataSourceFactory.createDataSource(properties);

} catch (xception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

// 创建连接

public static Connection getConnection() throws SQLException {

return ds.getConnection;

}

// 释放资源

public static void release(ResultSet resultSet, Statement statement, Connection connection) {

}

4.2 通过硬编码来表写(不需要配置文件.了解一下)

DataSource basicDataSource = new BasicDataSource();

basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");

basicDataSource.setUrl("jdbc:mysql://localhost:3306/day01_1");

basicDataSource.setUsername("root");

basicDataSource.setPassword("123456");

4 C3P0 增删改查

开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml

只要创建对象 就自动读取配置文件

1使用步骤 4

1- 添加jar包

2- 编写配置文件c3p0-config.xml,放在src中(注:文件名一定不要写错)

3. 通过配置文件来编写 ?创建c3p0对象 ?对象自动会寻找读取配置文件 ??3创建对象

public class C3P0Utils {

//1创建一个连接池对象 自动链接里面的c3p0-config.xml文件

static DataSource ds = new ComboPooledDataSource();

//2从池中获得一个连接

public static Connection getConnection() throws SQLException{

return ds.getConnection();

}

//3释放资源

public static void closeAll(ResultSet rs,Statement stmt,Connection conn){

}

3 通过硬编码来编写(不需要配置文件.了解一下)

DataSource cpds = new ComboPooledDataSource();

cpds.setDriverClass("com.mysql.jdbc.Driver"); // loads the jdbc driver

cpds.setJdbcUrl("jdbc:mysql://localhost:3306/day01_1");

cpds.setUser("root");

cpds.setPassword("ai1996");

5 DBCP与C3P0区别优缺点

: dbcp线程池不能自动获取配置文件 ?要用上面3种方法读取 ??C3P0能自动读取 ?C3P0更强大

6 DBUtils完成CRUD

1 概述

1. DBUtils是java编程中的数据库操作实用工具,小巧简单实用。 第一个操作数据库框架(jar),

2. DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

3. Dbutils三个核心功能介绍

?

QueryRunner中提供对sql语句操作的API. ?update(), query()

ResultSetHandler接口,用于定义select操作后,怎样封装结果集.

DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

?

3.2QueryRunner核心类

- QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection

- update(String sql, Object... params) ,执行更新数据 insert update delete ?参数就是一个数组,参数个数取决于语句中?的个数

- query(String sql, ResultSetHandler rsh, Object... params) ,执行查询 select

- batch(sql, object[][] params) 批量添加数据 ??把数据写到二维数组中 ?每个一维数组 为每一行数据--update是只增加一个数据

?

3.3ResultSetHandler结果集处理类

Handler类型说明 ?????????????????????????????????????

ArrayHandler ???? 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值

ArrayListHandler 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。

BeanHandler?????? 将结果集中第一条记录封装到一个指定的javaBean中。 ???????????

BeanListHandler?? 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中

ColumnListHandler 将结果集中指定的列的字段值,封装到一个List集合中 ?????????????

KeyedHandler将结果集中每一条记录封装到Map,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。,object>

MapHandler ???将结果集中第一条记录封装到了Map集合中,key就是字段名称,value就是字段值,object>

MapListHandler 将结果集中每一条记录封装到了Map集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。,object>

ScalarHandler???它是用于单个数据。例如select ?count(*) from 表操作。

2使用步骤

1获取线程池对象(c3p0,dbcp)创建对象

2 获取dbutils对象 ?创建dbutils对象 直接把线程池传递过去

3 写sql语句 底层用prepareStatement查询 String sql = "select nickname from user where id=?"; Object[] param = {7};

4 用dbutils对象的方法 操作数据库

1当更新时 用update ??返回int类型 ?受影响的行数

l?1 new beanListHardler<>(User.class) ?查多列 就是集合(不管这个列里面有多少个数据)

l?2 New beanHardler<>(User.class) ????查一列 ?就是一个对象接收

l?3 New ScalarHardler() ?????????????查一个数据 ?用obje查询 ct 变量接收

注意当你写的查询语句 是多列 ?一列 ?一个 可以分别使用上面三个查询语句 并接受 从大到小都没有错 ?当查询多列用一个变量接收就只得到一个

?

10 Xml和反射

1 XML文档声明

Web.xml中servlet标签和servlet-mapping标签中的servlet-name值应该一致,否则启动服务器会抛出异常

1.文档声明必须为结束;2.文档声明必须从文档的0行0列位置开始;

3.文档声明只有三个属性:

a)versioin:指定XML文档版本。必须属性,因为我们不会选择1.1,只会选择1.0;

b)encoding:指定当前文档的编码。可选属性,默认值是utf-8;

c)standalone:指定文档独立性。可选属性,默认值为yes,表示当前文档是独立文档。如果为no表示当前文档不是独立的文档,会依赖外部文件。

2元素

1.元素是XML文档中最重要的组成部分,2.元素体:元素体可以是元素,也可以是文本,例如:你好

3.空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合,例如:

4.元素命名:

a)区分大小写

b)不能使用空格,不能使用冒号:

c)不建议以XML、xml、Xml开头

6.良好的XML文档,必须有一个根元素。

3 属性

1.属性是元素的一部分,它必须出现在元素的开始标签中

2.属性的定义格式:属性名=属性值,其中属性值必须使用单引或双引

3.一个元素可以有0~N个属性,但一个元素中不能出现同名属性

4.属性名不能使用空格、冒号等特殊字符,且必须以字母开头

l注释 XML的注释与HTML相同,即以“”结束。注释内容会被XML解析器忽略!

l转义字符 XML中的转义字符与HTML一样。

因为很多符号已经被XML文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用转义字符,例如:“<”、“>”、“’”、“””、“&”。

l5 转译多个 CDATA区

3 DTD重点要求

开发中,我们很少自己编写DTD约束文档,通常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档。常见框架使用DTD约束有:struts2、hibernate等。 通过提供的DTD“web-app_2_3.dtd”编写XML

4元素声明

空格 ?表示有没有都可以

定义元素语法:

元素名:自定义

元素描述包括:符号和数据类型

常见符号:? * + () | ,

常见类型:#PCDATA 表示内容是文档,不能是子标签

?

5属性声明

属性的语法:

属性名 属性类型 约束

属性名 属性类型 约束

...

>

元素名:属性必须是给元素添加,所有必须先确定元素名

属性名:自定义

属性类型:ID、CDATA、枚举 …

ID : ID类型的属性用来标识元素的唯一性

CDATA:文本类型

枚举:(e1 | e2 | ...) 多选一

约束:

#REQUIRED:说明属性是必须的;

#IMPLIED:说明属性是可选的;

l实例

给web-app元素添加 version属性,属性值必须是文本,且可选。

都符号约束

6 Schema约束

1.2.3.1什么是Schema

Schema是新的XML文档约束;

Schema要比DTD强大很多,是DTD 替代者;

Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。

Schema 功能更强大,数据类型更完善

Schema 支持名称空间

2 DOM4j框架使用步骤

1获取单个和多个标签

SAXReader reader =new SAXReader(); //1得到dom4j的对象

Document read = reader.read("src/book.xml");//2根据对象 读取xml到dom中

Element root = read.getRootElement(); //3得到根目录 String name = root.getName(); //获取跟目录的名字

1得到多个子标签

List ?list = root.elements(); ???//4得到父目录下的所有子标签 ??封装到List集合里面 ?可以遍历出来

Iterator iterator = root.elementIterator(); //4得到根目录下的所有子目录迭代器

Iterator iterator = root.elementIterator("书"); ?得到根目录下所有的书 子标签 ?

2得到一个多级子标签

Element element = (Element) root.selectSingleNode("/书架/书[2]/作者"); ?得到一个多级子标签

3得到多个多级标签

List list = root.selectNodes("书/书名"); ?//所有根目录下的 书/书名 都得到

List list = root.selectNodes("//书/书名"); ?//得到所有目录下的 ?书/书名 标签

2操作属性

1获取属性值 ??根据属性名 ?获取属性值

Attribute attribute = element.attribute("出版社"); ?//获取属性名

String value = attribute.getValue();//获取属性值

Object data = attribute.getData();

3操作文本

1获取文本 element2.getText()

String text = root.element("报纸").element("新闻").getText(); ?//从多级标签中 ?得到文本

String elementText = element.elementText("书名"); ?从标签 直接得到文本

3 反射

作用

- 在运行时判断任意一个对象所属的类

- 在运行时构造任意一个类的对象

- 在运行时判断任意一个类所具有的成员变量和方法

- 在运行时调用任意一个对象的方法。通过反射甚至可以调用到private方法。

- 生成动态代理

1 获得字节码的3种

1种方式 * 第一种获取类的字节码对象方式 ?使用object里面的getClass()方法

?* 通过对象名.getClass()获取 不常用 你都不知道对象名是什么 ?怎么建对象 能建对象也就不用用反射了

Person p = new Person();

Class clazz = p.getClass(); //获取到正在运行的类的字节码对象\

2种方式 * 通过类名.class获取

Class clazz = Person.class;

3种方式 通过Class类的静态方法.forName(包名.类名); ?* 应用: 加载数据库驱动的时 ??* 推荐使用:常用

Class clazz = Class.forName("java.lang.String");

2 获取构造方法3

打印出来的构造方法 都是实体的全限定名称 修饰符+ 全类名+参数列表(全称)1 public reflect.Student(java.lang.String,int)?2 public reflect.Student()

1获取所有构造方法??这都是你利用Class里面的方法

//第一步:获取到类的字节码对象

Class clazz = Class.forName("com.heima.domain.Person");

//第二步:调用getConstructors获取类字节码对象的所有构造方法

Constructor[] cons = clazz.getConstructors();

//第三步:遍历构造方法数组

for(Constructor con : cons) {

//System.out.println(con);

System.out.println("构造方法名:" + con.getName());

2 获取单个构造方法 ?这都是你利用Class里面的方法 ?有参数

//第一步:获取类的字节码对象

Class clazz = Class.forName("com.heima.domain.Person");

//第二步:获取有参数构造方法

Constructor?con = clazz.getConstructor(String.class,int.class,char.class);

//第三步:创建对象

Object obj = con.newInstance("超哥",18,'男');

//第四步:向下转型

Person p = (Person)obj;

System.out.println(p.getName());

3 获取无参数的构造方法 ?无参数

//第一步:获取类的字节码对象

Class clazz = Class.forName("com.heima.domain.Person");

//第二步:获取构造方法

Constructor?con = clazz.getConstructor(); //不传参数代表获取该类的无参数构造方法

//第三步:使用构造方法对象创建一个对象

Object obj = con.newInstance();

//第四步:向下转型

Person p = (Person)obj;

p.eat(); p.sleep();

4- public Constructor[] getDeclaredConstructors() - 返回此 Class 对象表示的类声明的所有构造方法,包括私有构造方法。

5- public Constructor getDeclaredConstructor(Class... parameterTypes) ?- 返回此 Class 对象所表示的类的指定构造方法。

?

3 获取对象 操作对象3

1 使用构造方法对象创建一个有参对象 无惨对象 Student student = constructor.newInstance("张三",28);

2通过字节码文件对象创建独享 ??这个只能用字节码对象创建无惨的 对象 ?对于有参的对象都必须用 构造函数去创建

Student student = clazz.newInstance();

4 获取成员变量 操作成员变量3

打印所有的 成员变量 ?打印出来都是全包名 修饰符+全类型+全包名 public java.lang.String com.itheima.reflect.Student.name

对于设置成员变量值 ?可以先判断成员变量是什么类型 再设置什么类型的值 ?判断

1得到所有公共成员变量Field[] field=clazz.getFields() ?- public Field[] getFields() - 返回此Class 对象所表示的实体的所有 成员变量包括继承的。 1得到所有包括私有- public Field[] getDeclaredFields() - 返回此 Class 对象所表示的实体的所有属性,包括私有属性,但不包括继承父类的属性。

2得到成员变量的名- public String getName() ?- 返回此 Class 对象所表示的实体的全限定名称。

l?对于构造方法对象.getName() 得到全类名 reflect.Student ?2对于成员变量 只有名字

3得到成员变量值 Field[] fields = clazz.getFields(); ??Object object = field.get(student);

4设置变量值 ?field.set(student,"李四");

- public String getSimpleName() ?- 返回此 Class 对象所表示的实体的全限定名称。

5获取方法 操作方法4

1得到所有的公有方法- public Method[] getMethods() - 返回此 Class 对象所表示的实体的所有公共属性,包括父类的。

1得到所有的方法包括私有- public Method[] getDeclaredMethods() - 返回此 Class 对象表示的实体的所有方法,包括私有方法,但不包括继承父类的方法。

1获取指定公有方法- public Method getMethod(String name, Class... parameterTypes) - 返回此 Class 对象所表示的实体的指定公共成员方法,- name 指定方法名称,parameterTypes指定方法参数类型 字节码文件类型 例如 ?Method method = clazz.getMethod("sayHello", String.class,int.class);

1获取指定私有方法 方法名为study ???Method method2 = clazz.getDeclaredMethod("study");

?

2调用方法 method2.invoke(clazz.newInstance()); 对于调用的是静态的方法 括号里面可以写(null) 静态方法调用不用对象

?

3去除方法的私有权限调用方法method2.setAccessible(true);然后调用方法 method2.invoke(clazz.newInstance());

?

4得到方法名method.getName ??????if (method.getName().equals("show"))

- public Class[] getInterfaces() - 确定此 Class 对象所表示的类实现的接口。

后面几个几乎用不到

- public ClassgetSuperclass() - 返回此 Class 对象所表示的实体的超类的 Class。

- public Package getPackage() ?- 获取此类的包。 【String [Package].getName()】

- public int getModifiers() ?- 返回此类或接口以整数编码的 Java 语言修饰符。

?【String Modifier.toString(int)】

- public boolean isArray() ?- 判定此 Class 对象是否表示一个数组类。

- public ClassgetComponentType() ?- 返回表示数组组件类型的 Class。

成员变量(Field)获取和设置

- get(Object o); - 得到具体对象的该属性的值

- set(Object o, Object value); - 设置具体对象的该属性的值

方法(Method)调用 - invoke(Object o,Object... args) - o是调用该方法的对象,args是调用该方法时传入的参数