jdbc详解

jdbc概念

jdbc(Java Database Connectivity),是一种用于执行SQL语句的Java API,也就是java操作数据库,其本质是官方定义的一套操作所有关系型数据库的接口。

常见的关系数据库有Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL等,而jdbc就是为这些关系型数据库提供统一访问,数据库厂商自己写的实现类,封装成数据库驱动jar包。

真正执行的代码是驱动jar包中的实现类,如下形式使用

1
2
3
4
5
//Person接口、Worker类
//父类引用指向子类对象
Person p=new Worker();
//多态调用
p.eat();

jdbc快速入门

jdbc快速入门

步骤:

  1. 导入驱动jar包
  2. 注册驱动
  3. 获取数据库连接对象 Connection
  4. 定义sql
  5. 获取执行sql语句的对象 Statement
  6. 执行sql,接收返回的结果
  7. 处理结果
  8. 释放资源

详解各个对象

1. DriverManager:驱动管理对象

功能

① 注册驱动

写代码时使用:

1
2
//获取Driver类对象,即将类字节码文件加载进内存
Class.forName("com.mysql.jdbc.Driver");

查看源码发现了静态代码块

注册驱动是为了告诉程序该使用哪一个数据库驱动jar

注意:mysql5之后的驱动jar包可以省略注册驱动的步骤

② 获取数据库连接

方法:
修饰与类型 方法描述
static Connection getConnection(String url, String user, String password) 尝试建立与给定数据库URL的连接
参数:
  • url : 指定连接的路径(jdbc:mysql://ip地址:端口号/数据库名称
  • user : 用户名
  • password : 密码

小知识:如果连接的是本机mysql服务器,且mysql服务默认端口是3306,则url可简写为:jdbc:mysql:///数据库名称

2. Connection:数据库连接对象

功能

① 获取sql对象

1
2
statement createStatement()
preparedStatement prepareStatement(String sql)

② 管理事务

  • 开启事物

    setAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事物

  • 提交事物

    commit()

  • 回滚事物

    rollback()

3. Statement:执行sql的对象

常用方法

  • ① boolean execute(String sql): 可以执行任意的sql(了解)
  • ② int executeUpdate(String sql):执行DML(insert、update、delete)语句,返回值是影响的行数,可判断DML是否执行成功
  • ③ Resultset executeQuery(String sql):执行DQL(select)语句

练习

给student数据库的admin表添加一条数据

同样的方法来修改数据

4. ResultSet:结果集对象,封装查询结果

使用步骤:

  1. 游标向下移动一行
  2. 判断是否有数据
  3. 获取数据
1
2
3
4
5
6
7
8
9
10
11
12
Class.forName("com.mysql.jdbc.Driver");
String sql="select * from admin;";
conn = DriverManager.getConnection("jdbc:mysql:///student", "root", "123");
stat = conn.createStatement();
rs = stat.executeQuery(sql);
//获取数据
while(rs.next()){
int id =rs.getInt("id");
String name = rs.getString("name");
String password = rs.getString("password");
System.out.println(id+'/'+name+'/'+password);
}

练习一

查询stu表中的数据,将其封装为对象,然后打印

使用jdbc工具类改进
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
//jdbc工具类
public class jdbcUtils {
//作用域提升,只有静态的变量才能被静态代码块和静态方法访问
private static String url;
private static String user;
private static String password;
private static String driver;

//是用静态代码块读取文件
static{
try {
//1.创建Properties集合类
//获取src路径下文件的方式ClassLoader类加载器
ClassLoader cl= jdbcUtils.class.getClassLoader();
URL res=cl.getResource("jdbc.properties");
String path=res.getPath();
//2.加载文件
Properties pro=new Properties();
pro.load(new FileReader(path));
//3.获取数据赋值
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");
//4.注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}

public static void close(ResultSet rs,Statement stat, Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

if(stat!=null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

这样可以避免代码冗余

练习二

通过连接数据库查询用户输入的账号密码是否正确

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
public class jdbcDemo6 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
boolean flag = new jdbcDemo6().login(username, password);
if (flag){
System.out.println("登录成功");
}else{
System.out.println("账号或密码错误!");
}
}

//登录方法
public boolean login(String username,String password){
Connection conn =null;
Statement stat =null;
ResultSet rs =null;

if(username==null||password==null){
return false;
}
//连接数据库判断是否登陆成功
//1.获取连接
try {
conn = jdbcUtils.getConnection();
//2.定义sql
String sql="select * from admin where name='"+username+"' and password='"+password+"';";
//3.获取执行sql的对象
stat = conn.createStatement();
//4.执行sql
rs = stat.executeQuery(sql);
//判断,如果有下一行,则返回true
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
jdbcUtils.close(rs,stat,conn);
}
return false;
}
}

5. PreparedStatement:执行sql的对象

上面的代码有个致命错误,按如图输入竟然会登陆成功
,这是由于SQL注入引起的,在拼接sql时有一些sql的特殊关键字参与字符串的拼接,而这样会造成安全性问题。

所以上面代码实际执行的sql是

1
2
-- 返回true
select * from admin where name='4545' and password='a' or 'a'='a'

为了解决sql注入问题:使用PreparedStatement对象来解决

该接口继承自Statement接口,表示预编译的SQL语句的对象

预编译的SQL: 参数使用 ? 作为占位符,于是将sql语句改为:

1
select * from admin where name=? and password=?;

接着获取执行sql语句的对象

PreparedStatement Connection.prepareStatement(String sql)

给 ? 赋值:

1
2
3
setXXX(参数1,参数2)
//参数1:?的位置编号从1开始
//参数2:?的值

然后执行sql,接受返回结果,不需要传递sql语句

效果如图:

JDBC控制事务

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
  2. 操作:
  • 开启事务
  • 提交事务
  • 回滚事务

3.使用Connection对象来管理事务

  • 开启事物:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务(在执行sql之前开启事务
  • 提交事物:commit() (当所有sql都执行完提交事务)
  • 回滚事务:rollback() (在catch中回滚事务

来看一个例子:

手动制造异常

需使用控制事务来解决,一旦出现异常就会回滚到开启事务状态

请我喝杯咖啡吧~

支付宝
微信