文章目录
1. 表连接的分类
表连接 | 分类 | 语法 |
---|---|---|
内连接 | 隐式 | SELECT 字段 FROM 左表, 右表 WHERE 条件; |
显式 | SELECT 字段 FROM 左表, INNER JOIN 右表 ON 条件; | |
外连接 | 左外 | SELECT 字段 FROM 左表 LEFT OUTER JOIN 右表 ON 条件; |
右外 | SELECT 字段 FROM 左表 RIGHT OUTER JOIN 右表 ON 条件; |
1.1 子查询的三种情况
子查询的结果 | 使用运算符 |
---|---|
单行单列 | 作为条件 |
多行单列 | 作为条件 in |
多行多列 | 作为虚拟表 |
1.2 手动提交事务
功能 | MySQL语句 |
---|---|
开启事务 | start transaction; |
提交事务 | commit; |
回滚事务 | rollback; |
1.3 事务的四大特性
事务特性 |
---|
原子性 |
一致性 |
隔离性 |
持久性 |
2. JDBC的由来
-
直接写代码操作数据库
直接写代码操作数据库存在的问题:
- 不知道MySQL数据库的操作方式,解析方式
- 代码繁琐,写起来麻烦
- MySQL和Oracle等其他数据库的操作方式和解析方式不同,每个数据库都要写一套代码
- MySQL和Oracle等其他数据库相互切换麻烦
-
JDBC规范定义接口,具体的实现由各大数据库厂商来实现
JDBC是Java访问数据库的标准规范。真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用JDBC接口中的方法即可。数据库驱动由数据库厂商提供。
2.1 JDBC的好处
- 我们只需要会调用JDBC接口中的方法即可,使用简单
- 使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库
2.2 小结
- 说出JDBC的概念?Java数据库连接(Java操作数据库的标准规范)
- 说出JDBC的作用?Java通过JDBC就可以操作数据库
3. JDBC核心API的介绍
3.1 JDBC会用到的包
- java.sql:JDBC访问数据库的基础包,在JavaSE中的包。如:java.sql.Connection
- javax.sql: JDBC访问数据库的扩展包
- 数据库的驱动,各大数据库厂商来实现。如:MySQL的驱动:com.mysql.jdbc.Driver
3.2 JDBC四个核心对象
这几个类都是在java.sql包中
- DriverManager: 用于注册驱动
- Connection: 表示与数据库创建的连接
- Statement: 执行SQL语句的对象
- ResultSet: 结果集或一张虚拟表
3.3 JDBC访问数据库的步骤
-
由DriverManager注册驱动程序
-
创建连接对象Connection
-
由客户端发送SQL语句给服务器执行,SQL语句封装成Statement对象
-
查询到的结果集封装成ResultSet对象
-
在客户端可以从ResultSet中取出数据
-
释放资源,关闭连接对象
3.4 小结
JDBC四个核心对象?
-
DriverManager: 用于注册驱动
-
Connection: 表示与数据库创建的连接
-
Statement: 执行SQL语句的对象
-
ResultSet: 结果集或一张虚拟表
4. JDBC注册驱动
Connection
表示Java程序与数据库之间的连接,只有拿到Connection才能操作数据库。
JDBC获取连接步骤
1.导入mysql驱动Jar包
2.注册驱动
3.获取连接
4.1 注册驱动
我们Java程序需要通过数据库驱动才能连接到数据库,因此需要注册驱动。
MySQL的驱动的入口类是:com.mysql.jdbc.Driver
API介绍
java.sql.DriverManager
类用于注册驱动。提供如下方法注册驱动
static void registerDriver(Driver driver)
向 DriverManager 注册给定驱动程序。
4.1.1 注册驱动的两种方式
- 静态方法注册
DriverManager.registerDriver(驱动对象); 传入对应参数即可
【案例代码】
public class Demo01 {
public static void main(String[] args) throws Exception {
// 注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
}
}
通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
// 自己自动注册
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
}
}
注意:使用
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
,存在两方面不足
- 硬编码,后期不易于程序扩展和维护
- 驱动被注册两次
2.直接加载类文件
使用Class.forName("com.mysql.jdbc.Driver");
加载驱动,这样驱动只会注册一次
public class Demo01 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver"); // 后期可以将"com.mysql.jdbc.Driver"字符串写在文件中.
}
}
演示:Class.forName("包名.类名");
会走这个类的静态代码块
通常开发我们使用Class.forName() 加载驱动。Class.forName("com.mysql.jdbc.Driver");
会走Driver类的静态代码块。在静态代码块中注册一次驱动。
总结:注册MySQL驱动使用
Class.forName("com.mysql.jdbc.Driver");
4.2 小结
-
导入mysql驱动Jar包
-
通过JDBC注册数据库驱动?
Class.forName("com.mysql.jdbc.Driver");//好处,灵活,只会加载一次
5. 获取连接
5.1 API介绍
java.sql.DriverManager
类中有如下方法获取数据库连接
static Connection getConnection(String url, String user, String password)
连接到给定数据库 URL ,并返回连接。
5.2 参数说明
String url
:连接数据库的URL,用于说明连接数据库的位置String user
:数据库的账号String password
:数据库的密码
连接数据库的URL地址格式:协议名:子协议://服务器名或IP地址:端口号/数据库名?参数=参数值
MySQL写法:jdbc:mysql://localhost:3306/test
如果是本地服务器,端口号是默认的3306,则可以简写:jdbc:mysql:///test
5.3 注意事项
如果数据出现乱码需要加上参数: ?characterEncoding=utf8,表示让数据库以UTF-8编码来处理数据。
如: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
5.4 使用步骤
1.DriverManager.getConnection(url, user, password); 传入对应参数即可
案例代码
public class Demo01 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
// 连接到MySQL
// url: 连接数据库的URL
// user: 数据库的账号
// password: 数据库的密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day24", "root", "root");
System.out.println(conn);
}
}
5.5 小结
-
JDBC获取数据库连接使用哪个API?
DriverManager.getConnection(数据库url, 账号, 密码)
-
通过JDBC连接mysql的URL写法?
jdbc:mysql://localhost:3306/数据库
6. JDBC实现对单表数据增、删、改
准备数据
-- 创建分类表
CREATE TABLE category (
cid INT PRIMARY KEY AUTO_INCREMENT,
cname VARCHAR(100)
);
-- 初始化数据
INSERT INTO category (cname) VALUES('家电');
INSERT INTO category (cname) VALUES('服饰');
INSERT INTO category (cname) VALUES('化妆品');
JDBC实现对单表数据增、删、改
我们要对数据库进行增、删、改、查,需要使用Statement
对象来执行SQL语句。
API介绍
获取Statement对象
在java.sql.Connection
接口中有如下方法获取到Statement
对象
Statement createStatement()
创建一个 Statement 对象来将 SQL 语句发送到数据库
Statement的API介绍
-
boolean execute(String sql) 此方法可以执行任意sql语句。返回boolean值,表示是否返回ResultSet结果集。仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;
-
int executeUpdate(String sql) 根据执行的DML(INSERT、UPDATE、DELETE)语句,返回受影响的行数
-
ResultSet executeQuery(String sql) 根据查询语句返回结果集,只能执行SELECT语句
注意:在MySQL中,只要不是查询就是修改。
executeUpdate:用于执行增删改
executeQuery:用于执行查询
使用步骤
- 注册驱动
- 获取连接
- 获取Statement对象
- 使用Statement对象执行SQL语句
- 释放资源
案例代码
public class Demo03 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
System.out.println(conn);
// 从连接中拿到一个Statement对象
Statement stmt = conn.createStatement();
// 1.插入记录
String sql = "INSERT INTO category (cname) VALUES ('手机');";
int i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 2.修改记录
sql = "UPDATE category SET cname='汽车' WHERE cid=4;";
i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 3.删除记录
sql = "DELETE FROM category WHERE cid=1;";
i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 释放资源
stmt.close();
conn.close();
}
}
7. JDBC实现对单表数据查询
ResultSet
用于保存执行查询SQL语句的结果。
我们不能一次性取出所有的数据,需要一行一行的取出。
7.1 ResultSet的原理
- ResultSet内部有一个指针,刚开始记录开始位置
- 调用next方法, ResultSet内部指针会移动到下一行数据
- 我们可以通过ResultSet得到一行数据 getXxx得到某列数据
7.2 ResultSet获取数据的API
其实ResultSet获取数据的API是有规律的get后面加数据类型。我们统称getXXX()
7.3 使用JDBC查询数据库中的数据的步骤
- 注册驱动
- 获取连接
- 获取到Statement
- 使用Statement执行SQL
- ResultSet处理结果
- 关闭资源
7.4 案例代码
public class Demo04 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM category;";
ResultSet rs = stmt.executeQuery(sql);
// 内部有一个指针,只能取指针指向的那条记录
while (rs.next()) { // 指针移动一行,有数据才返回true
// 取出数据
int cid = rs.getInt("cid");
String cname = rs.getString("cname");
System.out.println(cid + " == " + cname);
}
// 关闭资源
rs.close();
stmt.close();
conn.close();
}
}
注意:
- 如果光标在第一行之前,使用rs.getXXX()获取列值,报错:Before start of result set
- 如果光标在最后一行之后,使用rs.getXXX()获取列值,报错:After end of result set
7.5 小结
其实我们使用JDBC操作数据库的步骤都是固定的。不同的地方是在编写SQL语句
-
注册驱动
Class.forName("com.mysql.jdbc.Driver")
-
获取连接
Connection conn =DriverManager.getConnection(String url,String user,String password)
-
获取到Statement
Statement state = conn.createStatement();
-
使用Statement执行SQL
public boolean execute(String sql):执行任何的sql语句 public int executeUpdate(String sql) :执行 Insert delete update public ResultSet executeQuery(String sql): 执行 select
-
ResultSet处理结果
ResultSet rs = state.executeQuery("select * from category"); while(rs.next()){ 值 = rs.getXxx(列名); 值 = rs.getXxx(列索引); // 索引从1开始 }
-
关闭资源
rs.close(); state.close(); conn.close();
ResultSet如何获取数据?
- 调用next方法, ResultSet内部指针会移动到下一行数据
- 我们可以通过ResultSet得到一行数据 getXxx得到某列数据
8. JDBC事务
之前我们是使用MySQL的命令来操作事务。接下来我们使用JDBC来操作银行转账的事务。
准备数据
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('张三', 1000), ('李四', 1000);
API介绍
Connection
接口中与事务有关的方法
-
void setAutoCommit(boolean autoCommit) throws SQLException; false:开启事务, ture:关闭事务 java-->setAutoCommit(false) <==> sql->start transaction;
-
void commit() throws SQLException; 提交事务 <==> commit;
-
void rollback() throws SQLException; 回滚事务 <==> roallback;
使用步骤
- 注册驱动
- 获取连接
- 开启事务
- 获取到Statement
- 使用Statement执行SQL
- 提交或回滚事务
- 关闭资源
案例代码
public class Demo05 {
public static void main(String[] args) {
Connection conn = null;
try {
// 拿到连接
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
// 开启事务
conn.setAutoCommit(false);
Statement pstmt = conn.createStatement();
// 张三减500
String sql = "UPDATE account SET balance = balance - 500 WHERE id=1;";
pstmt.executeUpdate(sql);
// 模拟异常
// int i = 10 / 0;
// 李四加500
sql = "UPDATE account SET balance = balance + 500 WHERE id=2;";
pstmt.executeUpdate(sql);
pstmt.close();
// 成功,提交事务
System.out.println("成功,提交事务");
conn.commit();
} catch (Exception e) {
// 失败,回滚事务
try {
System.out.println("出了异常,回滚事务");
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
8.1 小结
JDBC中与事务相关的API?Connection
接口中setAutoCommit,commit,rollback
JDBC操作事务的步骤?
- 注册驱动
- 获取连接
- 获取到Statement
- 开启事务
- 使用Statement执行SQL
- 提交或回滚事务
- 关闭资源
8.2 编写JDBC工具类
能够编写JDBC获取连接与关闭连接工具类
讲解
需求: 创建一张员工表,包含id,name,age,address字段.定义添加员工,修改员工,删除员工方法操作数据库。
通过上面案例需求我们会发现每次去执行SQL语句都需要注册驱动,获取连接,得到Statement,以及释放资源。发现很多重复的劳动,我们可以将重复的代码定义到某个类的方法中。直接调用方法,可以简化代码。
那么我们接下来定义一个JDBCUtils
类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中。以后直接调用方法即可。
编写步骤
- 将固定字符串定义为常量
- 在静态代码块中注册驱动(只注册一次)
- 提供一个获取连接的方法
static Connection getConneciton();
- 定义关闭资源的方法
close(AutoCloseable... resource)
案例代码
JDBCUtils.java
import java.io.IOException;
import java.sql.*;
public class JDBCUtils {
// 1.将固定字符串定义为常量
private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql:///day04";
private static final String USER = "root";
private static final String PASSWORD = "root";
// 2.在静态代码块中注册驱动(只注册一次)
// 当这个类加载到内存的时候就走这个静态代码块,再去触发Driver类中的静态代码块,主动注册
static {
try {
Class.forName(DRIVER_CLASS);
} catch (ClassNotFoundException e) {
}
}
// 3.提供一个获取连接的方法static Connection getConneciton();
// 我们面向JDBC编程
public static Connection getConnection() throws SQLException, IOException {
//有两种方式:如下
//第一种方式:
// 可以将用户名【user=root】和密码【password=root】放到配置文件jdbc.properties,
//配置文件可以放到src目录中,用以下加载方式
/* InputStream is = JDBCUtils.class.getResourceAsStream("/jdbc.properties");
Properties pp = new Properties();
pp.load(is);
Connection conn = DriverManager.getConnection(URL, pp);
*/
// 第二种方式:
// 直接使用静态常量定义的用户名和密码
Connection conn = DriverManager.getConnection(URL, USER,PASSWORD);
return conn;
}
//4.定义关闭资源方法
//Connection,Statement,ResultSet 都实现了AutoCloseable接口
public static void close(AutoCloseable... resource) {
for (AutoCloseable r : resource) {
try {
if (r != null) {
r.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Demo06.java
public class Demo06 {
public static void main(String[] args) throws Exception {
createTable();
// addEmployee();
// updateEmployee();
// deleteEmployee();
}
// 删除员工
public static void deleteEmployee() throws Exception {
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
// 删除id为3的员工
String sql = "DELETE FROM employee WHERE id=3;";
int i = stmt.executeUpdate(sql);
System.out.println("影响的行数: " + i);
// stmt.close();
// conn.close();
// JDBCUtils.close(conn, stmt, null);
JDBCUtils.close(conn, stmt);
}
// 修改员工
public static void updateEmployee() throws Exception {
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
// 将id为3的员工姓名改成田七,地址改成天津
String sql = "UPDATE employee SET address='天津', name='田七' WHERE id=3;";
int i = stmt.executeUpdate(sql);
System.out.println("影响的行数: " + i);
// stmt.close();
// conn.close();
// JDBCUtils.close(conn, stmt, null);
JDBCUtils.close(conn, stmt);
}
// 定义添加员工
public static void addEmployee() throws Exception {
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
// 添加4个员工
String sql = "INSERT INTO employee VALUES (NULL, '张三4', 20, '北京'),"
+ " (NULL, '李四4', 21, '南京'),"
+ " (NULL, '王五4', 18, '东京'),"
+ " (NULL, '赵六4', 17, '西安');";
int i = stmt.executeUpdate(sql);
System.out.println("影响的行数: " + i);
// stmt.close();
// conn.close();
// JDBCUtils.close(conn, stmt, null);
JDBCUtils.close(conn, stmt);
}
// 创建表
public static void createTable() throws Exception {
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
String sql = "CREATE TABLE IF NOT EXISTS employee ("
+ " id INT PRIMARY KEY AUTO_INCREMENT,"
+ " name VARCHAR(20) UNIQUE NOT NULL,"
+ " age INT,"
+ " address VARCHAR(50)"
+ ");";
int i = stmt.executeUpdate(sql);
System.out.println("ok");
// stmt.close();
// conn.close();
// JDBCUtils.close(conn, stmt, null);
JDBCUtils.close(conn, stmt);
}
}
9. JDBC实现登录案例
目标
模拟用户输入账号和密码登录网站
案例分析
- 使用数据库保存用户的账号和密码
- 让用户输入账号和密码
- 使用SQL根据用户的账号和密码去数据库查询数据
- 如果查询到数据,说明登录成功
- 如果查询不到数据,说明登录失败
实现步骤
-
创建一个用户表保存用户的账号和密码,并添加一些数据,SQL语句如下:
CREATE TABLE USER ( id INT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(50), PASSWORD VARCHAR(50) ); INSERT INTO USER (NAME, PASSWORD) VALUES('admin', '123'), ('test', '123'), ('gm', '123');
-
编写代码让用户输入账号和密码
public class Demo07 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入账号: "); String name = sc.nextLine(); System.out.println("请输入密码: "); String password = sc.nextLine(); }
-
使用SQL根据用户的账号和密码去数据库查询数据
public class Demo07 { public static void main(String[] args) throws Exception { // 让用户输入账号和密码 Scanner sc = new Scanner(System.in); System.out.println("请输入账号: "); String name = sc.nextLine(); System.out.println("请输入密码: "); String password = sc.nextLine(); // 使用SQL根据用户的账号和密码去数据库查询数据 Connection conn = JDBCUtils.getConnection(); Statement stmt = conn.createStatement(); String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';"; } }
-
如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败
public class Demo07 { public static void main(String[] args) throws Exception { // 让用户输入账号和密码 Scanner sc = new Scanner(System.in); System.out.println("请输入账号: "); String name = sc.nextLine(); System.out.println("请输入密码: "); String password = sc.nextLine(); // 使用SQL根据用户的账号和密码去数据库查询数据 Connection conn = JDBCUtils.getConnection(); Statement stmt = conn.createStatement(); String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';"; // 如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败 ResultSet rs = stmt.executeQuery(sql); if (rs.next()) { //能进来查询到了数据. String name2 = rs.getString("name"); System.out.println("欢迎您," + name2); } else { //查询不到数据,说明登录失败 System.out.println("账号或密码错误..."); } JDBCUtils.close(conn, stmt, rs); } }
小结
登录案例步骤
- 使用数据库保存用户的账号和密码
- 让用户输入账号和密码
- 使用SQL根据用户的账号和密码去数据库查询数据
- 如果查询到数据,说明登录成功
- 如果查询不到数据,说明登录失败