《Java基础入门 极速版》
ch12 JDBC
1. JDBC简介
JDBC概念
- JDBC就是使用Java语言操作关系型数据库的一套API
- 全称: (Java DataBase Connectivity)Java数据库连接
JDBC本质
- 官方(sun公司) 定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JDBC) 编程,真正执行的代码是驱动jar包中的实现类
JDBC好处:
- 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
- 可随时替换底层数据库,访问数据库的Java代码基本不变
2. JDBC快速入门
0. 创建工程,导入驱动jar包
mysql-connector-java-5.1.48.jar
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接 ,
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义SQL语询
String sql =“update..." ;
// 4.获取执行SQL对象
Statement stmt = conn.createStatement();
// 5.执行SQL
stmt.executeUpdate(sq);
// 6.处理返回结果
// 7.释放资源
【例题1】JDBC快速入门(七步操作数据库)
package cn.ls.ch12;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.DriverManager;
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注册驱动
// Class.forName("com.mysql.jdbc.Driver");
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
String url = "jdbc:mysql://81.70.247.52:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "******";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL
String sql = "update 账户表 set 金额 = 2000 where id = 2";
//4.获取执行sqL的对象Statement
Statement stmt = conn.createStatement();
//5.执行sqL
int count = stmt.executeUpdate(sql);//受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
create table 账户表( id int, 账户名 varchar(10), 金额 int);
insert 账户表 values (1,'柳帅',10),(2,'李同学',20);
select * from 账户表;
update 账户表 set 金额 = 2000 where id = 2;
3. JDBC API详解
- DriverManager
- Connection
- Statement
- ResultSet
- PreparedStatement
(1) DriverManager(驱动管理类)
DriverManager作用:
1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
- 查看Driver类源码
- 提示
- MySQL 5之后的驱动包,可以省略注册驱动的步骤
- 自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
2.获取数据库连接
static Connection getConnection(String url, String user, String password)
- url: 连接路径
语法:
jdbc:mysq://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...
示例:jdbc:mysal://127.0.0. 1:3306/db1
细节:- 如果连接的是本机mysq|服务器,并且mysql服务默认端口是3306,则ur可以简写为:
jdbc:mysq://数据库名称?参数键值对
- 配置
useSSL=false
参数,禁用安全连接方式,解决警告提示 WARN: Establishing SSL connection without server's identity verification is not reCommended .
- 如果连接的是本机mysq|服务器,并且mysql服务默认端口是3306,则ur可以简写为:
- user: 用户名
- password: 密码
【例题2】DriverManager举例
package cn.ls.ch12;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo_1DriverManager {
public static void main(String[] args) throws Exception {
//1.注册驱动 可以省略 下一句
// Class.forName("com.mysql.jdbc.Driver");
// Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接:如果连接的是本机mysqL并且端口是默认的3306可以简化书泻
//String url = "jdbc:mysql:///db1";
String url = "jdbc:mysql://81.70.247.52:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "*******";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL
String sql = "update 账户表 set 金额 = 30 where id = 2";
//4.获取执行sqL的对象Statement
Statement stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
(2) Connection(数据库连接对象)
Connection作用:
1.获取执行SQL的对象
- 普通执行SQL对象
Statement createStatement();
- 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql);
- 执行存储过程的对象
CallableStatement prepareCall(sql);
2.事务管理
MySQL事务管理
- 开启事务: BEGIN; / START TRANSACTION;
- 提交事务: COMMIT;
- 回滚事务: ROLLBACK; MySQL默认自动提交事务
JDBC事务管理: Connection接口中定义了3个对应的方法
- 开启事务: setAutoCommit(boolean autoCommit):
- true为自动提交事务;
- false为手动提交事务,即为开启事务
- 提交事务: commit()
- 回滚事务: rollback()
【例题3】Connection举例
package cn.ls.ch12;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo_2Connection {
public static void main(String[] args) throws Exception {
//1.注册驱动
// Class.forName("com.mysql.jdbc.Driver"); //mysql 5.x 驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
String url = "jdbc:mysql://IP地址:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "密码";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL
String sql1 = "update 账户表 set 金额 = 3001 where id = 1";
String sql2 = "update 账户表 set 金额 = 3000 where id = 2";
//4.获取执行sqL的对象Statement
Statement stmt = conn.createStatement();
try {
//开启事务
conn.setAutoCommit(false);
//5.执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6.处理结果
System.out.println(count1);
// int i = 2/0;
//5.执行sql
int count2 = stmt.executeUpdate(sql2);//受影响的行数
//6.处理结果
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception throwables) {
//回滚事务
conn.rollback();
throwables.printStackTrace();
}
//7.释放资源
stmt.close();
conn.close();
}
}
(3) Statement语句对象
Statement作用:
1.执行SQL语句
int executeUpdate(sql): 执行DML、DDL语句
➢返回值: (1) DML语句影响的行数 (2) DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql): 执行DQL语句
➢返回值: ResultSet 结果集对象
【例题4】Statement举例:DML和DDL
package cn.ls.ch12;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import org.junit.Test;
/**
* JDBC API 详解:Statement
*/
public class JDBCDemo_3Statement {
/**
* 执行DML语句
* @throws Exception
*/
@Test
public void testDML() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://81.70.247.52:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "*******";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "update 账户表 set 金额 = 3033 where id = 1";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句,受影响的行数
//6. 处理结果
System.out.println(count);
if(count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
//7. 释放资源
stmt.close();
conn.close();
}
/**
* 执行DDL语句
* @throws Exception
*/
@Test
public void testDDL() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://81.70.247.52:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "*********";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
//String sql = "create database db2";
String sql = "drop database db2";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql);//执行完DDL语句,可能是0
//6. 处理结果
System.out.println(count);
if(count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
//7. 释放资源
stmt.close();
conn.close();
}
}
(4) Statement结果集
- ResultSet(结果集对象)作用: 封装了DQL查询语句的结果
ResultSet stmt.executeQuery(sq) //执行DQL语句,返回ResultSet对象
- 获取查询结果
boolean next() // (1) 将光标从当前位置向前移动-行(2) 判断当前行是否为有效行 //➢返回值: // true:有效行,当前行有数据 // false:无效行,当前行没有数据 XXX getXxx(参数) // 获取数据 // XXX:数据类型;如: int getlnt(参数) ; String getString(参数) // ➢参数: // int:列的编号,从1开始 // String:列的名称
- 使用步骤
// 1. 游标向下移动一行,并判断该行否有数据: next() // 2. 获取数据: getXxx(参数) // 循环判断游标是否是最后一行末尾 while(rs.next()){ //获取数据 rs.getXxx(参数); }
【例题5】ResultSet测试和ResultSet案例
ResultSet案例:查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
package cn.ls.ch12.pojo;
public class Account {
private int id;
private String 账户名;
private double 金额;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String get账户名() {
return 账户名;
}
public void set账户名(String 账户名) {
this.账户名 = 账户名;
}
public double get金额() {
return 金额;
}
public void set金额(double 金额) {
this.金额 = 金额;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", 账户名='" + 账户名 + '\'' +
", 金额=" + 金额 +
'}';
}
}
package cn.ls.ch12;
import cn.ls.ch12.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* JDBC API 详解:ResultSet
*/
public class JDBCDemo_4ResultSet {
/**
* 执行DQL
* @throws Exception
*/
@Test
public void testResultSet() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://IP地址:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "密码";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "select * from 账户表";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果, 遍历rs中的所有数据
// 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
//6.2 获取数据 getXxx()
int id = rs.getInt(1);
String name = rs.getString(2);
double money = rs.getDouble(3);
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------");
}
// 6.1 光标向下移动一行,并且判断当前行是否有数据
System.out.println();
rs = stmt.executeQuery(sql);
while (rs.next()){
//6.2 获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("账户名");
double money = rs.getDouble("金额");
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
/**
* 查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
* 1. 定义实体类Account
* 2. 查询数据,封装到Account对象中
* 3. 将Account对象存入ArrayList集合中
*
* @throws Exception
*/
@Test
public void testResultSet2() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://IP地址:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "密码";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "select * from 账户表";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 创建集合
List<Account> list = new ArrayList<>();
// 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
Account account = new Account();
//6.2 获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("账户名");
double money = rs.getDouble("金额");
//赋值
account.setId(id);
account.setName(name);
account.setMoney(money);
// 存入集合
list.add(account);
}
System.out.println(list);
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
(5) PreparedStatement
- PreparedStatement作用: 预编译SQL语句并执行----预防SQL注入问题
- SQL注入: 通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
-- 删除tb user表
DROP TABLE IF EXISTS tb_user;
-- 创建tb user表
CREATE TABLE tb_user (
id int,
username VARCHAR(20),
password VARCHAR(32)
) ;
-- 添加数据
INSERT INTO tb_user VALUES(1, 'zhangsan' , '123'), (2, 'lisi', '234');
SELECT * from tb_user;
【例题6】SQL注入
package cn.ls.ch12;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 用户登录 SQL 注入
*/
public class JDBCDemo_5UserLogin {
@Test
public void testLogin() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://IP地址:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "密码";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
//String pwd = "123";
String pwd = "fhsjkfhdsk";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
/**
* 演示SQL注入
* @throws Exception
*/
@Test
public void testLogin_Inject() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql://IP地址:3306/ch12_ls?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false";
String username = "root";
String password = "密码";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "hfkjsfhskj";
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
System.out.println(sql);
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
12.4 数据库连接池
【例题6】语句
package cn.ls.ch03;
}
}