mysql -root -p
回车后,待Enter password:
提示出现后输入密码即可mysql -uroot -proot
此种方式是-u
后面直接跟用户名,没有空格,同样的-p
后面直接跟密码数据库 -> 表 -> 记录
数据库:对库的操作
数据表:维护表的结构,如包含哪些列、叫什么名、什么类型、多大、各种结束等
记录:按表的结构来增删改查数据
官方文档
运算符
数据类型
标识符
数据类型:https://mariadb.com/kb/en/data-types/
字段名必须以字母开头,尽量不要使用拼音
长度不能超过30个字符(不同数据库,不同版本会有不同)
不能使用SQL的保留字,如where,order,group
只能使用如下字符az、AZ、0~9、$ 等
Oracle习惯全大写:USER_NAME,mysql习惯全小写:user_name
多个单词用下划线隔开,而非java语言的驼峰规则
字符
char长度固定,不足使用空格填充,最多容纳2000个字符,char(11)存储abc,占11位。查询速度极快但浪费空间
varchar变长字符串,最多容纳4000个字符,varchar(11)存储abc,只占3位。查询稍慢,但节省空间。Oracle为varchar2
大文本: 大量文字(不推荐使用,尽量使用varchar替代)
数字
tinyint,int整数类型
float,double小数类型
numeric(5,2) decimal(5,2)—也可以表示小数,表示总共5位,其中可以有两位小数
decimal和numeric表示精确的整数数字
日期
date 包含年月日
time时分秒
datetime包含年月日和时分秒
timestamp时间戳,不是日期,而是从1970年1月1日到指定日期的毫秒数
图片
blob 二进制数据,可以存放图片、声音,容量4g。早期有这样的设计。但其缺点非常明显,数据库庞大,备份缓慢,这些内容去备份多份价值不大。同时数据库迁移时过大,迁移时间过久。所以目前主流都不会直接存储这样的数据,而只存储其访问路径,文件则存放在磁盘上。
https://mariadb.com/kb/en/data-manipulation/
SELECT INSERT UPDATE DELETE
https://mariadb.com/kb/en/data-definition/
CREATE DATABASE
CREATE TABLE
ALTER TABLE
DROP TABLE
CREATE VIEW
ALTER VIEW
DROP VIEW
TRUNCATE TABLE
CONNECT、GRANT、DENY
SELECT、INSERT、UPDATE、DELETE
EXECUTE、USAGE、REFERENCES
SELECT
show databases;
查看数据库
select * from information_schema.schemata;
与上面一样的功能,只是信息更多一些
create database testdb default character set utf8
创建数据库 database后面跟要创建的数据库的名字,后面四个单词是用来指定数据库默认编码为utf8,也可以指定其他编码
show variables like "%char%";
查看整个数据库的所有编码相关信息
show create database testdb;
查看指定数据库的编码
ALTER DATABASE testdb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
修改指定数据库的编码
alter table [数据库名称.表名称] character set utf8;
修改指定数据表的编码
alter table [表名称] change [字段名称] [字段名称] [类型] character set utf8;
修改指定数据表中字段的编码
drop database testdb
删除数据库testdb
show tables;
查看当前数据库中的所有的表
select * from information_schema.tables where table_schema = 'science' and table_name like '%science%' limit 10;
查看指定数据库中有哪些名字中包含science中的表
desc testdb.ta;
查看指定表的结构
drop table ta;
删除指定表
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) NULL DEFAULT NULL,
`password` VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) default COLLATE='utf8_general_ci'
alter table testb add column money numeric(7,2);
rename table 原表名 to 新表名;
insert into users values(1,"张三","123"); --按原表里面的各列的顺序和数量来插入时,可以使用此种简写
insert into users(name,password) values("李四","23");--插入的列的数量或是顺序与表格不一致时,可以手动指定要插入的列的名称与顺序
set names gbk;--如果插入数据时,报中文字段值太长如"ERROR(22001):Data too long for column 'loc' at row 1"这个报错,就可以临时使用这个命令来临时解决
insert into if not exists
问题DUPLICATE KEY
的错误提示,导致批处理无法执行。此时,可以使用如下语句,即在原有的insert语句的最后面加上ON DUPLICATE KEY UPDATE id = id
,这里的id
为表中的字段,任意字段都可以的,意思是如果插入时报DUPLICATE
的错,则将id
的值更新为原有的值,也就是不更新,也就实现了所谓的INSERT IF NOT EXISTS
。当然了,这只是该语句的一个用法,详细用法移步官方文档:13.2.5.2 INSERT … ON DUPLICATE KEY UPDATE 语句insert into users values(1,"张三","123") ON DUPLICATE KEY UPDATE id = id;
也可以使用ignore
关键字
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t (i) VALUES('abc');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'i' at row 1 |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)
官方文档:https://dev.mysql.com/doc/refman/5.7/en/insert.html
https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#ignore-effect-on-execution
delete from users where id = 1;--删除users表中id=1的记录,如果不写where条件,则整个表中所有的数据全部被删掉
联表限制查询条件,如下为删除sys_role_permission
表中无法与sys_role
表中相匹配的数据
delete ta
from sys_role_permssion as ta
left join sys_role as tb on ta.roleId = tb.id
where tb.id is null;
关于联表删除的还有其他写法,可看此文章:https://blog.csdn.net/xia_xing/article/details/47780091
字段约束可以混搭
主键列用于区分每条记录,因此需要整表唯一且不能为空
CREATE TABLE `users` (
`id` INT(11) PRIVMARY KEY,
`name` VARCHAR(64) NULL DEFAULT NULL
)
AUTO_INCREMENT
用于修饰int型的字段的值自动递增,Oracle中可设置自增策略
CREATE TABLE `users` (
`id` INT(11) PRIVMARY KEY AUTO_INCREMENT,
`name` VARCHAR(64) NULL
)
当向表中定义为主键的列插入相同的值时,会遇到如下错误
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
该字段不能为null,其他任意值都可以
CREATE TABLE tb_user(
id INT AUTO_INCREMENT,
NAME VARCHAR(30) UNIQUE NOT NULL,
age INT,
phone VARCHAR(20) UNIQUE NOT NULL,
email VARCHAR(30) UNIQUE NOT NULL,
PRIMARY KEY (id)
);
向定义了非空约束的列中插入null值时,会遇到如下错误
ERROR 1048 (23000): Column 'uid' cannot be null
该字段的值必须整个表内唯一,不可重复,比如身份证号、手机号,每个人的都不能一样
CREATE TABLE tb_user(
id INT,
NAME VARCHAR(30) UNIQUE NOT NULL,
phone VARCHAR(20) UNIQUE NOT NULL,
email VARCHAR(30) UNIQUE NOT NULL,
PRIMARY KEY (id)
);
向表中定义了唯一约束的列中插入相同的值时,会遇到如下错误
ERROR 1062 (23000): Duplicate entry '1' for key 'uid'
default
关键字,create table e(id int primary key auto_increment,sex varchar(10) default '男')
这样插入时如果此列的值为默认值,则可以不这一列赋值
insert into a (id) values(1);#sex有默认值,添加记录时不给值的话就是默认值
references
指向的列必须至少是unique的,主键自带unique,foreign key()
里面的列应该是没有太多的要求CREATE TABLE t_user(id INT PRIMARY KEY AUTO_INCREMENT,t_name VARCHAR(20));
create table tb_user_address(user_id int primary key,address varchar(255),foreign key(user_id) references tb_user(id));
# 定义了外键约束后,外键所在表插入被参考表里面没有的关键值时会得到如下错误
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`cgb2109`.`tb_user_address`, CONSTRAINT `tb_user_address_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`))
# 被参考表里面想要删除`外键所在表中已经存在了的关键值`的记录时,会得到如下错误
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`cgb2109`.`tb_user_address`, CONSTRAINT `tb_user_address_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`))
很少使用,了解即可,录入age超过200将报错,使用check
关键字
ERROR 4025 (23000): CONSTRAINT `tb_user .age` failed for `dm`.`tb_user ` #设置了检查约束后如果插非法数据,会得到此错误信息
DROP TABLE IF EXISTS tb_user; #如果表存在则删除,慎用会丢失数据
CREATE TABLE tb_user (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, #自增主键
NAME VARCHAR(50) NOT NULL UNIQUE, #非空,唯一索引
sex CHAR(2) DEFAULT '男', #默认值
phone CHAR(18),
age INT,
CHECK (age>0 AND age<=200),
createdTime DATE DEFAULT NOW()
);
DESC tb_user;
select upper(dname) from dept;--查询所有的部门名称,并将部门名称里面的值转成大写
select lower(dname) from dept;--查询所有的部门名称,并将部门名称里面的值转成小写
select length(dname) from dept;--查询所有的部门名称,但只显示其字节数
start
个位置开始,截取length
个字符。start
从1开始,这里是按字符,一个字母或一个中文都是一个字符,不够的就有多少显示多少。#
SUBSTRING(str,pos),
SUBSTRING(str FROM pos),
SUBSTRING(str,pos,len),
SUBSTRING(str FROM pos FOR len)
SUBSTR(str,pos),
SUBSTR(str FROM pos),
SUBSTR(str,pos,len),
SUBSTR(str FROM pos FOR len)
#
select substr(dname,2,3);--只显示部门名称从第2个位置开始,共显示3个字符
select ename,concat(ename,123) from emp;--在每个ename的值的后面拼接上字符串123
SELECT * FROM `wms_sku`;
SELECT order_id,group_concat(sku_name ORDER BY sku_name DESC SEPARATOR "|") AS skus FROM wms_sku GROUP BY order_id;
select dname,replace(dname,'j','Mr j') X from dept;--把j字符替换成Mr j
select ifnull(comm,3.13) as com from emp;--把comm列值是null的替换成3.13后显示
select round(comm) from emp;--对薪水四舍五入处理
select ceil(comm) from emp;--对薪水向上取整
select floor(comm) from emp;-- 对薪水向下取整
select now(),year(now()),month(now()),day(now()),hour(now()),minute(now()),second(now()); -- 分别获取当前时间、年、月、日、时、分秒
select "a\'b";
SELECT DISTINCT loc FROM dept;-- 查询所有的部门,总共有几个办公地点
UUID 是一个 128 位的数字,由 utf8 字符串表示,aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 格式为五个十六进制数字:
- 前三个数字是从时间戳生成的。
- 第四个数字保留时间唯一性,以防时间戳值失去单调性(例如,由于夏令时)。
- 第五个数字是提供空间唯一性的 IEEE 802 节点编号。如果后者不可用(例如,由于主机没有以太网卡,或者我们不知道如何在操作系统上找到接口的硬件地址),则用随机数代替。在这种情况下,无法保证空间唯一性。尽管如此,碰撞的概率应该非常低。
AS
关键字)参考链接
https://mariadb.com/kb/en/select/
select * from emp
select * from emp where 1=1 --类似没条件
select * from emp where 1=0 --条件不成立
select * from emp where empno=100 --唯一条件
select * from emp where ename='tony' and deptno=2 --相当于两个条件的&关系
select * from emp where ename='tony' or deptno=1 --相当于两个条件的|关系
select name, sal from emp where sal=1400 or sal=1600 or sal=1800;
-- 或
select name, sal from emp where sal in(1400,1600,1800);
select name, sal from emp where sal not in(1400,1600,1800);
select * from emp where ename like 'l%' --以l开头的
select * from emp where ename like '%a' --以a结束的
select * from emp where ename like '%a%' --中间包含a的
select * from emp where ename like 'l__' --l后面有两个字符的 _代表一个字符位置
select * from emp where mgr is null
而不是select * from emp where mgr = null
select * from emp where mgr <=> null --过滤字段值为空的
select * from emp where mgr is null --过滤字段值为空的
select * from emp where mgr is not null --过滤字段值不为空的
select * from emp where sal between 5000 and 10000;
LIMIT [offset, ]row_count #跳过offset条记录,返回接下来的row_count条记录
LIMIT row_count OFFSET offset#跳过offset条记录,返回接下来的row_count条记录
select * from emp limit 2;
select * from emp order by sal asc,mgr desc;
@r :=@r + 1 as alias
放在select 里面,然后在from的表的最后面加,(select @r:=0) as alias
#给查询结果加个序号
select @i:=@i+1,ta.*
from dept as ta,(select @i:=0) as t;//其实后面这句就相当于是初始货@i这个变量并赋值
select ename,sal,ifnull(sal,0)*13 as 年薪,comm,ifnull(comm,0)*13 as 年奖金 from emp;
官方文档
把一列所有的值聚合起来,然后做数据分析
group by
是可以使用列的虽名的。SELECT YEAR(hiredate) AS ye ,COUNT(1) FROM emp GROUP BY YEAR(hiredate);
having
也是可以使用别名的SELECT deptno,MAX(sal) FROM emp GROUP BY deptno HAVING MAX(sal)>10000;
由于having过程是在聚合函数执行以后,所以如果需要对使用了非聚性质的函数的列进行筛选时,需要以如下的方式来指定列名
select year(ta.hiredate),count(1) #此时第一个列的列名已经变成了year(ta.hiredate)
from emp as ta
group by YEAR(ta.hiredate)
having `year(ta.hiredate)`>2002;
窗口函数,也叫OLAP函数(Online Anallytical Processing,联机分析处理),可以对数据库数据进行实时分析处理。
个人理解窗口函数就是对查询出来的数据进行有序计算,比如我们用各种限定条件查询出来十天的销售记录,这十条记录是按日期排序的,如果希望每一行都能直接显示出从第一行到当前行累计的销售额,那么窗口函数就派上用场了
详细内容参考:https://www.cnblogs.com/SmithBee/p/16056458.html
还有一个有序计算的:https://www.jianshu.com/p/1a176fc50e7f
工作上遇到一个例子,就是需要计算当前行和上一行的差值,如果数据库版是5.7没有窗口函数的话,可以尝试下使用变量的方式
注意:5.7没有窗口函数
select empno,@i as lastEmpno,@i:=empno
from emp,(select @i:=-1) as ta
order by empno
可以得到这样的结果,也就达到目的了
但是!官方不推荐这样使用!原因是包含变量的表达式的计算顺序是没有定义的,即不保证能获得稳定的结果参考文档
However, the order of evaluation for expressions involving user variables is undefined.
empno | lastEmpno | @i:=empno |
---|---|---|
100 | -1 | 100 |
200 | 100 | 200 |
300 | 200 | 300 |
400 | 300 | 400 |
500 | 400 | 500 |
优化:小表驱动大表,因为from后面的表是注定要全表扫描的,所以可以把结构简单或是记录条数小的表格放到from后面会提高效率。
from
join
on
where
group by(开始使用select中的别名,后面的语句中都可以使用)
avg,sum....
having
select
distinct
order by
limit
是指作为单个逻辑工作单元的一系列操作,要么全部执行成功,要么全部失败,都不执行。
https://mariadb.com/kb/en/transactions/
可参考此文章来记忆
性能最好,但是安全性最差
个人理解,就是指一个事务在查询数据时,会受到其他尚未提交的事务已经“执行”的修改的影响。例如,事务A第一次查询后并未提交,但此时事务B开始了,然后执行了数据的插入,但是未提交,然后此时事务A又执行了一次查询,那么在当前级别下还没有被事务B提交的插入的数据,也会被查询出来。
Oracle默认级别性稍好,安全性较好
个人理解,可以对比着读未提交来理解,就是只能查询到其他已经提交的数据,尚未提交的数据不会。
性能较差 ,但安全性好。
个人理解,事务开始后,查询到的数据会被直接生成一个快照(至于这个快照的粒度有多大就不清楚了,具说是MVCC),当前事务提交前再次执行同样的查询时,还是从这个快照上查询,因此也就实现了当前事务内,重复查询时数据一致。Mysql默认级别。
个人理解:表级锁,一个表同一时间只能被一个事务所访问。效率低 下,安全性高,不能并发。
默认情况,mysql每一条mysql语句都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要手动开启事务和结束事务。
select @@tx_isolation; # 查询当前数据库的事务隔离级别
start transaction; --开启事务
# 这里放一堆需要同时执行成功的SQL语句
committed; --提交事务,把SQL语句对数据库的影响持久化。
rollback; --回滚事务,如果事务执行中途失败了,也会默认执行回滚,取消所有对数据的操作
insert into user(name,pwd) values ('Alice',md5('623')),('Qiura',md5('625')); ##批量插入时使用此种方式默认只会开启一次事务,可以提高效率
可以看林晓斌MySql实战45讲https://funnylog.gitee.io/mysql45/iframe/
如果打不开了可以看这个大搬运https://blog.csdn.net/qq_40378034/article/details/90904573
官方文档关于innodb
的锁https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
join
关键字#查询“计算机导论”这门课程的总分数
#子查询的方式
select sum(degree)
from scores
where cno =
(select cno
from courses
where cname = '计算机导论');
#联接的方式
select sum(degree)
from scores as ta join courses as tb
on ta.cno = tb.cno
where tb.cname = '计算机导论';
#子查询只返回一个值时,可以直接使用 = 来做比较
select ename from emp where deptno = (select deptno from dept where dname = 'accounting');
#子查询返回的值超过一个时,请使用 in 关键字
select ename from emp where deptno in (select deptno from dept where loc = '二区');
distinct
关键字来去掉重复项(在只显示需要处理的那个表的数据的前提下)。=
子查询的结果时,会遇到如下错误ERROR 1242 (21000): Subquery returns more than 1 row
定义:索引是一种排好序的、支持快速查找的数据结构,它帮助数据库高效的进行数据的检索。在数据之外,数据库系统还维护着满足特定查找算法的数据结构(额外的空间),这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高效的查找算法,这种数据结构就叫做索引。
分类:单值索引、唯一索引、复合索引
单值索引:索引只包括一个列,表里面可以有其他的列
# 用来查看dept表中现有的索引有哪些,以下两条是一样的
show index from dept;
show keys from dept;
# 给dept表中的loc字段创建索引
create index loc_index on dept(loc);
# 查看所有表的索引
SELECT a.TABLE_SCHEMA,
a.TABLE_NAME,
a.index_name,
GROUP_CONCAT(column_name ORDER BY seq_in_index) AS `Columns`
FROM information_schema.statistics a
GROUP BY a.TABLE_SCHEMA,a.TABLE_NAME,a.index_name
索引查询结果列表中各字段的含义:
Non_unique
:如果索引不能包括重复词,则为0。如果可以,则为1。
Key_name
:索引的名称。
Seq_in_index
:索引中的列序列号,从1开始。
Column_name
:列名称。
Collation
:列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。
Cardinality
:索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机 会就越大。
Sub_part
:如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。
Packed
: 指示关键字如何被压缩。如果没有被压缩,则为NULL。
Null
: 如果列含有NULL,则含有YES。如果没有,则该列含有NO。
Index_type
:用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。
最左原则
# 创建复合索引
create index name_index on persons(LastName,FirstName);
select * from persons where LastName = 'lily';# 此查询会使用复合索引
select * from persons where FirstName = 'Mr';# 此查询不会使用复合索引
# 创建唯一索引
create unique index dname_unique_index on dept(dname);
# 删除索引
ALTER TABLE `dept` DROP INDEX `loc_index`;
EXPLAIN
关键字EXPLAIN SELECT * FROM emp WHERE ename = 'jack';
create view 视图名 as SQL语句;
select * from 视图名;
#视图:就是一个特殊的表,缓存上次的查询结果
#好处是提高了SQL的复用率,坏处是占内存无法被优化
#1.创建视图
CREATE VIEW emp_view AS
SELECT * FROM emp WHERE ename LIKE '%a%' #模糊查询,名字里包含a的
#2.使用视图
SELECT * FROM emp_view
由索引牵出来的优化问题:https://blog.csdn.net/weixin_39796652/article/details/111668287
*
,而是具体字段or
来连接条件,减少查询结果的数据量varchar
代替char
主键(id):primary key优先使用数值类型int,tinyint
性别(sex):0-代表女,1-代表男;数据库没有布尔类型,mysql推荐使用tinyint
支付方式(payment):1-现金、2-微信、3-支付宝、4-信用卡、5-银行卡
服务状态(state):1-开启、2-暂停、3-停止
商品状态(state):1-上架、2-下架、3-删除
explain
分析SQL执行计划是否使用了索引及其扫描类型
type:
ALL 全表扫描,没有优化,最慢的方式
index 索引全扫描
range 索引范围扫描,常用语<,<=,>=,between等操作
ref 使用非唯一索引扫描或唯一索引前缀扫描,返回单条记录,常出现在关联查询中
eq_ref 类似ref,区别在于使用的是唯一索引,使用主键的关联查询
const/system 单条记录,系统会把匹配行中的其他列作为常数处理,如主键或唯一索引查询
null MySQL不访问任何表或索引,直接返回结果
key:
真正使用的索引方式
Extra:原文连接
Extra | 说明 | 解读 |
---|---|---|
Using where | SQL使用了where条件过滤数据 | 常见的优化方法为,在where过滤属性上添加索引。 |
Using index | SQL所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录 | 这类SQL语句往往性能较好 |
Using index condition | 确实命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录 | 这类SQL语句性能也较高,但不如Using index |
Using filesort | 得到所需结果集,需要对所有记录进行文件排序 | 这类SQL语句性能极差,需要进行优化。 典型的,在一个没有建立索引的列上进行了order by,就会触发filesort,常见的优化方案是,在order by的列上添加索引,避免每次查询都全量排序 |
Using temporary | 需要建立临时表(temporary table)来暂存中间结果 | 这类SQL语句性能较低,往往也需要进行优化。典型的,group by和order by同时存在,且作用于不同的字段时,就会建立临时表,以便计算出最终的结果集 |
Using join buffer (Block Nested Loop) | 需要进行嵌套循环计算 | 这类SQL语句性能往往也较低,需要进行优化。典型的,两个关联表join,关联字段均未建立索引,就会出现这种情况。常见的优化方案是,在关联字段上添加索引,避免每次嵌套循环计算。 |
alter table student add index inde_name(name); #也可以使用之前学的create index
!=
或<>
,因为可能返回更多的数据select distinct * from emp;# 这种就不建议
insert into studdent(id,name) values(4,'lily'),(5,'mary');# sqlyog工具导出后就是这样的写法,说是只开启一次事务
group by
的效率,可以在执行到该语句前,先使用where把不需要的记录过滤掉in
子查询的优化,用来设计表时的一些原则,范式NF(Normal Form),分为六大范式,通常只 需要了解三大范式就可以了
mysql-connector-java-5.1.32.jar #mariadb10.4(不含)之前的数据库的话用这个
mysql-connector-java-8.0.24.jar #mariadb10.4(含)开始的用这个
把上面的相应的jar包直接复制到project目录下,然后在IDEA里面,选中这个jar包,右键-Aad as Library,只要看到这个jar包前面有可以小箭头了,就说明导入成功了。
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
//定义地址 协议:jdbc:mysql: 加mysql的地址
String url = "jdbc:mysql://localhost/cgb2109";
/*如果出现中文乱码,可采用如下的方式,增加编码指定*/
/*String url ="jdbc:mysql://localhost:3306/mydb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false";*/
//获取连接
Connection connection = DriverManager.getConnection(url, "root", "root");
//获得statement
Statement statement = connection.createStatement();
//执行SQL并取得结果集
ResultSet resultSet = statement.executeQuery("select * from dept;");
//获取列名的集合
ResultSetMetaData metaData = resultSet.getMetaData();
//拿到列数
int columnCount = metaData.getColumnCount();
//遍历输出每一列的列名
for (int i = 0; i < columnCount; i++) {
System.out.print(metaData.getColumnName(i + 1) + "\t");
}
System.out.println();
//遍历输出每一行,当resultSet还有下一行时,next()方法返回true
while (resultSet.next()) {
//遍历输出当前行的每一列的值
for (int i = 0; i < columnCount; i++) {
//当前全部统一使用getString()方法取出该列的值,还有getByte\getShort\getInt\getFloat\getDouble..
System.out.print(resultSet.getString(i + 1) + "\t");
int empno = resultSet.getInt("empno");
}
System.out.println();
}
//关闭连接
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
DriverManager.getConnection(url,userName,passWord)
里面的url里面加入?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
来指定字符集
String url ="jdbc:mysql://localhost:3306/mydb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false";
String condition = "陈强";
String condition = "陈强' or 1=1 or '";
String condition = "陈强' or true or '";
String sql = "select * from teachers where tname='" + condition+"'";
利用sql中’单撇是字符串的结束符,or只要一个条件成立其它就不用再判断,而恶意造成sql查询失效,本应该只展示一条数据,结果全部展现。
注入后形成的SQL:SELECT * FROM teachers WHERE tname='陈强' OR 1=1 OR ''
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
Connection connection = DriverManager.getConnection("jdbc:mysql:///cgb2109", "root", "root");
PreparedStatement ps = connection.prepareStatement("select * from user where name = ? and pwd = ?");
ps.setString(1, "a");
ps.setInt(1, 123);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
System.out.println("登陆成功!");
}
ps.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
错误原因:jar没有导入,没有builder path
或 Class.forName("com.mysql.jdbc.Driver");
字符串拼写错误
Unknown database mydb;
错误原因:数据库名称拼写错误
Access denied for user ‘root123’@‘localhost’ (using password: YES)
错误原因:数据库用户名或者密码错误
Table ‘py-school-db.mydb’ doesn’t exist
错误原因:表不存在,也可能表名写错了