浅尝JDBC

JDBC简介

JDBC定义:

简单地说,JDBC就是为多种关系数据库提供统一访问同时也是程序与数据库连接的一个中间件,起着桥梁的作用。

客户端连接服务端

无jdbc

  • 没有jdbc的时候,数据库有自己的连接驱动的方式
    在这里插入图片描述
    缺点:
    1.不知道不同数据库的解析方式和操作方式
    2.代码量大,比较繁琐后期维护麻烦
    3.由于解析方式不同和操作方式不同,每个数据库都要协一套代码
    4.数据库与数据库之间的切换比较麻烦

有jdbc

  • 使用jdbc的时候
    在这里插入图片描述
    我们只需要编写一套程序可以连接不同的数据库而且数据库之间切换比较方便

jdbc常见的类和接口

一个类:
DriverManager类:驱动管理器类 专门注册驱动的
三个接口:

名字描述和作用
Connection接口连接对象 就是建立与数据库之间的连接
Statement接口SQl编译器 像数据库发送并执行sql语句的
ResultSet接口查询结果集 执行查询操作的时候返回的结果集行进行处理

入门案例

接下来写一个简单地入门案例
使用jdbc操作数据库有六步,需要记住

步骤描述
1注册驱动
2获取连接对象
3创建执行sql语句的连接对象
4执行sql语句
5处理结果集
6释放资源

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) throws Exception {
//1.注册驱动 里面放mysql驱动的全限定路径
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象 用的DriverManager类
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "123456");
// System.out.println(conn);//com.mysql.jdbc.JDBC4Connection@377dca04
//3.创建执行sql语句的连接对象
Statement st = conn.createStatement();
//4.执行sql语句
String sql = "select * from user";
ResultSet rs = st.executeQuery(sql);
//5.处理结果集
while (rs.next()) {
String username = rs.getString("username");
System.out.println(username);
}
//6.释放资源
rs.close();
st.close();
conn.close();

}

jdbc实现增删改查

其中增删改使用的方法是executeUpdate,查询使用的方法是executeQuery

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//增加
@Test
public void addUSer() throws Exception {
//6步
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "123456");
//创建执行sql语句连接对象
Statement st = conn.createStatement();
//执行sql语句
String sql = "insert into user values (null,'小李','123')";
//因为是控制的行数,所以返回的是int类型
int i = st.executeUpdate(sql);
//判断
if (i>0) {
//更新成功
System.out.println("成功添加了"+i+"行数据");
}else {
System.out.println("添加失败");
}

//释放资源
st.close();
conn.close();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//删除
@Test
public void deleteByUid() throws Exception {
//6步
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "123456");
//创建执行sql语句连接对象
Statement st = conn.createStatement();
//执行sql语句
String sql = "delete from user where uid = 4";
//因为是控制的行数,所以返回的是int类型
int i = st.executeUpdate(sql);
//判断
if (i>0) {
//更新成功
System.out.println("成功删除了"+i+"行数据");
}else {
System.out.println("删除失败");
}

//释放资源
st.close();
conn.close();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//修改
@Test
public void updateByUid() throws Exception {
//6步
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "123456");
//创建执行sql语句连接对象
Statement st = conn.createStatement();
//执行sql语句
String sql = "update user set username = '小王' where uid = 3";
//因为是控制的行数,所以返回的是int类型
int i = st.executeUpdate(sql);
//判断
if (i>0) {
//更新成功
System.out.println("成功修改了"+i+"行数据");
}else {
System.out.println("修改失败");
}

//释放资源
st.close();
conn.close();
}

查询先创建一个实体类 User 和表名一样,而且查询的结果需要放在一个集合当中进行遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.ujiuye.pojo;
//类名和表名一样
public class User {
private int uid;
private String username;
private String password;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + "]";
}
public User(int uid, String username, String password) {
super();
this.uid = uid;
this.username = username;
this.password = password;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//查询
@Test
public void findByUid() throws Exception {
//6步
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//创建连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "123456");
//创建执行sql语句连接对象
Statement st = conn.createStatement();
//执行sql语句
String sql = "select * from user";
//因为是控制的行数,所以返回的是int类型
ResultSet rs = st.executeQuery(sql);
//创建集合
ArrayList<User> list = new ArrayList<User>();
//处理结果集
while (rs.next()) {
int uid = rs.getInt("uid");
String username = rs.getString("username");
String password = rs.getString("password");
User user = new User(uid, username, password);
list.add(user);
}
for (User user : list) {
System.out.println(user);
}

//释放资源
rs.close();
st.close();
conn.close();
}

sql注入问题

在查询的时候使用createStatement来执行sql语句的连接对象的时候就会出现sql注入问题
通过一个案例来引出sql注入问题
先对jdbc重复要写的步骤进行抽取,抽取为JDBCUtils
其中rs, psvm, conn是查询,执行sql语句和获取sql连接对象,如果没有某个值就用null代替

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.ujiuye.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCUtils {

static {
//注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

//创建连接对象
public static Connection getConnection() {
try {
Connection conn = DriverManager.getConnection("jdbc:mysql:///day08_jdbc", "root", "123456");
return conn;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

//释放资源
public static void closeAll(ResultSet rs, Statement st, Connection conn) {
//判断
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(st != null) {
try {
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//释放资源
public static void closeAll(ResultSet rs, PreparedStatement psvm, Connection conn) {
//判断
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(psvm != null) {
try {
psvm.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

接着写主要逻辑内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) throws Exception {
//第一步:输入用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();

//第二步:和数据库做对比
Connection conn = JDBCUtils.getConnection();
Statement cs = conn.createStatement();
ResultSet rs = cs.executeQuery("select * from user where username = '"+username+"' and password = '"+password+"' ");
if (rs.next()) {
System.out.println("欢迎:"+ rs.getString("username"));
}else {
System.out.println("账号或者密码错误");
}
}

在以上案例当中,如果正确输入用户名,但是在输入密码的时候后面跟上'or' 1=1就会导致登录也会成功,这就和我们预期的效果不一样了,这就称之为sql注入问题
为什么会出现sql注入问题
当我们使用statement接口时, 会将控制台输入的字符串与sql语句进行拼接, 拼接时把字符串中的or当做了逻辑运算符进行处理, 此时, or后边的1=1是恒成立的, 所以就失去了账号和密码登录的功能, 无论你的账号和密码怎么输入, 都是可以正常登录。
解决SQL注入问题:
需要将statement接口更换为preparedstatement接口。因为用preparedstatement会将sql语句预编译,所以就不会有or的问题。
preparedstatement的时候直接在执行sql语句的连接对象的时候就把sql语句写了,并且用?占位,然后再用set方法进行赋值,1代表第一个?,2代表第二个?,然后执行executeQuery方法进行查询,获取的时候用next的方法进行判断,如有用get方法获取到并输出,并且next就会去判断下一个位置有没有值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	public static void main(String[] args) throws Exception {
//第一步:输入用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();

//第二步:和数据库做对比
Connection conn = JDBCUtils.getConnection();
// Statement cs = conn.createStatement();
PreparedStatement psvm = conn.prepareStatement("select * from user where username = ? and password = ? ");
//设置参数
psvm.setString(1, username);
psvm.setString(2, password);
// ResultSet rs = cs.executeQuery("select * from user where username = '"+username+"' and password = '"+password+"' ");
ResultSet rs = psvm.executeQuery();
if (rs.next()) {
System.out.println("欢迎:"+ rs.getString("username"));
}else {
System.out.println("账号或者密码错误");
}
JDBCUtils.closeAll(rs, psvm, conn);
}

PreparedStatement常见方法的使用

方法描述
setInt(int index,int value)为?占位符,赋予int值
setString(int index,String value)为?占位符,赋予String值
executeQuery()执行查询的SQL语句
executeUpdate()执行更新的SQL语句。

PreparedStatement的增删改查操作

  • 增加一条数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void addUser() throws Exception {
//注册驱动和获取连接
Connection conn = JDBCUtils.getConnection();
String sql = "insert into user values(?,?,?)";
//获取预处理对象
PreparedStatement psvm = conn.prepareStatement(sql);
//设置参数
psvm.setString(1, null);
psvm.setString(2, "热巴");
psvm.setString(3, "123");
//执行
int i = psvm.executeUpdate();
//判断
if(i > 0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}
//释放资源
JDBCUtils.closeAll(null, psvm, conn);
}
  • 新增多条
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//新增多条
@Test
public void addUsers2() throws Exception {
Connection conn = JDBCUtils.getConnection();
String sql = "insert into user values(?,?,?)";
PreparedStatement psvm = conn.prepareStatement(sql);
//设置参数
psvm.setString(1, null);
psvm.setString(2, "小短腿");
psvm.setString(3, "123");
psvm.addBatch();

//设置参数
psvm.setString(1, null);
psvm.setString(2, "小乔");
psvm.setString(3, "123");
psvm.addBatch();

//批量执行
psvm.executeBatch();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//修改
@Test
public void updateUserByUid() throws Exception {
Connection conn = JDBCUtils.getConnection();
String sql = "update user set username = ? where uid = ?";
PreparedStatement psvm = conn.prepareStatement(sql);
//设置参数
psvm.setString(1, "houyi");
psvm.setInt(2, 6);
//执行
int i = psvm.executeUpdate();
//判断
if(i > 0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}
//释放资源
JDBCUtils.closeAll(null, psvm, conn);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//删除
@Test
public void deleteUserByUid() throws Exception {
Connection conn = JDBCUtils.getConnection();
String sql = "delete from user where uid = ?";
PreparedStatement psvm = conn.prepareStatement(sql);
//设置参数
psvm.setInt(1, 5);
//执行
int i = psvm.executeUpdate();
//判断
if(i > 0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}
//释放资源
JDBCUtils.closeAll(null, psvm, conn);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//查询
@Test
public void findUsers() throws Exception {
Connection conn = JDBCUtils.getConnection();
String sql = "select * from user";
PreparedStatement psvm = conn.prepareStatement(sql);
//设置参数
//执行
ResultSet rs = psvm.executeQuery();
while(rs.next()) {
int uid = rs.getInt("uid");
String username = rs.getString("username");
String password = rs.getString("password");
System.out.println(uid + "\t" + username + "\t" + password);
}
//释放资源
JDBCUtils.closeAll(rs, psvm, conn);
}

需要的jar包

链接:https://pan.baidu.com/s/1_nqg99Fb83FA1KaFXsip_g
提取码:1314
复制这段内容后打开百度网盘手机App,操作更方便哦

-------------本文结束感谢您的阅读-------------