数据库学习

数据库

数据库基础

数据库概念
数据库得存储方式

从我们已经学过的知识当中,主要有以下几种方式存储数据:

Java 中创建对象:User u = new User (1, “小明”) 存在内存中;

学习了 Java IO 流:把数据保存到文件中;

本阶段,我们将学习一种新的存储数据的方式:使用数据库存储数据

数据库分类

关系型数据库 ---->MySQL、SqlServer、Oracle

非关系型数据库---->Redis、Mongodb

数据库管理系统

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

数据库管理系统和数据库,表之间的关系

数据库管理程序(DBMS)可以管理多个数据库,一般开发人员会针对每一个应用创建一个数据库。为保存应用中实体的数据,一般会在数据库创建多个表,以保存程序中实体的数据。

即:数据库管理系统管理着多个数据库,一个数据库管理着多张数据表,一张表里面有很多数据


mysql数据库
mysql简介

数据库是按照数据结构来组织、存储和管理数据的仓库,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的的各种数据管理方式。数据库有多种类型,从最简单的存储有各种数据的表格到能够海量数据存储的大型数据库系统,都在各个方面得到了广泛的应用。

MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。

关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。

RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:

  • 数据以表格的形式出现
  • 每行为各种记录名称
  • 每列为记录名称所对应的数据域
  • 许多的行和列组成一张表单
  • 若干的表单组成database
基本术语
  • 数据库: 数据库是一些关联表的集合。
  • 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
  • 列: 一列(数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
  • **行:**一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
  • 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
  • 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
  • **外键:**外键用于关联两个表。
  • 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
  • **索引:**使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
  • 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
数据表的组成
  • 表头(header): 每一列的名称;
  • 列(col): 具有相同数据类型的数据的集合;
  • 行(row): 每一行用来描述某条记录的具体信息;
  • 值(value): 行的具体信息, 每个值必须与该列的数据类型相同;
  • 键(key): 键的值在当前列中具有唯一性。
数据库管理系统,数据库和表的关系

数据库管理程序(DBMS)可以管理多个数据库,一般开发人员会针对每一个应用创建一个数据库。为保存应用中实体的数据,一般会在数据库创建多个表,以保存程序中实体的数据。

数据类型
数值

MySQL 支持所有标准 SQL 数值数据类型。

类型大小范围(有符号)范围(无符号)用途
TINYINT1 Bytes(-128,127)即(-2^7 , 2^7-1)(0,255)小整数值
SMALLINT2 Bytes(-32 768,32 767)(0,65 535)大整数值
MEDIUMINT3 Bytes(-8 388 608,8 388 607)(0,16 777 215)大整数值
INT或INTEGER4 Bytes(-2 147 483 648,2 147 483 647)(0,4 294 967 295)大整数值
BIGINT8 Bytes(-9,223,372,036,854,775,808,9 223 372 036 854 775 807)(0,18 446 744 073 709 551 615)极大整数值
FLOAT4 Bytes(-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38)0,(1.175 494 351 E-38,3.402 823 466 E+38)单精度 浮点数值
DOUBLE8 Bytes(-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)双精度 浮点数值
DECIMAL对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2依赖于M和D的值依赖于M和D的值小数值
日期时间类型
类型大小 ( bytes)范围格式用途
DATE31000-01-01/9999-12-31****YYYY-MM-DD日期值
TIME3‘-838:59:59’/‘838:59:59’HH:MM:SS时间值或持续时间
YEAR11901/2155YYYY年份值
DATETIME8‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’YYYY-MM-DD hh:mm:ss混合日期和时间值
TIMESTAMP4‘1970-01-01 00:00:01’ UTC 到 ‘2038-01-19 03:14:07’ UTC结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07YYYY-MM-DD hh:mm:ss混合日期和时间值,时间戳
字符串类型
类型大小用途
CHAR0-255 bytes定长字符串
VARCHAR0-65535 bytes变长字符串
TINYBLOB0-255 bytes不超过 255 个字符的二进制字符串
TINYTEXT0-255 bytes短文本字符串
BLOB0-65 535 bytes二进制形式的长文本数据
TEXT0-65 535 bytes长文本数据
MEDIUMBLOB0-16 777 215 bytes二进制形式的中等长度文本数据
MEDIUMTEXT0-16 777 215 bytes中等长度文本数据
LONGBLOB0-4 294 967 295 bytes二进制形式的极大文本数据
LONGTEXT0-4 294 967 295 bytes极大文本数据

说白了,比较常用了数据类型就只有INT或INTEGER,FLOAT,DOUBLE,DATE,DATETIME,VARCHAR这几个数据类型


数据库表的约束

对表中的数据进行限制,保证数据的正确性、有效性和完整性。一个表如果添加了约束,不正确的数据将无法插入到表中。约束在创建表的时候添加比较合适。

约束种类
约束名约束关键字
主键primary key
唯一unique
非空not null
外键foreign key
主键约束

主键约束用来唯一标识数据库中的每一条数据

例:表中的id字段,就相当于每个人的身份证一样,每个人的都不一样(不可重复),并且每个人都有(非空),当然这只是一种理解方式,如果真的遇到学号或则身份证号码之类的情况,还是不建议使用身份证号码作为主键的,主键通常是跟业务无关的,主要是给数据库使用

创建:使用关键字primary key

格式:字段名 字段类型 PRIMARY KEY

特点:非空,不能重复(所以通常把主键设置为自增)

创建主键:

CREATE TABLE IF NOT EXISTS user1 (
		-- 设置三个字段
		userid INT ( 10 ) AUTO_INCREMENT,-- userid设置自动递增(AUTO_INCREMENT)
		PRIMARY KEY ( userid ) -- 设置主键,主键(非空,不能重复)
	)

添加主键

alter table stu01 add primary key(id);

删除主键

alter table stu01 drop primary key;

注意,我们已经知道主键通常是自增的了,所以我们应该如何设置主键从哪儿自增呢

创建表的时候直接在后面设置AUTO_INCREMENT=起始值就可以了.

CREATE TABLE IF NOT EXISTS per ( ppid INT ( 10 ) PRIMARY KEY AUTO_INCREMENT )AUTO_INCREMENT=2

修改起始值:

alter table stu01 auto_increment = 2000; 
唯一约束

唯一约束:表中某一列不能出现重复的值

格式:字段名 字段类型 UNIQUE

主要用于:身份证号码,学生编号

CREATE TABLE
IF
	NOT EXISTS per ( 
	ppid INT ( 10 ) PRIMARY KEY AUTO_INCREMENT ,
	-- 创建一个字段,字段添加唯一约束
	name VARCHAR(22) UNIQUE
	) 

验证:连续两次添加相同的同一字段就行,第二次出现错误即表示唯一约束撤成功

设置唯一约束

ALTER TABLE 表名称 ADD UNIQUE KEY(字段列表);

ALTER TABLE 表名称 MODIFY 字段名 字段类型 UNIQUE;

如果插入值为null,不会出现这个问题

非空约束

非空约束:某一列不能为 null

格式:字段名 字段类型 NOT NULL

CREATE TABLE
IF
	NOT EXISTS per ( 
	ppid INT ( 10 ) PRIMARY KEY AUTO_INCREMENT ,
	-- 添加字段,设置非空约束
	sex VARCHAR(10) NOT NULL
	) 
	
	
-- 设置非空约束
ALTER TABLE 表名称 MODIFY 字段名 数据类型 NOT NULL;
-- 验证:
INSERT INTO per VALUES (null,null)

-- 报错:sex字段不能为空
-- > 1048 - Column 'sex' cannot be null
-- > 时间: 0.003s

如果你的字段添加了非空约束但是在添加数据的时候出现了错误怎么办,这个时候就可以设置默认值了

DEFAULT 默认值

CREATE TABLE
IF
	NOT EXISTS per ( 
	ppid INT ( 10 ) PRIMARY KEY AUTO_INCREMENT ,
    -- 设置默认值为其他
	sex VARCHAR(10) NOT NULL DEFAULT "其他"
	) 

验证:

INSERT INTO per VALUES (null,DEFAULT)

注意:如果一个字段设置了非空与唯一约束,该字段与主键的区别?

①主键在一个表中,只能有一个。不能出现多个主键。主键可以单列,也可以是多列;

②自增长只能用在主键上。

外键约束
外键创建

首先创建一个员工表:

员工表

这样子得到的数据会发现部门的重复很多,也就是 造成了数据冗余下现象.这个时候就可以试试用外键进行关联查询此时,我们需要创建两个表,

在这里插入图片描述
在这里插入图片描述

这个时候,我们插入user表的信息,如果此时插入的roleid在下面的权限表中并不存在,能插入么?答案肯定是可以的,但是我们所期望的结果是当我们插入的roleid只能插入在权限表当中存在的,该怎么办呢?那么这个时候,也就会使用到我们的外键了.

外键:在从表中与主表主键对应的那一列,如:用户表中的 roleid。

主表:用来约束别人的表,一方

从表(副表):被别人约束的表,多方

格式:

新建表时增加外键:[CONSTRAINT] [外键约束名称] FOREIGN KEY(外键字段名) REFERENCES 主表名(主键字段名);

创建主键的时候,必须注意主表的主键和从表的外键,也就是这关联的两个字段的字段的类型,约束等一致

CREATE TABLE if NOT EXISTS user_c(
id int(11) PRIMARY KEY auto_increment,
username VARCHAR(22),
password VARCHAR(255),
roleid int(11) NOT NULL,-- 外键对应着主表的主键
constraint roleid_fk foreign key (roleid) references rolelist(roleid)
)

此时如果在从表中添加关联字段并且主表中没有的数据就会报错.

当然,在navcat中也可以设置

在这里插入图片描述

对已有表增加外键

ALTER TABLE 从表名称 ADD CONSTRAINT 外键名称 FOREIGN KEY (从表外键字段) REFERENCES 主表名称(主表主键);

删除存在的外键

alter table 表名称 drop foreign key 外键名称;
外键的次联

在修改和删除主表的主键时,同时更新或删除副表的外键值,称为级联操作

语法描述
ON UPDATE CASCADE级联更新,只能是创建表的时候创建级联关系。更新主表中的主键,从表中的外键列也自动同步更新
ON DELETE CASCADE级联删除

创建表

create table `emp01`(
id int primary key auto_increment,
name varchar(20),
age int,
dept_id int, -- 外键对应主表的主键
constraint emp_deptid_fk foreign key (dept_id) references
department(id) on update cascade on delete cascade -- 创建外键约束
);		
外键删除,修改

CASCADE:父表delete、update的时候,子表会delete、update掉关联记录;

SET NULL:父表delete、update的时候,子表会将关联记录的外键字段所在列设为null,所以注意在设计子表时外键不能设为not null;

RESTRICT:如果想要删除父表的记录时,而在子表中有关联该父表的记录,则不允许删除父表中的记录;

NO ACTION:同 RESTRICT,也是首先先检查外键;

当创建外键约束之后,如果两个字段相互RESTRICT关联,这个时候想删除子表中被约束的数据,(例如:用户表中某用户的角色id为4,这个时候想删除这个角色表中的id为4的角色,直接删除就会出错,必须先删除用户表中被约束的数据,再去删除角色表中的数据)


数据库查询语句

数据库函数
标量函数

对表的计算,求出来是一个单一的

  1. UCASE() - 将某个字段转换为大写

    SELECT UCASE(username) FROM `user`
    
  2. LCASE() - 将某个字段转换为小写

  3. MID(字段,开始,长度) - 从某个文本字段提取字符

  4. LENGTH() - 返回某个文本字段的长度

    SELECT LENGTH(username) FROM `user`
    
  5. ROUND() - 对某个数值字段进行指定小数位数的四舍五入

    SELECT ROUND(openingprice) FROM gpinfoc
    
  6. NOW() - 返回当前的系统日期和时间

  7. FORMAT() - 格式化某个字段的显示方式timestampdiff()-时间差,例如:求年龄

    SELECT userid,username,DATE_FORMAT(NOW(),'%Y') - DATE_FORMAT(brithday,'%Y') 年龄 FROM user1;
    

在这里插入图片描述

8.timestampdiff()函数:格式化某个字段的显示方式

聚合函数

聚合函数是将“若干行数据”经过计算后聚合成“一行数据”,(不包含null数据)即空数据不包含在计算范围之内,所有需要注意使用ifnull()

  1. count(col): 表示求指定列的总行数,
  2. max(col): 表示求指定列的最大值
  3. min(col): 表示求指定列的最小值
  4. sum(col): 表示求指定列的和
  5. avg(col): 表示求指定列的平均值
-- 当score列含有三行空数据的时候,这三行就不参与计算
SELECT COUNT(score) FROM cjb

-- 加了ifnull()之后,就将null替换为ifnull的第二个参数
SELECT COUNT(IFNULL(score,0)) FROM cjb

sql语句基本查询

SQL(Structured Query Language):结构化查询语言。

作用
  1. 是一种所有关系型数据库的查询规范,不同的数据库都支持;

  2. 通用的数据库操作语言,可以用在不同的数据库中;

  3. 不同的数据库SQL语句有一些区别。

mysql数据类型

整型(xxxint):int
位类型(bit):了解
浮点型(float和double、real)
定点数(decimal,numeric)
日期时间类型:date(日期,xxxx-xx-xx),time(时间),datetime(日期时间,年月日,时分秒),year(年份),timestamp(时间戳)
字符串(char**,varchar**,xxxtext)
二进制数据(xxxBlob、xxbinary)
枚举(enum)
集合(set)

sql语句分类
  1. 数据库定义语言DDL:即建表,建库,不过一般情况下不会使用这个操作,因为有图形化界面,语句也可以自动生成,我们可以直接查看生成语句。
  2. 数据查询语言DQL(Data Query Language):对表中的查询操作
  3. 数据操纵语言DML(Data Manipulation Language):对表中的记录操作增删改
  4. 数据控制功能DCL(Data Control Language):用户权限的设置
mysql语法
  1. 每一条SQL语句都是以分号(英文状态)结束,但是在Navicat中是可以不加分号的;

  2. SQL中是不区分大小写,关键字中认为大小写一样;

  3. 注释:

     -- 注释内容
    

进入mysql操作语句:

mysql -uroot -p密码
数据库创建语句–DDL
创建数据库
  1. 数据定义语言DDL(Data Definition Language):建表,建库
-- 创建数据库 sqlstudy为数据库名称
CREATE DATABASE sqlstudy;

-- 删除数据库
drop DATABASE sqlstudy;
 
-- 展示数据库
show databases;

-- 使用数据库
use sqlstudy;
创建mysql表

创建数据库表需要三个信息:

  • 表名
  • 表字段名
  • 定义每个表字段

语法:

创建一张表:

-- 如果有这个表,就删掉这个表,重新建表
DROP TABLE IF EXISTS user1;
	
-- 创建表,如果没有创建表的话就创建
CREATE TABLE IF NOT EXISTS user1 (
		-- 设置三个字段
		userid INT ( 10 ) AUTO_INCREMENT,-- userid设置自动递增(AUTO_INCREMENT)
		username VARCHAR ( 22 ),
		brithday date COMMENT '生日',-- COMMENT 表示注释
		sex VARCHAR ( 22 ),
		create_time datetime,
		PRIMARY KEY ( userid ) -- 设置主键,主键(非空,不能重复)
	)
  • IF NOT EXISTS是判断此表是否创建
  • 如果你不想字段为 NULL 可以设置字段的属性为 NOT NULL, 在操作数据库时如果输入该字段的数据为NULL ,就会报错。
  • AUTO_INCREMENT定义列为自增的属性,一般用于主键,数值会自动加1。
  • PRIMARY KEY关键字用于定义列为主键。 您可以使用多列来定义主键,列间以逗号分隔。
  • ENGINE 设置存储引擎,CHARSET 设置编码
  • UNSIGNED:'无符号,即非负数 ,一般id都用于自动递增,所以一般都有这个
修改数据库表*

如果想改动字段或者删除字段,添加字段,使用的是ALTER语句

-- ALTER 命令及 DROP 子句来删除以上创建表的 i 字段:
ALTER TABLE testalter_tbl  DROP i;

-- 使用 ADD 子句来向数据表中添加列,如下实例在表 testalter_tbl 中添加 i 字段,并定义数据类型:
ALTER TABLE testalter_tbl ADD i INT;

-- 如果需要修改字段类型及名称, 你可以在ALTER命令中使用 MODIFY 或 CHANGE 子句
ALTER TABLE testalter_tbl MODIFY c CHAR(10)
ALTER TABLE testalter_tbl CHANGE i j BIGINT;
删除数据库,表

MySQL中删除数据表是非常容易操作的,但是你在进行删除表操作时要非常小心,因为执行删除命令后所有数据都会消失。

-- 删除数据库
DROP DATABASE 数据库名;

-- 删除表
DROP TABLE table_name ;
# 判断是否有再删除
DROP DATABASE IF EXISTS 数据库名;

# demo
DROP DATABASE IF EXISITS demo;

在这里我们会发现:删除表格和数据库都使用DROP关键字进行删除

另外还有其他的DDL语句:修改数据库表格ALTER TABLE,创建查询命令CREATE VIEW、修改查询命令ALTER VIEW、删除查询命令DROP VIEW、删除数据表内容TRUNCATE TABLE

数据改动–DML语句
插入数据(insert 增)

添加数据使用的主要关键字是insert into 这类的关键字,主要有两种方式

-- insert into 表名 (字段名1,字段名2,...字段名n) values(字段1对应数据,字段2数据,...字段n数据)

-- 例子:now() 获取当前时间
INSERT INTO `user` (`user`.username,`user`.`password`,`user`.creat_date) VALUES ("cc","1234",NOW())
-- 此方式必须将所有字段都列举出来
inert into 表名 values(字段1,....字段n)

-- 例子:CURRENT_DATE通now()
INSERT INTO `user` VALUES(NULL,"cl","23423",CURRENT_DATE)

如果数据是字符型,必须使用单引号或者双引号,如:“value”。

改动数据(update 改)

语法:update 表名称 set 列名称 = 新值 where 更新条件;

-- 表中所有信息得username修改成cxk,但是这样有个弊端,就是回改变大多数得数据,所以多数情况下都是在后面加个where条件语句
UPDATE `user` SET username='cxk'

-- 加上where条件之后
UPDATE `user` SET username='cxkas' WHERE userId=3

更新多个字段

-- 即在修改字段后面使用逗号隔开,写多个字段
UPDATE `user` SET username='cxkas',`password`="jntm" WHERE userId=3
删除数据(delete 删)

你可以使用 SQL 的 DELETE FROM 命令来删除 MySQL 数据表中的记录。

语法:delete from 表名称 where 删除条件

-- 删除userId为1得数据信息
DELETE FROM `user` WHERE userId = 1

-- TRUNCATE也可以删除数据,并且是全部删除,
TRUNCATE runoob_tbl  

delete,drop,truncate 都有删除表的作用,区别在于:

1、delete 和 truncate 仅仅删除表数据,drop 连表数据和表结构一起删除

2、delete 是 DML 语句,操作完以后如果不想提交事务还可以回滚,truncate 和 drop 是 DDL 语句

3、执行的速度上,drop>truncate>delete

4、如果使用truncate进行删除记录,相当于删除表的结构,再创建一张表

逻辑删除和物理删除

逻辑删除:

逻辑删除的本质是修改操作,所谓的逻辑删除其实并不是真正的删除,而是在表中将对应的是否删除标识(is_delete)或者说是状态字段(status)做修改操作。(类似死亡证明,如果一个人失踪了,多年以后给他开设死亡证明了,但是现实情况是这个人并没有死.),

物理删除:

物理删除就是真正的从数据库中做删除操作了,即为将数据库中该信息进行彻底删除,无法恢复

数据查询–DQL
查询数据(select 查)

MySQL 数据库使用SQL SELECT语句来查询数据

语法:SELECT 查询列表 FROM 表名称 where 条件 

①查询列表可以是:表中的字段、常量值(相当于增加一列常量值)、表达式、函数(求和)

查询常量、表达式、函数时语句后面不用跟from 表名,因为它并不是表示来自哪个表

②查询的结果是一个虚拟的表格

-- 这是一个最简单的查询语句,功能为查询名为user的表的所有信息
SELECT * FROM `user`

-- 当然,不仅可以查询表的所有信息,还可以单独查询多个字段或者一个字段.需要将*换成相应的字段名就行,多个字段名用逗号隔开
SELECT `code`,shortname ,openingprice ,latestprice FROM gpinfoc 
-- 上面例子就是只查询表中四个字段.这样显示的字段就只有四个,极大地提高了我们得效率
  • 查询语句中你可以使用一个或者多个表,表之间使用逗号(,)分割,并使用WHERE语句来设定查询条件。

  • SELECT 命令可以读取一条或者多条记录。

  • 你可以使用星号(*)来代替其他字段,SELECT语句会返回表的所有字段数据

  • 你可以使用 WHERE 语句来包含任何条件。

  • 你可以使用 LIMIT 属性来设定返回的记录数。

  • 你可以通过OFFSET指定SELECT语句开始查询的数据偏移量。默认情况下偏移量为0。

    -- 需要九条数据,便宜两条
    SELECT * FROM book WHERE score>9 LIMIT 9 OFFSET 2
    
    SELECT * FROM book WHERE score>9 LIMIT 2,9
    

别名(AS)

当我们查询了某些字段的时候,需要将字段名设置为比较好区别的名字的时候,就可以使用AS给字段设置一个别名

-- 例:将code字段设置别名为 股票编码
SELECT code as "股票编码" FROM gpinfoc 

还可以用空格代替as

SELECT code "股票编码" FROM gpinfoc  	

注意:

①便于理解

②如果要查询的字段有重复的情况,使用别名可以区分

注意:如果取的别名有特殊符号或者是数据库关键字,比如OUT,空格,#号等,需要给别名加上引号。

去重

当涉及到有些查询的时候,需要获得的是某一类得数据,

-- 查询book列表中得评分,但是我只想知道有哪些评分,查出来的话,会有一些评分重复.所以添加DISTINCT(),进行去重
SELECT DISTINCT(score) FROM book

联合

unionunion all 的区别是,union 会自动压缩多个结果集合中的重复结果,而 union all 则将所有的结果全部显示出来,不管是不是重复。

-- 以下结果是将查询得分数和书籍名称联合起来,可以分别使用UNION 和UNION ALL看一下结果如何,union 进行表链接后会筛选掉重复的记录
SELECT score FROM book
UNION ALL
SELECT bookname FROM book

+号的作用

作用:仅仅只有做加法运算功能。

例:

SELECT 122+20; -- 数值加法运算
SELECT "222"+20;  -- 其中一个是字符型,会试图将字符型数值转换成数值型,成功就做加法运算
SELECT "john"+20; -- 转化不了数值就直接转化为0
SELECT NULL+20;  -- 只有有一个字符为null,结果就是null

加入想将两个字段加在一起输出,使用concat方法

SELECT CONCAT(username,sex) FROM user1
where语句

我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据。如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中。

比如当我们想选择suername属性为"cc"的数据,那么我们就应该这样写语句:

SELECT * FROM `user` WHERE username='cc'

当你的查询条件不止一个的时候,就可以使用or 或 and 关键字进行条件的设置

-- 查询图书评分在9.x的并且没有翻译者的图书
SELECT * FROM	book WHERE score LIKE "9.%" AND translater ="无翻译"
-- 查询成绩大于90或者班级号为3的数据
SELECT * FROM cjb WHERE score >90 OR clazz=3

between and:等价于大于等于第一个值,小于等于第二个值

-- 查询分数在90到95之间的数据
SELECT * FROM cjb WHERE score BETWEEN 90 AND 95

in判断某个字段的值是否属于in列表中的某一项

-- 查询分数在列表中的数据
SELECT * FROM cjb WHERE score in (90,89,99)

SELECT * FROM cjb WHERE (score,clazz) in ((90,2),(89,3),(99,1))

is null:

SELECT age,name FROM stu WHERE money IS NULL;
  • 查询语句中你可以使用一个或者多个表,表之间使用逗号**,** 分割,并使用WHERE语句来设定查询条件。
-- 这是查询两个表的内容  但是查询出来的结果是两个表的笛卡尔积(即两个表得信息交叉所得的集合)
SELECT * FROM `user`,`user_copy1`
  • 你可以在 WHERE 子句中指定任何条件。
这里查询的是user表中username为cc得数据
SELECT * FROM `user` WHERE username="cc"
  • 你可以使用 AND 或者 OR 指定一个或多个条件。
or关键字:满足两个条件中的一个即可
SELECT * FROM `user` WHERE username="cc" or username="cl"

and关键字:必须满足两个关键字
SELECT * FROM `user` WHERE username="cc" AND userId=3
  • WHERE 子句也可以运用于 SQL 的 DELETE 或者 UPDATE 命令。
  • WHERE 子句类似于程序语言中的 if 条件,根据 MySQL 表中的字段值来读取指定的数据。
操作符描述实例
=等号,检测两个值是否相等,如果相等返回true(A = B) 返回false。
<>, !=不等于,检测两个值是否相等,如果不相等返回true(A != B) 返回 true。
>大于号,检测左边的值是否大于右边的值, 如果左边的值大于右边的值返回true(A > B) 返回false。
<小于号,检测左边的值是否小于右边的值, 如果左边的值小于右边的值返回true(A < B) 返回 true。
>=大于等于号,检测左边的值是否大于或等于右边的值, 如果左边的值大于或等于右边的值返回true(A >= B) 返回false。
<=小于等于号,检测左边的值是否小于或等于右边的值, 如果左边的值小于或等于右边的值返回true(A <= B) 返回 true。
like语句

当某些情况下,我们需要将查询条件设置成查询包含某个或某些字符得数据时,就需要用到like语句

例如:当我们需要查询图书表里面press(出版设)字段的数据中包含"出版社三个字的数据的时候,就可以使用以下sql语句"

SELECT * FROM book WHERE press LIKE "%出版社%"

SQL LIKE 子句中使用百分号 %字符来表示任意字符,如果没有使用百分号 %, LIKE 子句与等号 = 的效果是一样的

like 匹配/模糊匹配,会与 %_ 结合使用 %表示任意字符串占位,_表示单字符占位

'%a'     //以a结尾的数据
'a%'     //以a开头的数据
'%a%'    //含有a的数据
'_a_'    //三位且中间字母是a的
'_a'     //两位且结尾字母是a的
'a_'     //两位且开头字母是a的
-- 查询评分在是8.*得数据
SELECT * FROM book WHERE score LIKE "8._"
-- 查询名字中
SELECT * FROM user1 WHERE username LIKE "_原里%"

在 where like 的条件查询中,SQL 提供了四种匹配方式,后两种做了解

  1. %:表示任意 0 个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。
  2. _:表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字符长度语句。
  3. []:表示括号内所列字符中的一个(类似正则表达式)。指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个。(*)
  4. [^] :表示不在括号所列之内的单个字符。其取值和 [] 相同,但它要求所匹配对象为指定字符以外的任一个字符。(*)
  5. 查询内容包含通配符时,由于通配符的缘故,导致我们查询特殊字符 “%”、“_”、“[” 的语句无法正常实现,而把特殊字符用 “[ ]” 括起便可正常查询。
排序

如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。排序分为倒序(DESC)和升序(ASC),没设置的话就默认为升序,order by一般放到sql语句最后,

LMITI关键字:作为最后需要的数据行数的选择,语法:LIMIT 开始索引,数据行数

-- 查询股票信息表中得数据 根据openingprice字段进行排序,排序规则是DESC(倒序),不设置排序规则默认为ASC(升序)
SELECT * FROM gpinfoc ORDER BY openingprice DESC limit 0,5

-- 当然排序规则也可以不仅一个条件,也可以多个,先按照前一个条件条件进行排序,在按照第二条件排序
SELECT * FROM cjb ORDER BY score ASC ,clazz desc 

-- 甚至排序条件还可以设置为函数或者表达式,下面例子是通过成绩总分进行排序
SELECT `name`,SUM(score) FROM cjb GROUP BY name ORDER BY SUM(score) ASC

如果字符集采用的是 gbk(汉字编码字符集),直接在查询语句后边添加 ORDER BY,如果字符集采用的是 utf8(万国码),需要先对字段进行转码然后排序:

SELECT * FROM runoob_tbl ORDER BY CONVERT(name using gbk);

分组查询

注意:在mysql5.7之后的版本,MySQL默认开启了SQL_MODE[严格模式],对数据进行严格校验,所以需要修改一下配置,

修改配置文件my.ini

在[mysqld]模块下新增一行配置:

sql_mode=‘STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION’;

运行后重启,即可生效(net stop mysql)(net start mysql)

在分组的列上我们可以使用 COUNT, SUM, AVG,等函数。

当你要通过某个字段进行分类的时候,比如需要查询一个学生列表中,有几个班级,那么咋们就需要通过将班级作为条件进行分组

-- 查询班级,通过班级进行分组
SELECT clazz FROM student GROUP BY student.clazz 


-- 根据姓名分组查询,获取每个学生得总成绩(SUM函数,求和)
SELECT name,SUM(score) FROM cjb GROUP BY `name`

在分组之后如果要额外添加条件的话,则需要加having关键字

-- SELECT 字段名 FROM 表名 groupby 字段名 having 条件
SELECT `name`,SUM(score) FROM cjb GROUP BY name HAVING `name` LIKE "李_";

-- 求平均分大于80的同学并排序
SELECT name, AVG(score) FROM cjb  GROUP BY `name` HAVING AVG(IFNULL(score,0))>80 ORDER BY AVG(IFNULL(score,0)) desc

having和where的区别:

  • 对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,即先过滤再分组;
  • where后面不可以使用聚合函数,having后面可以使用聚合函数。
  • having子句的作用是筛选满足条件的组,即在分组之后过滤数据,即先分组再过滤;
  • where在分组之前就会进行筛选,过滤掉的数据不会进入分组。

执行顺序

		1.select 
		2.from
		3.where
		4.group by
		5.having
		6.order by
		7. limit
select 查询字段... form 表名 where 条件 group by 分组字段 having 分组条件 order by 排序字段 limit
mysql NULL值处理

mySQL 使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作。为了处理这种情况,MySQL提供了三大运算符:

  • IS NULL: 当列的值是 NULL,此运算符返回 true。
  • IS NOT NULL: 当列的值不为 NULL, 运算符返回 true。
  • <=>: 比较操作符(不同于 = 运算符),当比较的的两个值相等或者都为 NULL 时返回 true。
-- 查询成绩表score字段为null的数据
SELECT * FROM cjb WHERE score is NULL

在 MySQL 中,NULL 值与任何其它值的比较(即使是 NULL)永远返回 NULL,即 NULL = NULL 返回 NULL 。MySQL 中处理 NULL 使用 IS NULL 和 IS NOT NULL 运算符。

mysql连接查询

在之前,我们使用的都是对于一张表得查询,相对来说比较简单,但是在实际的开发项目的时候,我们经常需要从多个数据表中读取数据,这个时候就需要用到数据库表得连接了.是为了能 够同时查询多张表得信息.

  • INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。
  • **LEFT JOIN(左连接):**获取左表所有记录,即使右表没有对应匹配的记录。
  • RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
内连接

内连接:直接连接两张表,将两张表的数据生成笛卡尔积的数据

-- 连接用户和角色表
SELECT * FROM `user` INNER JOIN rolelist

-- 查询user表和permission表连接之后,roleid相等得数据, 内连接
SELECT * FROM `user` INNER JOIN permissi on WHERE `user`.roleid=permission.roleid

在这里插入图片描述

左连接

MySQL LEFT JOIN 会读取左边数据表的全部数据,即使右边表无对应数据。

-- 将user表和roleList表进行左连接,即使没有相互匹配的数据也会将左表显示
SELECT * FROM `user` LEFT JOIN rolelist ON rolelist.roleid=`user`.roleid
-- 当user表中没有roleid=4的数据的话,user表也会显示
SELECT * FROM `user` LEFT JOIN rolelist ON user.roleid=4

在这里插入图片描述

右连接

MySQL RIGHT JOIN 会读取右边数据表的全部数据,即使左边边表无对应数据。

-- 将user表和roleList表进行左连接,即使没有相互匹配的数据也会将右表显示
SELECT * FROM `user` RIGHT JOIN rolelist ON user.roleid=4

在这里插入图片描述

子查询

子查询指一个查询语句嵌套在另一个查询语句内部的查询

SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较。

子查询(内查询)在主查询之前一次执行完成。
子查询的结果被主查询(外查询)使用。

子查询要包含在括号内
将子查询放在比较条件的右侧
单行操作符对应单行子查询,多行操作符对应多行子查询

-- 查询其他班级中数学成绩比2班李伟的数学成绩高的学生姓名和分数(用子查询)
SELECT name,score FROM cjb WHERE `subject`="数学"  AND score >(select score FROM cjb where `name`="李伟" AND clazz=2 AND `subject`="数学" )

数据库相关概念

mysql事务
事务概述

**在mysql中,事务是一种机制、一个操作序列,是访问和更新数据库的程序执行单元。**事务中包含一个或多个数据库操作命令,会把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行.

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  • 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
  • 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
  • 事务用来管理 insert,update,delete 语句
事务四大特性-AICD
  1. 原子性(Atomicity):事务的原子性是指事务必须是一个原子的操作序列单元事务中包含的各项操作要么都成功,要么都失败.失败的时候其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成.
  2. 一致性(Consistency):事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。比如:如果从A账户转账到B账户,不可能因为A账户扣了钱,而B账户没有加钱
  3. 隔离性(Isolation):事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的
  4. 持久性(Duration):事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态

事务,能保证AID,即原子性,隔离性,持久性。但是一致性无法通过事务来保证,一致性依赖于应用层,开发者。

事务分类

在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。这种事务叫做隐式事务

显示事务:该事务具有明显的开启和结束标记;即不会自动提交

#步骤一:开启事务(可选)
start transaction;
#步骤二:编写事务中的sql语句(insert、update、delete)
#这里实现一下"李二给王五转账"的事务过程
update t_account set balance = 50 where vname = "李二";
update t_account set balance = 130 where vname = "王五";
#步骤三:结束事务
commit; #提交事务
# rollback; #回滚事务:就是事务不执行,回滚到事务执行前的状态
事务并发时出现的问题

因为某一刻不可能总只有一个事务在运行,可能出现A在操作t_account表中的数据,B也同样在操作t_account表,那么就会出现并发问题,对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采用必要的隔离机制,就会发生以下各种并发问题。

脏读

A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。如果恰巧B事务回滚,那么A事务读到的数据根本是不被承认的。

时间转账(事务A)取款(事务B)
1开始
2开始
3查询账户余额1000元
4取出500元,将余额改成500元
5查询余额,500元
6放弃取款,回滚事务
7汇入100元,将余额改成600元
8提交事务提交事务

这样就造成了白白损失了500元,就很离谱.

不可重复读

不可重复读是指 A事务读取了B事务已经提交的更改数据。,例:事务A两次读取数据,第一次余额400元,第二次余额1000元,而两次读取出现不一样的情况是因为在第一次和第二次读取数据之间的空档期,事务更改了数据.导致第二次读取数据出现偏差.

幻读

A事务读取B事务提交的新增数据,这时A事务将出现幻读的问题。例:事务A先读取了表的数据,然后事务B又往表中添加了几行数据,导致A事务再次读取表的时候,会发现表的数据发生了变化.就像发生了幻像一样.

幻读和不可重复读很相似,不可重复读是针对于一条数据,而幻读是针对于多条数据.

第一类丢失更新

A事务撤销时,把已经提交的B事务的更新数据覆盖了。

第二类丢失更新

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失.

事务隔离级别

为了解决多个事务的并发问题,数据库系统提供了四种事务隔离级别供用户选择。

读未提交

允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)

读已提交

只允许事务读取已经被其他事务提交的变更。(因为只能读取已经被提交的事务,所以就能避免因为读取没提交的数据而产生的脏读)

可重复读

确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新(update)。(可以避免脏读和不可重复读,但幻读仍然存在)

串行化(serializable)

确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可避免,但性能十分低下(因为你不完成就都不可以弄,效率太低)

oracle默认的事务隔离级别是:读已提交

mysql的默认事务隔离级别是:可重复读


mysql索引
索引概述

MySQL索引的建立对于MySQL的高效运行是很重要的,**索引可以大大提高MySQL的检索速度。**拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。

索引分单列索引和组合索引。

单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。

组合索引,即一个索引包含多个列。

创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。

上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

建立索引会占用磁盘空间的索引文件。

单列索引
普通索引

MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一 点。

唯一索引

索引列中的值必须是唯一的,但是允许为空值。

主键索引

是一种特殊的唯一索引,不允许有空值。(主键约束,就是一个主键索引)。

组合索引

在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。

全文索引

全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引.

索引数据结构

索引的数据结构使用的是B+树

B+树:只有叶子节点才会存储数据,非叶子节点至存储键值。叶子节点之间使用双向指针连接,最底层的叶子节点形成了一个双向有序链表
如果想学习B+树原理,推荐一个地址:
B+树学习


MYSQL视图

视图是指计算机数据库中的视图,是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。

使用视图的原因

使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。

使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。

一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

使用视图的大部分情况是为了保障数据安全性,提高查询效率。

什么是视图

视图是基于sql语句结果集的可视化的表,视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实的表中的字段。我们可以向视图添加 SQL 函数、WHERE 以及 JOIN 语句,我们也可以提交数据,就像这些来自于某个单一的表。

注意:

数据库的设计和结构不会受到视图中的函数、where 或 join 语句的影响

视图作用
  • 重复利用SQL语句
  • 简化SQL查询,快速取数据
  • 只用知道表的部分结构
  • 保护数据,根据特定授权
  • 更改数据格式和表示,视图可返回与底层表的表示和格式不同的数据

视图只是用来查看存储在别处的数据的设施,本身不包含数据,返回的数据也是从其他表检索出来的。

视图规则和限制
  • 与表一样,命名必须是唯一的(不能出现同名视图或表名)。
  • 创建视图数目无限制,但是要考虑复杂查询创建为视图之后的性能影响。
  • 视图不能添加索引,也不能有关联的触发器或者默认值。
  • 视图可以提高安全性,必须具有足够的访问权限。
  • order by可用在视图中,但是如果从该视图检索数据select中含有order by ,那么该视图中的order by将被覆盖。
  • 视图可以和表一起使用。
视图的应用
  1. 权限控制时使用

    如某几个列,允许用户查询,其他列不允许查询

    可以通过视图,开放其中几列查询,起到权限控制作用

  2. 简化复杂查询时使用

    查询每个栏目下商品的平均价格,并按平均价格排序,查询出平均价格前3的栏目

  3. 视图能不能更新,删除,添加

    如果视图的每一行,是与物理表一一对应的则可以

    视图的行是由物理表多行经过计算得到的结果,视图不可以更新的

创建视图
-- CREATE VIEW <视图名> AS (SELECT语句)

-- 查看视图
select * from 视图名

在这里插入图片描述

视图记录修改
-- update 数据库表名 set 字段名1=字段值1,字段名2=字段值2,...字段名n=字段值n where 条件表达式; #和表的修改一样
update ss set username='cl' where userId=2;

-- 注意:修改了视图的数据记录,对基表数据也有影响

在这里插入图片描述

修改视图
格式:
alter view 视图名称 as select 语句;
或
alter view 视图名称 as select 视图;
或
create or replace view  视图名  as  select 字段名 from 表名;

视图重命名:
rename table 视图名 to 新视图名;

在这里插入图片描述


mysql触发器

触发器(TRIGGER)是由事件来触发某个操作。这些事件包括insert语句、update语句和delete语句。当数据库系统执行这些事件时,就会激活触发器执行相应的操作。

触发器是由insert、update和delete等事件来触发某种特定操作。满足触发器的触发条件时,数据库系统就会执行触发器中定义的程序语句。这样做可以保证某些操作之间的一致性。

创建触发器
CREATE TRIGGER  -- 触发器名称
BEFORE/AFTER  -- (二选一,表示在事件之前执行还是事件之后执行)
UPDATE/INSERT/DELETE -- (三选一,指定在什么事件触发触发器,即增,删,改)
ON 表名称 
FOR EACH ROW  -- (影响所有行) 
#触发器主体
sql语句;
-- 创建触发器   此触发器作用:在对user表执行修改操作的时候执行对gxtime表的添加操作
create trigger t1 before update on user for each row insert into gxtime values(now());

在这里插入图片描述

删除触发器
#删除触发器T1
DROP TRIGGER IF EXISTS T1;
查询触发器
#在已知数据库内,查询触发器
SHOW TRIGGERS;
触发器类型OLD和NEW

在这里插入图片描述

#创建一个update触发器
CREATE TRIGGER T2
AFTER 
UPDATE ON customer
FOR EACH ROW 
#old和new的使用方法:old.columnname/new.columnname(列名)
#将更新前后的值,赋值给两个变量
SELECT OLD.CUST_ID,NEW.CUST_ID INTO @OLD_ID,@NEW_ID;
mysql存储过程

场景:当修改表A之后,会关联到其他表的相关数据,例如转账给某人300块,必须要从一个人的账户里减少300块,接受方才能增加300块,.

存储过程概括

存储过程就是事先经过编译并存储在数据库中的一段 SQL 语句的集合;

调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。

存储过程的操作
-- 创建一个名为p2的存储过程 
-- create procedure 存储过程名称() begin sql语句 end;
create procedure p2() begin DELETE FROM `user` WHERE userId = 4; end;

-- 创建存储过程p21,先删除user表中的roleid=4的数据,在删除rolelist表中的roleid=4的数据
CREATE PROCEDURE p21 () 
 	BEGIN
 	DELETE  FROM `user`  WHERE roleid = 4;
 	DELETE FROM rolelist WHERE roleid=4;
 	END;

-- 调用存储过程
CALL p2();

-- SHOW CREATE PROCEDURE 存储过程名称;     查询某个存储过程的定义
SHOW CREATE PROCEDURE p2;

-- DROP PROCEDURE [ IF EXISTS ] 存储过程名称 ;
DROP PROCEDURE IF EXISTS p1 ;

上面创建存储过程的语句在navicat或者sqlyog中没问题,但是放到命令行中执行会报错,在命令行中模式下,需要通过关键字 delimiter 指定SQL语句的结束符


据库备份与还原

在服务器进行数据传输、数据存储和数据交换,就有可能产生数据故障。比如发生意外停机或存储介质损坏。这时,如果没有采取数据备份和数据恢复手段与措施,就会导致数据的丢失,造成的损失是无法弥补与估量的。所以我们需要将数据进行备份,避免这些情况的发生

备份和还原的语句

备份

DOS下,未登录的时候:cmd

-- 输入以下命令进行保存sql文件: mysqldump -uroot -p密码 数据库名称>保存地址及名称

mysqldump -uroot -proot sqlstudy>D:/Desktop/demo.sql

还原操作

第一步先将数据库的表都删除掉,因为生成的sql文件是不会建数据库的,所以数据库不用删

登录数据库:
mysql -uroot -proot

还原到数据库:
mysql -uroot -proot sqlstudy<D:/Desktop/demo.sql

mysql dos命令导入数据和导出数据
  1. 进入dos命令窗口,进入数据库文件夹bin 文件夹下方

  2. 导出sql文件到目标文件夹

    -- mysqldump -uroot -proot 数据库名称 > 目标文件夹地址\文件名字.sql 
    mysqldump -uroot -proot sqlstudy > D:\Desktop\sqlstudy.sql;
    
  3. 导入数据到数据库,执行命令后输入密码就成功了

    mysql -uroot -p sqlstudy<D:/Desktop/sqlstudy.sql
    

PowerDesigner用法

​ PowerDesigner是Sybase公司的CASE工具集,是图形化、易于使用的企业建模环境。使用它可以方便地对管理信息系统进行分析设计,它几乎包括了数据库模型设计的全过程。利用PowerDesigner可以制作数据流程图、概念数据模型、物理数据模型,可以生成多种客户端开发工具的应用程序,还可为数据仓库制作结构模型,也能对团队设计模型进行控制。它可与许多流行的数据库设计软件,例如:PowerBuilder、Delphi、VB等相配合使用来缩短开发时间和使系统设计更优化

功能

集成了多种建模能力,能建立的建模包括:

  • 数据模型
  • 业务模型
  • 应用模型
范式
什么是范式?

规范的数据库需要满足一些规则来优化数据的设计和存储,这些规则就称为范式。

三大范式
  1. 第一范式(1NF):数据库表的每一列都是不可分割的原子数据项,不能是集合、数组等非原子数据项。即表中的某个列有多个值时,必须拆分为不同的列。简而言之,第一范式每一列不可再拆分,称为原子性。
  2. 第二范式(2NF):在满足第一范式的前提下,表中的每一个字段都完全依赖于主键。谓完全依赖是指不能存在仅依赖主键一部分的列。
  3. 第三范式(3NF):在满足第二范式的前提下,表中的每一列都直接依赖于主键,而不是通过其它的列来间接依赖于主键。

JDBC编程

JDBC概括

JDBC(java database connectivity) 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法。

制作到数据库的连接。
创建 SQL 或 MySQL 语句。
执行 SQL 或 MySQL 查询数据库。
查看和修改所产生的记录。

JDBC架构

DBC 的 API 支持两层和三层处理模式进行数据库访问,但一般的 JDBC 架构由两层处理模式组成:

  • JDBC API: 提供了应用程序对 JDBC 管理器的连接。
  • JDBC Driver API: 提供了 JDBC 管理器对驱动程序连接。
jar包

在使用jdbc之前,我们需要先进行导jar包,的操作,因为jdbc的相关包是已经封装好了的专门用于链接数据库的代码,所以在使用这些代码之前,我们需要先进性导包操作.根据数据库版本不同,我们导入的包也不同.我们需要使用的是mysql-connector-java-5.1.37-bin.jar

所以,在进行编程之前,我们需要先进行导包,进入项目文件夹,建一个名为lib的包,将mysql-connector-java-5.1.37-bin.jar放进去,在项目根文件夹右键点击open Module setting ,将包添加到libraries中.这样idea才能识别到jar包

JDBC核心API
接口/类功能
DriverManager类①管理和注册数据库驱动 ②得到数据库连接对象
Connection接口一个连接对象,可用于创建Statement和PreparedStatement对象
Statement接口一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器
PreparedStatemen接口一个 SQL 语句对象,是 Statement 的子接口
ResultSet接口用于封装数据库查询的结果集,返回给客户端 Java 程序
连接数据库

连接数据库之前需要知道连接数据库的步骤:

  1. 注册数据库驱动:

    // 两种方式:第二种方式比较常用,因为后面使用jdbc连接数据库通常是使用配置文件配置数据库信息,所以会配置成字符串,便于利用反射机制进行驱动注册,在开发中,就更倾向于后者
    DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    Class.forName("com.mysql.jdbc.Driver");
    
  2. 获取数据库连接(地址,端口号,用户名,密码,数据库名称)

    1.url: 统一资源定位符 url格式-百度百科
    2.jdbc:mysql 是协议名称 是指JDBC连接方式
    3.localhost:3306 是主机:端口 还可以写作127.0.0.1:3306
    4.test 数据库名
    5.useSSL: MySQL在高版本需要指明是否进行SSL连接 在mysql连接字符串url中加入ssl=true或者false即可

    6.useUnicode: 是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true
    7.characterEncoding: 当useUnicode设置为true,给定编码,常用utf8,默认是:autodetect
    8.serverTimezone: 设置时区 例如 serverTimezone=UTC(统一标准世界时间)或serverTimezone=Asia/Shanghai(中国时区)

    String url = "jdbc:mysql://127.0.0.1:3306/sqlstudy?useUnicode=true&characterEncoding=UTF-8";
    String user = "root";
    String password = "root";
    
  3. 通过连接获取操作对象(执行sql语句)

  4. 使用相关方法执行sql语句(书写sql语句)

  5. 获取结果

  6. 释放资源.这个步骤是不管报不报异常都会去做的步骤,如果不是释放资源,就会一直存在于内存.

字符串配置连接数据库
package hqyj;
import java.sql.*;

public class conMysql {
    public static void main(String[] args) throws SQLException {
        Connection con = null;
        Statement sta = null;
//        注册驱动
        Driver driver = new com.mysql.jdbc.Driver(); //多态,父类型引用指向自类型对象
//            注册
        DriverManager.registerDriver(driver);
            /*
            获取连接
            获取链接之前应该先拿到数据库配置,端口号,密码,用户名,数据库名称等
             */
        String url = "jdbc:mysql://127.0.0.1:3306/sqlstudy?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "root";
//            获取连接
        con = DriverManager.getConnection(url, user, password);
        System.out.println(con);
        //执行sql语句
        
        //释放资源
        sta.close();
        con.close();
    }
}
用资源绑定器进行资源绑定
  1. 创建一个xxx.properties文件用于装配置信息注意配置文件汇中的字符串别加引号

    Driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/sqlstudy?useUnicode=true&characterEncoding=UTF-8
    user=root
    password=root
    
  2. 访问资源连接数据库

package hqyj;

import java.sql.*;
import java.util.ResourceBundle;

public class fw {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
//        通过静态方法获取jdbc.properties文件的对象
        ResourceBundle rb = ResourceBundle.getBundle("jdbc");
//        注册驱动,注册驱动和连接数据库所需要的配置信息从配置文件中获取
        Class.forName(rb.getString("Driver"));
//        连接数据库
        Connection con = DriverManager.getConnection(rb.getString("url"), rb.getString("user"), rb.getString("password"));
        Statement sta = con.createStatement();
        System.out.println(con);
        
        //        执行sql语句
        
        sta.close();
        con.close();
    }
}
工具类JdbcUtil

为了放置以后每次写都要进行注册驱动,连接数据库,我们可以直接把注册驱动和数据库连接写道一个工具类里面.下次要注册驱动和连接数据库的时候,就能够直接使用了.相当于直接一次性写好.

创建工具类三个步骤

  1. 将几个字符串定义在配置文件当中(地址,端口号,用户名,密码,数据库名称)
  2. 创建工具类,创建方法getCon用于获取连接,返回Connection对象
  3. 创建方法用于释放资源.两个方法,同名,重载.三个参数的方法用于释放查询语句的资源,两个参数的用于释放DML语句的资源
package hqyj.Utils;

import java.sql.*;
import java.util.ResourceBundle;

public class JdbcUtil {
    //    定义为静态方法,这样就可以直接通过类名进行调用
    public static Connection getCon() throws ClassNotFoundException, SQLException {
//        获取配置文件的配置
        ResourceBundle pro = ResourceBundle.getBundle("jdbc");
        //        注册驱动
        Class.forName(pro.getString("Driver"));
//        连接数据库  数据库配置从配置文件jbbc中获取
        Connection con = DriverManager.getConnection(pro.getString("url"), pro.getString("user"), pro.getString("password"));
//        返回数据库连接对象
        return con;
    }

    //    定义为静态方法,这样就可以直接通过类名进行调用
    public static void closeJdbc(ResultSet rs, PreparedStatement pra, Connection con) throws SQLException {
//        释放资源
        if (rs != null) {
            rs.close();
        }
        pra.close();
        con.close();

    }

    //    重载  用于DML语句中,没有ResultSet的情况
    public static void closeJdbc(PreparedStatement pra, Connection con) throws SQLException {
//        释放资源
        pra.close();
        con.close();
    }
}
操作数据库

在做DML语句的时候,因为是修改数据库表,所以最后返回的是一个int类型变量,表示影响的行数.

而做DQL语句的时候,因为是返回的数据库表的查询结果,所以会返回一个resultSet类型的结果.

添加数据
package hqyj;

import java.sql.*;

/*
jdbc连接数据库
*/
public class conMysql {
    public static void main(String[] args) {
        Connection con = null;
        Statement sta = null;
//        注册驱动
        try {
            Driver driver = new com.mysql.jdbc.Driver(); //多态,父类型引用指向自类型对象
//            注册
            DriverManager.registerDriver(driver);
            /*
            获取连接
            获取链接之前应该先拿到数据库配置,端口号,密码,用户名,数据库名称等
             */
            String url = "jdbc:mysql://127.0.0.1:3306/sqlstudy";
            String user = "root";
            String password = "root";
//            获取连接
            con = DriverManager.getConnection(url, user, password);
            System.out.println(con);
//            连接数据库之后,我们就开始操作数据库对象了,所以还要拿到数据库操作对象,通过con.createStatement()可以返回一个Statement对象
            sta = con.createStatement();
//            执行sql语句
            String sql = "insert into user values(null,'chenlong','clclcl',1)";
//            此时使用sta对象的executeUpdate(sql)方法,此方法专门用来执行DML语句的(增删改)
            int count = sta.executeUpdate(sql);
//            返回的是改变数据库信息条数
            System.out.println(count);
            //释放资源在finally中释放
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (sta != null) {
                try {
//                    关闭操作对象
                    sta.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (con != null) {
                try {
//                    关闭连接对象
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
删除修改数据库
package hqyj;

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


public class deleteOne {
    public static void main(String[] args) throws SQLException {
//        定义全局变量 作为连接对象和操作对象
        Connection con = null;
        Statement sta = null;
//        注册驱动
        try {
//            注册驱动:两种方式,第二种方式比较常用
//            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            Class.forName("com.mysql.jdbc.Driver");
//            定义地址,端口号,密码,用户名,数据库名称配置信息
            String url = "jdbc:mysql://localhost:3306/sqlstudy";
            String user = "root";
            String password = "root";
//            通过驱动获取数据库连接
            con = DriverManager.getConnection(url, user, password);
//            通过数据库连接对象获取操作对象
            sta = con.createStatement();
//            执行sql语句
//          删除数据库信息,执行delete语句
            int count = sta.executeUpdate("delete from user where userid=8");
//           修改数据,执行update数据
//          int count = sta.executeUpdate("update user set username='kunkun' where userid=2");
           
            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
//            释放资源
            if (sta != null) {
                sta.close();
            }
            if (con != null) {
                con.close();
            }
        }
    }
}
查询信息

resultSet:包含符合 SQL 语句中条件的所有行,并且它通过一套 get 方法(这些 get 方法可以访问当前行中的不同列)提供了对这些行中数据的访问。

ResultSet.next :方法用于移动到 ResultSet 中的下一行,使下一行成为当前行,ResultSet 维护指向其当前数据行的光标。每调用一次 next 方法,光标向下移动一行。

列:方法 getXXX 提供了获取当前行中某列值的途径。如果getXXX方法中参数是字符串,则返回的是相应字段列的数据,如果参数是int数据,则返回的是第N列的数据.N从1开始,而不是从0开始.方法根据XXX的不同,返回的数据类型也不同,如果 getXXX 方法为 getString,而基本数据库中数据类型为 VARCHAR,则 JDBC 驱动程序将把 VARCHAR 转换成 Java String。getString 的返回值将为 Java String 对象。

package hqyj;

import java.sql.*;

/*
jdbc连接数据库
*/
public class conMysql {
    public static void main(String[] args) throws SQLException {
        Connection con = null;
        Statement sta = null;
//        注册驱动
        Driver driver = new com.mysql.jdbc.Driver(); //多态,父类型引用指向自类型对象
//            注册
        DriverManager.registerDriver(driver);
            /*
            获取连接
            获取链接之前应该先拿到数据库配置,端口号,密码,用户名,数据库名称等
             */
        String url = "jdbc:mysql://127.0.0.1:3306/sqlstudy?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "root";
//            获取连接
        con = DriverManager.getConnection(url, user, password);
        System.out.println(con);
        // 获取操作对象
        sta = con.createStatement();
        String sql = "select * from user where userId=2";
        // 执行sql查询语句:返回resultSet对象
        ResultSet res = sta.executeQuery(sql);
        while (res.next()){
            System.out.println(res.getString("userid"));
            System.out.println(res.getString("username"));
            System.out.println(res.getString("password"));
            System.out.println(res.getString("roleid"));
        }
        //释放资源
        sta.close();
        con.close();
    }
}

ResultSet 接口中的注意事项:

① 如果光标在第一行之前,使用 rs.getXX()获取列值,报错:Before start of result set

② 如果光标在最后一行之后,使用 rs.getXX()获取列值,报错:After end of result set

③ 使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection

练习:实现用户登录

package hqyj;

import java.sql.*;
import java.util.ResourceBundle;
import java.util.Scanner;


public class userLogin {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner sc = new Scanner(System.in);
        String username = sc.nextLine();
        String password = sc.nextLine();
//        获取配置文件的配置
        ResourceBundle pro = ResourceBundle.getBundle("jdbc");
        //        注册驱动
        Class.forName(pro.getString("Driver"));
//        连接数据库  数据库配置从配置文件jbbc中获取
        Connection con = DriverManager.getConnection(pro.getString("url"), pro.getString("user"), pro.getString("password"));
//       获取操作对象
        Statement sta = con.createStatement();
//        sql语句凭借
        String sql = "select * from user where username='" + username+"'";
        System.out.println(sql);
//        获取查询结果
        ResultSet userData = sta.executeQuery(sql);
//        判断:没有数据,则未注册,如果密码正确则登陆成功,反之则密码错误
        if (userData.next()) {
            String u = userData.getString("username");
            String p = userData.getString("password");
            System.out.println(p);
            if (username.equals(u)) {
                if (password.equals(p)) {
                    System.out.println("登陆成功");
                } else {
                    System.out.println("登陆失败,密码错误");
                }
            }
        }else {
            System.out.println("用户未注册");
        }
//        释放资源
        userData.close();
        sta.close();
        con.close();
    }
}
sql注入问题

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

如果在上述的登录例子中,我们将登录的sql语句写成**select * from user where password=‘admin’ and password= ‘123’**的话,这样就可直接通过resultSet.next()进行判断是否登录了.但是这样也会出现一个问题,如果在password后面加一个or password='xxxx’类似语句,也就是说:select * from user where password=‘admin’ and password= ‘123’ or password='xxx’这个样子就会造成,我们随便输入一个密码也能登录了.这个问题,就是我也能够改变SQL语句执行登录操作,这就是Statement引发的SQL注入问题。要想解决这个问题,就用其子类PreparedStatement替换掉Statement即可。

PreparedStatement

Statement 在进行输入插入的时候,都会发送一条SQL语句给数据库,数据库先编译SQL语句,然后执行,返回结果.这就是statement的工作原理.但是如果有一万条数据插入的语句呢,那不就会编译一万次,然后执行么?这样就会造成效率低下.

所以,诞生了PreparedStatement接口.他继承于statement接口的所有方法.PreparedStatement在进行数据插入的时候,会先发送SQL语句预编译,PreparedStatement就会引用预编译的结果,如果多次插入的内容相同的话,就只需要预编译一次,只是每一次执行SQL语句的时候参数不一样。这样就提高了效率。PreparedStatement可以有效的防止 SQL 注入的问题,安全性更高。

预编译使用步骤
  1. 编写 SQL 语句,未知内容使用?占位
  2. 获得 PreparedStatement 对象;预编译操作对象有个参数sql,是作为sql模板使用的.
  3. 设置实际参数:setXxx(占位符的位置, 真实的值);
  4. 执行参数化 SQL 语句;获取结果
  5. 关闭资源。
package hqyj;

import java.sql.*;
import java.util.ResourceBundle;
import java.util.Scanner;

public class PreparedStatementUse {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner sc = new Scanner(System.in);
//        String username = sc.nextLine();
//        String password = sc.nextLine();
        String username = "admin";
        String password = "123";
//        获取配置文件的配置
        ResourceBundle pro = ResourceBundle.getBundle("jdbc");
        //        注册驱动
        Class.forName(pro.getString("Driver"));
//        连接数据库  数据库配置从配置文件jbbc中获取
        Connection con = DriverManager.getConnection(pro.getString("url"), pro.getString("user"), pro.getString("password"));
//       获取预编译操作对象,获取的函数中有一个参数sql,意思是设置一个sql模板,这样才能够进行预先编译,然后执行sql语句
        String sql = "select * from user where username=? and password=?";
        PreparedStatement sta = con.prepareStatement(sql);
//        依次设置?的值  参数1:第几个占位,参数2:替换占位数据
        sta.setString(1, username);
        sta.setString(2, password);
        ResultSet rs = sta.executeQuery();
//        输出结果
        rs.next();//移动光标
        System.out.println(rs.getString("username"));
        System.out.println(rs.getString("password"));
//        释放资源
        rs.close();
        sta.close();
        con.close();
    }
}

PreparedStatement方法

PreparedStatement 中设置参数的方法作用描述
void setDouble(int parameterIndex, double x)将指定参数设置为给定 Java double 值
void setLong(int parameterIndex, long x)将指定参数设置为给定 Java long 值
void setFloat(int parameterIndex, float x)将指定参数设置为给定 Java REAL 值
void setObject(int parameterIndex, Object x)使用给定对象设置指定参数的值
void setInt(int parameterIndex, int x)将指定参数设置为给定 Java int 值
void setString(int parameterIndex, String x)将指定参数设置为给定 Java String 值
表和类的关系

类的属性名称对应着表的字段名称.所以类对象的属性值就对应着表的一行的数据某个字段的值.多个类对象组成就可以表示一张表了

①整个表可以当做是一个java类;

②每一个表中的字段,当做是java类中的成员变量;

③表的一行数据,当做是java类的一个实例对象。

查询数据库数据

例子:现在有一个user类.

package hqyj.entity;

public class user {
//    定义类属性 对应数据库表中的各个字段
    private int userid;
    private String username;
    private String password;
    private int roleid;
    
//    需要的构造方法
    
//    定义相应的get/set方法  为了能在java程序中获取/设置各个属性的值
    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getRoleid() {
        return roleid;
    }

    public void setRoleid(int roleid) {
        this.roleid = roleid;
    }
    
//    toString方法
    @Override
    public String toString() {
        return "user{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", roleid=" + roleid +
                '}';
    }
}

将查询到的结果放进实体类,如果只有一组数据的话,就直接存到一个类对象里面,如果是多组数据,例如slecet * from user,就声明一个ArrayList进行存储就可以了.

package hqyj;

import hqyj.Utils.JdbcUtil;
import hqyj.entity.User;
import java.sql.*;

public class entityPreparedStatement {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
//        使用工具类获取数据库连接
        Connection con = JdbcUtil.getCon();
//        准备sql语句
        String sql = "select * from user where username=? ";
//        将sql模板配置到preparedStatement中
        PreparedStatement pre = con.prepareStatement(sql);
//        设置替换字段
        pre.setString(1, "admin");
//        获取查询结果
        ResultSet data = pre.executeQuery();
//        将结果放进user对象当中
        while (data.next()) {
//            声明一个user对象
            User user = new User();
//            将每个字段放进对象属性
            user.setUserid(data.getInt("userid"));
            user.setRoleid(data.getInt("roleid"));
            user.setUsername(data.getString("username"));
            user.setPassword(data.getString("password"));
//            输出结果
            System.out.println(user);
        }
    }
}
插入信息到数据库
  1. 声明一个user对象
  2. 注册驱动,连接数据库,获取预编译对象
  3. sql语句
  4. 执行sql语句,获取结果
  5. 释放资源
package hqyj;

import hqyj.Utils.JdbcUtil;
import hqyj.entity.User;

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

public class preparedStatementInsert {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
//        使用有参构造声明带数据的实体类
        User user = new User("杨开来", "66666", 3);
//        获取连接
        Connection con = JdbcUtil.getCon();
//        sql
        String sql = "insert into user values(null,?,?,?)";
//        获取预编译数据库操作对象
        PreparedStatement ps = con.prepareStatement(sql);
//        设置替换数据:数据来自类对象
        ps.setString(1, user.getUsername());
        ps.setString(2, user.getPassword());
        ps.setInt(3, user.getRoleid());
//        返回影响行数
        int insertRow = ps.executeUpdate();
//        输出
        System.out.println(insertRow);
//        释放资源
        JdbcUtil.closeJdbc(ps, con);
    }
}

练习:删除/修改

数据库连接池

数据库连接池实际上就是一个容器(集合),存放数据库连接的容器.当系统被初始化后,容器就被创建了.容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象用户访问完之后,会将连接对象归还给容器。简单来时,数据库连接池就是用来创建,分配,管理,释放数据库连接的.它允许应用程序重复使用一个现有的数据库连接,而不是重 新建立一个。

数据库连接池的基本思想就是为数据库连接建立一个缓冲池,预先在这个缓冲池中放入一定数量的数据库连接.当需要数据库链接的时候,就不用去创建,直接从缓冲池中拿一个.用完再放回去就行了

常用连接池

常用的主流开源数据库连接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等。

如果使用数据库连接池,则必须要增加几个配置.数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池 的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连 接数量时,这些请求将被加入到等待队列中。

jdbc.properties

Driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/sqlstudy?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true
username=root
password=root
#初始化创建连接的个数,
initialSize=10
#最大连接数
maxActive=20
#获取连接时最大等待时间
maxWait=1000
Druid数据库连接池

Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了 日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的 连接池之一。

package hqyj;

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.Statement;
import java.util.Properties;

public class ConPool {
    public static void main(String[] args) throws Exception {
        Properties pro = new Properties();
        pro.load(new FileInputStream("src/jdbc.properties"));
//        创建数据库连接池
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//        获取数据库连接
        Connection con = ds.getConnection();
        Statement sta = con.createStatement();
        String sql = "select * from user";
        ResultSet re = sta.executeQuery(sql);
        while (re.next()) {
            System.out.println(re.getInt(1));
            System.out.println(re.getString(2));
            System.out.println(re.getString(3));
            System.out.println(re.getInt(4));
        }
        re.close();
        sta.close();
        con.close();
    }
}

加密/解密

场景:放置外人看到数据库当中的密码之类的隐秘信息,使用加密算法进行加密,需要验证的时候,使用解密算法进行解密.

常见加密算法

1,单向散列加密算法

常见算法包括:MD5、sha1、sha256等

2,对称加密算法

常见的算法有:DES、3DES、AES

3,非对称加密算法

常见算法包括:RSA、ECC

MD5

MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码),MD5加密算法用的是哈希函数,一般应用于对信息产生信息摘要,防止信息被篡改。最常见的使用是对密码加密、生成数字签名。

特点:

  1. 无论输入的消息有多长,加密后的长度总是固定的。
  2. 一般地,只要输入的消息不同,对其进行加密后产生的内容也必不相同;但相同的输入必会产生相同的输出。
  3. 只能进行正向的信息加密,而无法从加密内容中恢复出任何的原消息,甚至根本就找不到任何与原信息相关的信息(不可逆性)。
原理

获取md5对象,将目标字符串转换成字节数组,byte[] md5Bytes = md5.digest(byteArray);将字节数组加密,若字节数组长度小于16,转换成字符串StringBuffer,使用append做补0操作。

  1. 获取加密字符串
  2. 获取md5加密
  3. 将字符串转化成byte数组,将数组使用md5.digest(byteArray)发放加密计算
  4. 创建StringBuffer对象用来装字符串
  5. 遍历加密得到的字符数组,每次循环将得到的byte数据和(0xff)进行与运算
  6. 存入StringBuffer字符串,最终得到加密之后的数据
package hqyj;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MD5Test {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String paw = "ccc";
//        9df62e693988eb4e1e1444ece0578579
//        生成普通md5密码
        MessageDigest md5 = MessageDigest.getInstance("md5");
//        获取到byte数组,计算MD5加密后的16字节(128位)摘要
        byte[] bytesData = md5.digest(paw.getBytes());
//        创建此对象是为了添加字符串
        StringBuffer hexValue = new StringBuffer();
//        通过循环,将每一个字节做一个与运算(0xff),因为任意数与0xff做与运算都是取十六进制的后两位
        for (byte b : bytesData) {
            //加盐
            int num = b & 0xff;
//          然后将这个整数进行16进制转化操作
            String str = Integer.toHexString(num);
//            因为最终是将字符串转化为16位 所以不够两位的,需要在前面添加一个0
            if (str.length() == 1) {
                hexValue.append("0");
            }
            hexValue.append(str);
        }
        System.out.println(hexValue);
    }
}

练习:验证密码

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Oracle数据库是一种常见的关系型数据库管理系统,被广泛应用于企业级应用程序的开发和数据管理领域。CSDN(China Software Developer Network)是国内最大的软件开发者社区,提供了大量与数据库相关的学习资源,包括Oracle数据库学习内容。 在CSDN上,我们可以通过搜索功能迅速找到与Oracle数据库相关的教程、文章和帖子。这些资源涵盖了从基础入门到高级应用的各个方面。例如,我们可以找到关于Oracle SQL语法、表设计和索引优化的教程,以及如何使用PL/SQL进行存储过程和触发器的开发等等。这些教程通常由专业人士编写,质量较高,能够帮助我们深入理解Oracle数据库的各种功能和使用方法。 除了教程,CSDN还有很多Oracle数据库相关的实战案例和经验分享。在这些案例中,我们可以看到其他开发者在实际项目中如何应用Oracle数据库解决了具体的问题,这对我们的学习和实践非常有帮助。 另外,CSDN还提供了一个活跃的社区论坛,在这里我们可以与其他学习者和专业人士交流和讨论。如果遇到问题或者有疑惑,我们可以在论坛上提问,得到其他人的帮助和解答。这种互动交流的方式可以帮助我们更好地理解和应用Oracle数据库的知识。 综上所述,通过CSDN我们可以找到丰富的Oracle数据库学习资源,包括教程、实战案例和社区论坛等。利用这些资源,我们可以系统地学习和掌握Oracle数据库的各个方面,提升自己在数据库开发和管理方面的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值