1 数据库的备份和恢复
- 都是在命令窗口写的
1.1 备份
- 表和数据生成sql脚本,导出数据。
mysqldump -u root -p mydb>E:\WorkSpace\Excellent\mysql\a.sql
mysqldump -u 用户名 -p 数据库>路径 回车之后在密码
- 注意:脚本文件中没有创建数据库的语句,所以在恢复数据的时候,需要先创建或者指定一个数据库。
这个命令不需要登录mysql
1.2 恢复
- 执行sql脚本文件,恢复数据
- 前提:必须先有数据库
mysqldump -u root -p mydb<E:\WorkSpace\Excellent\mysql\a.sql
mysql -u 用户名 -p 数据库<路径 回车之后在密码
- 另一种方式
登录mysql
进入指定的数据库
source 文件路径
source E:\WorkSpace\Excellent\mysql\a.sql
1.3 注意:后面不能有;
- 恢复的时候要先看指定的数据库中有没有同名的表
2 数据库的范式
2.1 概述
- 为了创建出冗余较小,结构合理的数据库,设计数据库的时候就需要遵从一些规则,在关系型数据库中这些规则就叫做范式。
- 范式一共6中,一般满足前3范式,就可以设计出一个比较好的数据库。
2.2 第一范式
符合1NF的关系中的每个属性都不可再分
- 最基本的范式。要求表中的每一个字段的值都必须是一个不可分割的值。
- 比如:user表中的address字段。地址由:省市区组成,如果只设计成一个字段就不满足第一范式。
- 如果我们设计的系统经常要访问城市的值,如果把地址设计成一个字段,每次获取出来的值都是由省市区组成的,我们就需要截取地址中的城市这部门。如果我们设计的时候直接就把他们分开。获取的时候就直接可以获取到市的值,就不需要截取字符串了。
不满足第一范式
CREATE TABLE ccc(
id INT,
NAME VARCHAR(10),
address VARCHAR(50)
);
满足了第一范式
CREATE TABLE ccc2(
id INT,
NAME VARCHAR(10),
province VARCHAR(10),
city VARCHAR(10),
qu VARCHAR(10)
);
2.3 第二范式
满足1NF,表中的字段必须完全依赖于全部主键而非部分主键
- 第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)
- 第二范式要求:也就是说一个数据表中只能存一种数据。
CREATE TABLE ccc2(
id INT,
NAME VARCHAR(10),
province INT,
city INT,
qu INT,
);
INSERT INTO ccc VALUES(3,'小巴',1,2,1);
CREATE TABLE dlxx(
num INT,
NAME VARCHAR()
);
INSERT INTO dlxx VALUES(1,'陕西省');
INSERT INTO dlxx VALUES(2,'河北省');
INSERT INTO dlxx VALUES(3,'河南省');
INSERT INTO dlxx VALUES(4,'山西省');
2.4 第三范式
满足2NF,非主键外的所有字段必须互不依赖
- 数据库表中的每一列都要和主键直接相关,不能和主键的某一个部分相关。
- 比如订单表,可以把用户编号作为一个外键保存到订单信息表中,不能在订单信息表中在出现其他关于用户的信息。
CREATE TABLE product(
商品编号 INT,
商品名称 VARCHAR(10),
商品的描述
商品价格
....
);
CREATE TABLE USER(
用户编号
用户名称
用户地址
用户电话
.....
);
CREATE talbe info(
订单编号
商品编号
负责人
订单数量
客户编号
);
3 jdbc(java database connectivity)
3.1 概述
在java技术中,用于访问数据库的技术叫做jdbc。
是一种用于执行sql语句的javaAPI。
给多种关系型数据库提供了统一的访问方式。
由一组用java语言编写的类和接口组成。
实现了数据库链接的标准化和对象话,使用方便。支持不同的数据库。
- sun公司提供的一套数据库的标准规范(接口)— jdbcAPI.
- 数据库厂商或者一些第三方中间商根据该规范提供了对应的具体实现—jdbc驱动
- 规范和驱动的关系:接口和实现类的关系。
3.2 jdbc规范
实现了数据库链接的标准化和对象化,使用方便。支持不同的数据库。
-
主要掌握4个核心对象即可。
DriverManager:注册驱动
Connection:表示和数据库的链接
Statement:操作数据库sql语句的对象
ResultSet:结果集对象 -
使用jdbc操作数据库的步骤:
注册驱动
建立链接
创建发送sql语句的对象
执行对应的数据库操作
处理结果
关闭资源 -
开发jdbc程序的准备工作
规范在哪里?java.sql包下
驱动在哪里?mysql-connector-java-8.0.12.jar -
练习:完成jdbc链接数据查询数据
创建java项目
新建文件夹 lib
把数据库厂商提供的jar文件复制放入lib
右键 add as …
package com.momo.demo;
import java.sql.*;
/*
* 使用jdbc查询数据库,把数据展示到控制台上。
* */
public class Demo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//注册驱动
//这种方式不用,导致驱动被注册2次,依赖与jar包
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");
//建立链接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456");
//获取发送sql语句的对象
Statement stmt = conn.createStatement();
//执行对应的sql操作,获取结果
String sql = "select * from dept";
ResultSet rs = stmt.executeQuery(sql);
//处理结果
while (rs.next()){
System.out.print(resultSet.getInt("deptid")+"\t");
System.out.print(resultSet.getString("address")+"\t");
System.out.println(resultSet.getString("dname")+"\t");
System.out.println("-------------------------------");
}
//释放资源
rs.close();
conn.close();
stmt.close();
}
}
4 jdbc中常用的类和接口的介绍
4.1 java.sql.DriverManager类
- 用于管理一组jdbc驱动程序的基本服务
- 注册驱动
DriverManager.registerDriver() 不建议使用
使用 Class.forName(“com.mysql.cj.jdbc.Driver”); - 建立连接
三种方式(重载)
// static Connection getConnection(String url, String user, String password)
DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456");
尝试建立与给定数据库URL的连接。
static Connection getConnection(String url, String user, String password)
url:sun公司和数据库厂商之间的一种协议
jdbc:mysql://localhost:3306/test?serverTimezone=UTC
协议:子协议://ip地址:端口号/数据库?时区
jdbc:mysql:///test?serverTimezone=UTC 默认链接本机的
// static Connection getConnection(String url, Properties info)
Properties info = new Properties();
info.setProperty("user","root");
info.setProperty("password","123456");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", info);
Properties info 数据库参考的文档
还有一种写法,账号密码直接跟在后边,用&连接
// static Connection getConnection(String url)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&user=root&password=123456");
4.2 java.sql.Connection接口 表示连接
-
接口的实现在数据库驱动中。
-
所有和数据库的交互都是基于连接对象的。
Statement createStatement()
创建一个 Statement对象,用于将SQL语句发送到数据库。
4.3 java.sql.Statement接口 把SQL语句发送到数据库
- 接口的实现在数据库驱动中。
ResultSet executeQuery(String sql) 执行给定的DQL SQL语句,该语句返回单个ResultSet对象。
int executeUpdate(String sql) 执行给定的DML SQL语句,这可能是INSERT,DELETE,或UPDATE语句,返回受影响行数
boolean execute(String sql) 执行给定的任意SQL语句,返回值表示是否返回了 ResultSet 结果集对象。仅当执行select语句并且有返回结果时这个方法才返回true
4.4 java.sql.ResultSet接口 结果集(客户端存表数据的对象)
- 接口的实现在数据库驱动中。
- next和getInt getString
- 在这个对象中提供了一个游标,是一个可以移动的指针。默认是在第一行数据之前。
- boolean next() 每当我们调用一次next方法,这个游标就会向下移动一行。这个方法的返回值是boolean类型。如果下一行有数据返回真,否则返回假。
- get方法都是为了将来用javaBean封装获取到的数据
- Object getObject(int columnIndex) 获取resultSet中当前行指定列的值 参数是列的序号
- Object getObject(String columnName)获取resultSet中当前行指定列名的值 参数是列的名字
但是返回Object类型将来封装很麻烦,需要向下转型。所以我们以后用对应的get方法类获取- int getInt(int columnIndex)
- int getInt(String columnLabel)
- String getString(int columnIndex)
- String getString(String columnLabel)
每种类型都有对应的get方法。
- 将来要用java类封装数据库中的数据,要知道数据库和java的类型对应关系
byte tityint
short smallint
int int
long bigint
float float
double double
String char varchar
Date date
jdbc实现数据库增删改查
package com.mysql.Demo;
import com.mysql.Domain.Dept;
import java.sql.*;
import java.util.ArrayList;
/*
* jdbc 对数据库进行增删改查
* */
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取链接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456");
//创建发送sql语句的对象
Statement statement = connection.createStatement();
//执行sql 处理结果
// 增
// int i = statement.executeUpdate("INSERT INTO dept values(50,'渭南','销售部')");
// System.out.println("共"+i+"行受影响");
// 删
// int j = statement.executeUpdate("DELETE FROM dept WHERE deptid=50");
// System.out.println("共"+i+"行受影响");
// 改
int k = statement.executeUpdate("UPDATE dept set address='大连' where deptid=40");
// System.out.println("共"+k+"行受影响");
// 查
ResultSet resultSet = statement.executeQuery("SELECT * FROM dept");
// 用ArrayList装数据
ArrayList<Dept> list = new ArrayList<>();
while (resultSet.next()){
Dept d = new Dept();
d.setDeptid(resultSet.getInt("deptid"));
d.setDname(resultSet.getString("dname"));
d.setAddress(resultSet.getString("address"));
list.add(d);
}
// 释放资源
connection.close();
statement.close();
resultSet.close();
//遍历集合
for (Dept dept : list) {
System.out.println(dept);
}
}
}
package com.mysql.Domain;
public class Dept {
private int deptid;
private String address;
private String dname;
public int getDeptid() {
return deptid;
}
public void setDeptid(int deptid) {
this.deptid = deptid;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"deptid=" + deptid +
", address='" + address + '\'' +
", dname='" + dname + '\'' +
'}';
}
}
使用jdbc模拟用户登录功能
package com.mysql.Demo;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
/*
* 模拟用户登录功能
用户输入账号和密码。
链接数据库进行查询
如果数据库中有这个账号和密码就登录成功,否则登录失败。
* * */
public class Demo6 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 用户键盘输入账号 密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号");
String account = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
// 连接数据库进行查询
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接
Connection coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456");
//获取发送sql的对象
Statement statement = coon.createStatement();
//拿用户输入的账号和密码到数据库中查询
ResultSet resultSet = statement.executeQuery("SELECT * FROM user where account='" + account + "' and password='" + password + "'");
//判断看根据输入的账号和密码有没有找到信息,如果有就成功,否则失败
if(resultSet.next()){
Date date = new Date();
System.out.println("欢迎你:"+ resultSet.getString("name")+",登录成功,当前时间:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(date));
}else {
System.out.println("账号或密码错误,登录失败。。。");
}
// 释放资源
coon.close();
resultSet.close();
statement.close();
}
}
5 sql注入问题
5.1 引出
发现密码不正确 仍然登录成功 ,sql注入问题
5.2 解决注入问题
- 使用Statement的子类PreparedStatement对象即可。
- PreparedStatement
表示预编译的SQL语句的对象
它会把sql语句预先编译,然后我们传参数的时候它会过滤掉我们输入的关键字。 - 特点:
预编译sql
性能高
会过滤掉用户输入的关键字 - sql语句中的? 叫做占位符
使用对象中的setXxx方法给占位符赋值 ,这个方法有2个参数
第一个表示占位符的序号。
第二个表示要赋的值
package com.mysql.Demo;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Demo7 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//键盘输入账号密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号:");
String account = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456");
//获取preparedStatement对象
PreparedStatement preparedStatement = conn.prepareStatement("select * from user where account=? and password=?");
preparedStatement.setString(1,account);
preparedStatement.setString(2,password);
//执行sql
ResultSet resultSet = preparedStatement.executeQuery();
//判断看根据输入的账号和密码有没有找到信息,如果有就成功,否则失败
if(resultSet.next()){
Date date = new Date();
System.out.println("欢迎你:"+ resultSet.getString("name")+",登录成功,当前时间:"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(date));
}else{
System.out.println("账号或密码错误,登录失败。。。");
}
//释放资源p
resultSet.close();
preparedStatement.close();
conn.close();
}
}
- 写一个工具类 提供方法 直接获取连接对象
package com.mysql.Domain;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtil {
private static Connection conn;
//静态代码块
static{
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//提供一个方法,可以直接获取链接对象
public static Connection getConnection(){
Properties info = new Properties();
info.setProperty("user","root");
info.setProperty("password","123456");
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false", info);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
package com.mysql.Demo;
import com.mysql.Domain.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo8 {
public static void main(String[] args) throws SQLException {
Connection conn = JdbcUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement("select * from dept");
ResultSet rs = pstmt.executeQuery();
while (rs.next()){
System.out.println(rs.getObject(1));
}
conn.close();
pstmt.close();
rs.close();
}
}