安装MySQL
这里建议大家使用压缩版,安装快,方便.不复杂.
软件下载
mysql5.7 64位下载地址:
https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip
电脑是64位的就下载使用64位版本的!
安装步骤
1、下载后得到zip压缩包.
2、解压到自己想要安装到的目录,本人解压到的是D:\Environment\mysql-5.7.19
3、添加环境变量:我的电脑->属性->高级->环境变量
选择PATH,在其后面添加: 你的mysql 安装文件下面的bin文件夹
4、编辑 my.ini 文件 ,注意替换路径位置
[mysqld]
basedir=D:\Program Files\mysql-5.7\
datadir=D:\Program Files\mysql-5.7\data\
port=3306
skip-grant-tables
5、启动管理员模式下的CMD,并将路径切换至mysql下的bin目录,然后输入mysqld –install (安装mysql)
6、再输入 mysqld --initialize-insecure --user=mysql 初始化数据文件
7、然后再次启动mysql 然后用命令 mysql –u root –p 进入mysql管理界面(密码可为空)
8、进入界面后更改root密码
update mysql.user set authentication_string=password('123456') where user='root'and Host = 'localhost';
9、刷新权限
flush privileges;
10、修改 my.ini文件删除最后一句skip-grant-tables
11、重启mysql即可正常使用
net stop mysql
net start mysql
12、连接上测试出现以下结果就安装好了
几个基本的数据库操作命令 :
update user set password=password('123456')where user='root'; 修改密码
flush privileges; 刷新数据库
show databases; 显示所有数据库
use dbname;打开某个数据库
show tables; 显示数据库mysql中所有的表
describe user; 显示表mysql数据库中user表的列信息
create database name; 创建数据库
use databasename; 选择数据库
exit; 退出Mysql
? 命令关键词 : 寻求帮助
-- 表示注释
命令行操作数据库
创建数据库 : create database [if not exists] 数据库名;
删除数据库 : drop database [if exists] 数据库名;
查看数据库 : show databases;
使用数据库 : use 数据库名;
数据值和列类型
列类型 : 规定数据库中该列存放的数据类型
数值类型
字符串类型
日期和时间型数值类型
NULL值
通常用图形化界面操作,稍作了解
创建表(CREATE TABLE)
CREATE TABLE IF NOT EXISTS `student` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` varchar(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` varchar(20) NOT NULL DEFAULT '123456' COMMENT '密码'
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
如果忘记了怎么写可以查看以前表的语句
-- 查看数据库的定义
SHOW CREATE DATABASE school;
-- 查看数据表的定义
SHOW CREATE TABLE student;
-- 显示表结构
DESC student;
修改表 ( ALTER TABLE )
修改表名 :ALTER TABLE 旧表名 RENAME AS 新表名
添加字段 : ALTER TABLE 表名 ADD字段名 列属性[属性]
修改字段 :
删除字段 : ALTER TABLE 表名 DROP 字段名
删除数据表
语法:DROP TABLE [IF EXISTS] 表名
外键
外键作用
保持数据一致性,完整性,主要目的是控制存储在外键表中的数据,约束。使两张表形成关联,外键只能引用外表中的列的值或使用空值。
例子,student表的grandId引用grand表的grandId
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`);
注意 : 删除具有主外键关系的表时 , 要先删子表 , 后删主表
INSERT命令
语法:
INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3')
INSERT INTO grade(gradename) VALUES ('大一');
update命令
语法:
UPDATE 表名 SET column_name=value [,column_name2=value2,...] [WHERE condition];
UPDATE grade SET gradename = '高中' WHERE gradeid = 1;
DELETE命令
语法:
DELETE FROM 表名 [WHERE condition];
DELETE FROM grade WHERE gradeid = 5
SELECT
语法
SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name2] -- 联合查询
[WHERE ...] -- 指定结果需满足的条件
[GROUP BY ...] -- 指定结果按照哪几个字段来分组
[HAVING] -- 过滤分组的记录必须满足的次要条件
[ORDER BY ...] -- 指定查询记录按一个或多个条件排序
[LIMIT {[offset,]row_count | row_countOFFSET offset}];
-- 指定查询的记录从哪条至哪条
注意 : [ ] 括号代表可选的 , { }括号代表必选得
查询全部
-- 查询所有学生信息
SELECT * FROM student;
查询指定字段
-- 查询指定列(学号 , 姓名)
SELECT studentno,studentname FROM student;
可以取别名,方便使用
-- 这里是为列取别名(当然as关键词可以省略)
SELECT studentno AS 学号,studentname AS 姓名 FROM student;
-- 使用as也可以为表取别名
SELECT studentno AS 学号,studentname AS 姓名 FROM student AS s;
-- 使用as,为查询结果取一个新名字
-- CONCAT()函数拼接字符串
SELECT CONCAT('姓名:',studentname) AS 新姓名 FROM student;
DISTINCT关键字的使用
作用 : 去掉SELECT查询返回的记录结果中重复的记录 ( 返回所有列的值都相同 ) , 只返回一条
-- # 查看哪些同学参加了考试(学号) 去除重复项
SELECT * FROM result; -- 查看考试成绩
SELECT studentno FROM result; -- 查看哪些同学参加了考试
SELECT DISTINCT studentno FROM result; -- 了解:DISTINCT 去除重复项 , (默认是ALL)
使用表达式的列
-- 学员考试成绩集体提分一分查看
SELECT studentno,StudentResult+1 AS '提分后' FROM result;
-- 查询考试成绩在95-100之间的
SELECT Studentno,StudentResult
FROM result
WHERE StudentResult>=95 AND StudentResult<=100;
-- 除了1000号同学,要其他同学的成绩
SELECT studentno,studentresult
FROM result
WHERE studentno!=1000;
模糊查询 :比较操作符
操作符名称 | 语法 | 描述 |
---|---|---|
is null | a is null | 若操作符为空,则结果为真 |
is not null | a is not null | 若操作符不为空,则结果为真 |
between | a between b and c | 若a在b和c 之间,则结果为真 |
like | a like b | 若a与b匹配,则结果为真 |
in | a in(a1,a2,a3,…) | 若a对于a1,a2其中一个,则结果为真 |
like的使用
-- LIKE
-- =============================================
-- 查询姓刘的同学的学号及姓名
-- like结合使用的通配符 : % (代表0到任意个字符) _ (一个字符)
SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘%';
-- 查询姓刘的同学,后面只有一个字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘_';
-- 查询姓刘的同学,后面只有两个字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘__';
-- 查询姓名中含有 嘉 字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '%嘉%';
in的使用
-- IN
-- =============================================
-- 查询学号为1000,1001,1002的学生姓名
SELECT studentno,studentname FROM student
WHERE studentno IN (1000,1001,1002);
-- 查询地址在北京,南京,河南洛阳的学生
SELECT studentno,studentname,address FROM student
WHERE address IN ('北京','南京','河南洛阳');
JOIN 对比
操作符名称 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,则返回行 |
left join | 即使右表中没有匹配,也从左表中返回行 |
right join | 即使左表中没有匹配,也从右表中返回行 |
-- 查询参加了考试的同学信息(学号,学生姓名,科目名,分数)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno
自连接
将一个表看成两个一样的表
SELECT a.categoryName AS '父栏目',b.categoryName AS '子栏目'
FROM category AS a,category AS b
WHERE a.`categoryid`=b.`pid`
排序
降序
ORDER BY StudentResult DESC
升序
ORDER BY StudentResult ASC
分页
limit
推导:
第一页 : limit 0,5
第二页 : limit 5,5
第三页 : limit 10,5
......
第N页 : limit (pageNo-1)*pageSzie,pageSzie
[pageNo:页码,pageSize:单页面显示条数]
-- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
SELECT studentno,subjectno,StudentResult
FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '数据库结构-1'
)
ORDER BY studentresult DESC;
GROUP BY 按什么分组 HAVING 分组的过滤条件
-- 查询不同课程的平均分,最高分,最低分
-- 前提:根据不同的课程进行分组
SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY r.subjectno
HAVING 平均分>80;
/*
where写在group by前面.
要是放在分组后面的筛选
要使用HAVING..
因为having是从前面筛选的字段再筛选,而where是从数据表中的>字段直接进行的筛选的
*/
数据函数
SELECT ABS(-8); /*绝对值*/
SELECT CEILING(9.4); /*向上取整*/
SELECT FLOOR(9.4); /*向下取整*/
SELECT RAND(); /*随机数,返回一个0-1之间的随机数*/
SELECT SIGN(0); /*符号函数: 负数返回-1,正数返回1,0返回0*/
字符串函数
SELECT CHAR_LENGTH('狂神说坚持就能成功'); /*返回字符串包含的字符数*/
SELECT CONCAT('我','爱','程序'); /*合并字符串,参数可以有多个*/
SELECT INSERT('我爱编程helloworld',1,2,'超级热爱'); /*替换字符串,从某个位置开始替换某个长度*/
SELECT LOWER('KuangShen'); /*小写*/
SELECT UPPER('KuangShen'); /*大写*/
SELECT LEFT('hello,world',5); /*从左边截取*/
SELECT RIGHT('hello,world',5); /*从右边截取*/
SELECT REPLACE('狂神说坚持就能成功','坚持','努力'); /*替换字符串*/
SELECT SUBSTR('狂神说坚持就能成功',4,6); /*截取字符串,开始和长度*/
SELECT REVERSE('狂神说坚持就能成功'); /*反转
-- 查询姓周的同学,改成邹
SELECT REPLACE(studentname,'周','邹') AS 新名字
FROM student WHERE studentname LIKE '周%';
日期和时间函数
SELECT CURRENT_DATE(); /*获取当前日期*/
SELECT CURDATE(); /*获取当前日期*/
SELECT NOW(); /*获取当前日期和时间*/
SELECT LOCALTIME(); /*获取当前日期和时间*/
SELECT SYSDATE(); /*获取当前日期和时间*/
-- 获取年月日,时分秒
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());
系统信息函数
SELECT VERSION(); /*版本*/
SELECT USER(); /*用户*/
函数名称 | 描述 |
---|---|
COUNT() | 返回满足Select条件的记录总和数,如 select count(*) 【不建议使用 *,效率低】 |
SUM() | 返回数字字段或表达式列作统计,返回一列的总和。 |
AVG() | 通常为数值字段或表达列作统计,返回一列的平均值 |
MAX() | 可以为数值字段,字符字段或表达式列作统计,返回最大的值。 |
MIN() | 可以为数值字段,字符字段或表达式列作统计,返回最小的值。 |
SELECT COUNT(*) FROM student;
SELECT SUM(StudentResult) AS 总和 FROM result;
SELECT AVG(StudentResult) AS 平均分 FROM result;
SELECT MAX(StudentResult) AS 最高分 FROM result;
SELECT MIN(StudentResult) AS 最低分 FROM result;
什么是事务
事务的ACID原则
原子性(Atomic)
一致性(Consist)
隔离性(Isolated)
持久性(Durable)
基本语法
-- 使用set语句来改变自动提交模式
SET autocommit = 0; /*关闭*/
SET autocommit = 1; /*开启*/
-- 注意:
--- 1.MySQL中默认是自动提交
--- 2.使用事务时应先关闭自动提交
-- 开始一个事务,标记事务的起始点
START TRANSACTION
-- 提交一个事务给数据库
COMMIT
-- 将事务回滚,数据回到本次事务的初始状态
ROLLBACK
-- 还原MySQL数据库的自动提交
SET autocommit =1;
-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
测试
SET autocommit = 0
START TRANSACTION
UPDATE ACCOUNT SET cash=cash-500 WHERE `name`='A';
UPDATE ACCOUNT SET cash=cash+500 WHERE `name`='B';
COMMIT;
--rollback;
SET autocommit = 1;
当数据库比较复杂时我们需要设计数据库
糟糕的数据库设计 :
良好的数据库设计 :
软件项目开发周期中数据库设计 :
设计数据库步骤
收集信息
标识实体[Entity]
标识每个实体需要存储的详细信息[Attribute]
标识实体之间的关系[Relationship]
为什么需要数据规范化?
不合规范的表设计会导致的问题:
信息重复
更新异常
插入异常
删除异常
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。
如上图就不符合第一范式,应该调整如下
第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
保证每张表只描述一件事
举例说明:
在上图所示的情况中,同一个订单中可能包含不同的产品,因此主键必须是“订单号”和“产品号”联合组成,
但可以发现,产品数量、产品折扣、产品价格与“订单号”和“产品号”都相关,但是订单金额和订单时间仅与“订单号”相关,与“产品号”无关,
这样就不满足第二范式的要求,调整如下,需分成两个表:
第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
举例说明:
上表中,所有属性都完全依赖于学号,所以满足第二范式,但是“班主任性别”和“班主任年龄”直接依赖的是“班主任姓名”,
而不是主键“学号”,所以需做如下调整:
这样以来,就满足了第三范式的要求。
应用程序无法自主的调用数据库,不同的数据库需要不同的数据库驱动来操作数据库。
用于对数据库的统一操作,可以称为数据库的规范,我们只需要会操作Jsbc就可以实现对数据库的操作。
导入驱动
新建lib目录,把jar包放入lib文件夹,add as library
jdbc 测试
package com.chen.lesson01;
import java.sql.*;
public class JDBCFirst {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.用户信息和url
//userUnicode=true&characterEncoding=utf8&useSSL=true,支持中文编码,设置utf8编码格式,启用安全连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";
String pwd = "123456";
//3.连接成功,创建数据库对象 connection 表示数据库对象
Connection connection = DriverManager.getConnection(url, username, pwd);
//4.执行sql对象 statement 执行SQL的对象
Statement statement = connection.createStatement();
//5.执行sql语句,返回结果集 resultset
String sql ="SELECT * FROM `users`";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("id=" + resultSet.getObject("id"));
System.out.println("NAME=" + resultSet.getObject("NAME"));
System.out.println("PASSWORD=" + resultSet.getObject("PASSWORD"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birthday=" + resultSet.getObject("birthday"));
System.out.println("============================");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
步骤
1.加载驱动
2.用户信息和url
3.连接成功,创建数据库对象 connection 表示数据库对象
4.执行sql对象 statement 执行SQL的对象
5.执行sql语句,返回结果集 resultset
6.释放连接
先将参数信息保存到资源文件db.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true
username = root
pwd = 123456
编写工具类
package com.chen.lesson02.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver= null;
private static String url= null;
private static String username=null;
private static String pwd= null;
static {
try{
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
pwd=properties.getProperty("pwd");
//加载驱动
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,pwd);
}
//释放资源
public static void release(Connection cn, Statement st, ResultSet rs) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}if(cn!=null){
try {
cn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试调用工具类
package com.chen.lesson02;
import com.chen.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection coon = null;
Statement st = null;
ResultSet rs = null;
try {
coon = JdbcUtils.getConnection();//获取数据库连接
st = coon.createStatement();
String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)\n" +
"VALUES(5,'czt','123456','[email protected]','2020-01-01')";
int i =st.executeUpdate(sql);
if (i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(coon,st,rs);
}
}
}
sql存在问题,可以通过拼接字符串,恶意访问数据库,导致数据泄露
使用PreparedStatement对象可以防止sql注入
PreparedStatement使用方式
package com.chen.lesson02;
import com.chen.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert02 {
public static void main(String[] args) {
Connection cn = null;
PreparedStatement st = null;
try {
cn = JdbcUtils.getConnection();
String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)VALUES(?,?,?,?,?)";
st = cn.prepareStatement(sql);//预编译
st.setObject(1,4);
st.setObject(2,"czt");
st.setObject(3,"123456");
st.setObject(4,"[email protected]");
st.setObject(5,"2020-01-01");
int i = st.executeUpdate();
if(i>0){
System.out.println("成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(cn,st,null);
}
}
}
PreparedStatement会先预编译sql语句,通过传参的方式给sql语句赋值,当有sql注入时其中的转义字符如’'会被转义,从而达到防止sql注入的效果
基本结构
cn.setAutoCommit(false);//关闭数据库自动提交,同时会开启事务
sql语句
cn.commit();
如果事务执行失败则默认回滚
package com.chen.lesson02;
import com.chen.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) {
Connection cn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
cn = JdbcUtils.getConnection();
cn.setAutoCommit(false);
//关闭数据库自动提交,同时会开启事务
String sql1 = "update account set money = money-100 where name = 'A'";
st = cn.prepareStatement(sql1);
st.executeUpdate();
String sql2 = "update account set money = money+100 where name = 'B'";
st = cn.prepareStatement(sql2);
st.executeUpdate();
cn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
cn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
JdbcUtils.release(cn,st,rs);
}
}
}
数据库连接过程:
数据库连接—执行—释放连接
浪费资源
池化技术:预先准备一些数据连接
打个比方,银行服务:
没有连接池:开门—服务–关门
有连接池:开门–业务员–服务