JDBC相关知识

本文全部内容均来自黑马程序员的资料,本文仅对其总结,很多复杂难懂内容跳过。

1. JDBC介绍

1.1 JDBC概念

全称( Java database connectivity)Java数据库连接

JDBC 是使用Java语言操作关系型数据库的一套API

同一套Java代码无法操作不同的关系型数据库,因为每一个关系型数据库的底层实现不同,sun公司制定了一套操作数据库的标准接口(JDBC),JDBC中定义了所有操作关系型数据库的规则,接口无法使用,需要使用接口的实现类,这套实现类(称之为:驱动),由各自的数据库厂商给出。

1.2 JDBC本质

官方定义的一套操作所有关系型数据库的规则,即接口。

各个数据库厂商去实现这套接口,提供数据库驱动jar包

我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中德实现类

1.3 JDBC好处

各个数据库厂商实现同一个相同的接口,客户实际使用时调用这套接口(JDBC)操作不同的数据库。

可随时替换底层数据库,且访问数据库的Java代码不变。

客户编写操作数据库的代码只需要面向这套接口(JDBC),操作哪个关系型数据库就导入对应的数据库的驱动包,如操作MySQL数据库就需要在项目中导入MySQL数据库的驱动包。

2. JDBC快速入门

Java操作数据库的流程是:

第一步:编写Java代码

第二部:Java代码将sql发送到MySQL服务端

第三步: MySQL服务端接受sql语句并执行

第四步:MySQL服务端将sql语句执行结果返回给Java代码

2.1 编写代码步骤

  1. 创建工程,导入驱动jar包

  2. 注册驱动(以MySQL为例),目的是将数据库驱动程序加载到JVM中,旧版本JDBC需要手动注册驱动,新版本驱动会自动注册,以下为手动注册代码,现在在编程是可以不用写以下代码,因为会自动注册

    1
    Class.forname("com.mysql.jdbc.Driver");
  3. 获取连接,Java代码需要发送sql给MySQL服务端,就需要先建立连接

    1
    Connection conn = DriverManage.getConnection(url, username, password);
  4. 定义sql语句

    1
    String sql = "update...";
  5. 获取执行sql的对象,执行sql语句需要sql执行对象,就是Statement对象

    1
    Statement stmt = coon.createStatement();
  6. 执行SQL

    1
    stmt.executeUpdate(sql);
  7. 处理返回结果

  8. 释放资源

2.2 完整代码

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
/**
* JDBC快速入门
*/
public class JDBCDemo {
public static void main(String[] args) {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义SQL
String sql = "update account set money = 2000 where id = 1";
// 4.获取执行SQL对象 Statement
Statement stmt = conn.createStatement();
// 5.执行SQL
int count = stmt.executeUpdate(sql);
// 6.处理结果
...
System.out.println(count);
// 7.释放资源
stmt.close();
coon.close();
}
}

3. JDBC API详解

3.1 DrvierManage

  • 获取数据库连接
static Connection getConnection(String url, String username, String password) 尝试与给定数据库URL连接

参数说明:

  • url:连接路径

语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2。

示例:jdbc:mysql://127.0.0.1:3306/db1

细节:

  • 如果连接的是本机MySQL服务器,并且MySQL服务器默认端口是3306,则url可简写为:jdbc:mysql:///数据库名称?参数键值对
  • 配置useSSL=false参数,禁用安全连接方式,解决警告提示
  • user:用户名
  • password: 密码

3.2 Connection

Connection(数据库连接对象)作用:

  • 获取执行SQL对象
  • 管理事务

3.2.1 获取SQL执行对象

  • 普通执行SQL对象
1
Statement createStatement()
  • 预编译SQL的执行SQL对象,可防止SQL注入
1
PreparedStatement prepareStatement(sql)

3.2.2 事务管理

MySQL事务管理的操作:

开启事务:BEGIN; 或者START TRANSACTION;

提交事务:COMMIT;

回滚事务:ROLLBACK;

Connection接口中定义了三个对应的方法:

  • 开启事务

    void setAutoCommit(boolean autoCommit)

    参数autoCommit表示是否自动提交事务,true表示自动提交,false表示手动提交。而开启事务需要将该参数设为false。

  • 提交事务

    void commit()
  • 回滚事务

    void rollback()

具体代码如下:

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
/**
* JDBC API详解: Connection
*/
public class JDBCDemo {
public static void main(String[] args) {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接,如果连接的是本机MySQL且端口是3306可以简化书写
// String url = "jdbc:mysql://127.0.0.1:3306/db1";
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义SQL
String sql1 = "update account set money = 3000 where id = 1";
String sql2 = "update account set money = 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 = 3/0;
// 5.执行SQL
int count2 = stmt.executeUpdate(sql2);//受影响的行数
// 6.处理结果
System.out.println(count2);
// ======提交事务======
//程序运行到此处,说明没有出现任何问题,则需要提交事务
coon.commit();
}catch(Exception e) {
// ======回滚事务======
//程序在出现异常时会执行到这个地方,此时就需要回滚事务
conn.rollback();
e.printStackTrace();
}

// 7.释放资源
stmt.close();
coon.close();
}
}

3.3 Statement

Statement对象的作用是用来执行SQL语句,针对不同的SQL语句使用的方法也不同。

  • 执行DDL、DML语句

    开发中很少使用Java代码操作DDL语句

int executeUpdate(String sql) 执行给定的SQL语句,可能是INSERT,UPDATE或DELETE语句
  • 执行DQL语句

    ResultSet executeQuery(String sql) 执行给定的SQL语句,返回单个ResultSet对象

3.4 ResultSet

3.4.1 介绍

ResultSet(结果集对象)封装了SQL查询语句的结果。对应执行DQL语句的方法如下:

1
ResultSet executeQuery(sql): 执行DQL语句,返回ResultSet对象

ResultSet对象提供了操作查询结果的方法,如下:

boolean next()

  • 将光标从当前位置向后移动一行
  • 判断当前行是否为有效行

方法返回值说明:

  • true:有效行,当前行有数据
  • false:无效行,当前行没有数据

xxx getXxx(参数):获取数据

  • xxx:数据类型;如:int getInt(参数);String getString(参数);
  • 参数
    • int类型的参数:列的名称(行号也可以)
    • String类型的参数:列的名称(行号也可以)

如下为执行SQL语句后的结果:

如图,一开始光标指在第一行前,如图所示红色箭头指向于表头行。当我们调用了next()方法后,光标就下移到第一行,并且方法返回true,此时可通过getInt("id")获取当前行id字段的值,也可通过getString("name")获取当前行的name字段的值。如果想获取下一行的数据,继续调用next()方法。

3.4.2 代码实现

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
/**
* 执行DQL
* @throws Exception
*/
@Test
public void testResultSet() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "select * from account";
//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 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
//6.2 获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");

System.out.println(id);
System.out.println(name);
System.out.println(money);

System.out.println("--------------");
}

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

3.5 PreparedStatement

  • PreparedStatement作用:

    预编译SQL语句并执行,预防SQL注入问题

3.5.1 SQL注入

SQL注入是通过操作输入来修改事先定义好的SQL语句,达到执行代码来攻击服务器的手段,具体详情感觉与Java学习关系不大,我也不太懂,就不详细介绍了。

3.5.2 PreparedStatement概述

  • 获取PreparedStatement对象

    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
      //SQL语句中的参数值,使用 ? 占位符替代
    String sql = "select * from user where username = ? and password = ?";

    //通过Connection对象获取,并传入对应的SQL语句,这里比以前的createStatement()方法参数传递提前了
    PreparedStatement pstmt = coon.preparedStatement(sql);

    - 设置参数值

    上面的SQL语句中参数使用 `?` 进行占位,在此之前要设置这些 `?` 的值

    > 方法:setXxx(参数1, 参数2)
    >
    > - Xxx:表示数据类型,例如setInt(参数1, 参数2)
    > - 参数1:占位符 `?` 的位置编号,代表在SQL语句中第几个占位符,从1开始
    > - 参数2:占位符`?`的值

    - 执行SQL语句

    > executeUpdate(); //执行DDL语句和DML语句
    >
    > executeQuery(); //执行DQL语句
    >
    > - 注意:调用这两个方法时不需要传递SQL语句,在获取SQL语句执行对象PreparedStatement时已经对SQL语句进行预编译了。

    - 开启预编译功能

    > 在代码中编写url时需要加上以下参数:
    >
    > useServerPrepStmts=true

    ### 3.5.3 PreparedStatement的使用

    ```java
    /**
    * JDBC API详解: PreparedStatement
    */
    public class JDBCDemo {
    public static void main(String[] args) {
    // 1.注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 2.获取连接,如果连接的是本机MySQL且端口是3306可以简化书写
    // String url = "jdbc:mysql://127.0.0.1:3306/db1";
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);
    //占位符 ? 的值
    String name = "zhangsan";
    String pwd = "123";


    //定义SQL
    String sql = "select * from tb_user where username = ? and password = ?";

    //获取PreparedStatement对象
    PreparedStatement pstmt = conn.prepareStatement(sql);

    //设置占位符 ? 的值
    pstmt.setString(1, name);
    pstmt.setString(2, pwd);

    //执行SQL
    ResultSet rs = pstmt.executeQuery();

    //判断是否登录成功
    if (rs.next()) {
    System.out.println("登录成功");
    }else {
    System.out.println("登录失败");
    }
    // 7.释放资源
    rs.close();
    pstmt.close();
    coon.close();
    }
    }

最后,PreparedStatement原理较为复杂,读者也不太懂。

4. 数据库连接池

4.1 数据库连接池介绍

  • 数据库连接池是一个容器,负责分配、管理数据库连接(Connection)
  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立新连接

之前代码中使用连接时每一个使用都创建一个Connection对象,使用完后将其销毁。这样重复创建销毁的过程时特别耗费计算机的性能和时间。

但在使用数据库连接池后,可以实现对Connection对象的复用。

连接池是在一开始就创建好了一些连接对象(Connection)存储起来,用户需要连接数据库时,不需要自己创建连接,只需从连接池中获取一个连接进行使用,使用完毕后在将连接对象(Connection)归还给连接池,这样可以起到资源复用的作用,也节省了频繁创建连接、销毁连接所花费的时间,从而提升了响应速度。

4.2 数据库连接池实现

  • 标准接口:DataSource

    官方提供的数据库连接池标准接口,由第三方实现此接口,该接口提供过了获取连接的功能:

    1
    Connection getConnection()

    使用数据库连接池就不需要通过DriverManager对象获取Connection对象,而是通过连接池DataSource获取Connection对象。

  • 常用数据库连接池: Druid(德鲁伊)

    • Druid连接池是阿里巴巴开源的数据库连接池项目

4.3 Druid使用

  • 导入jar包 例如druid-1.1.12.jar //将druid的jar包放在项目下的lib下并添加为库文件
  • 定义配置文件
  • 加载配置文件
  • 获取数据库连接池对象
  • 获取连接

编写名为druid.properties的配置文件,放在src下的目录中

druid.properties的配置文件内容如下:

1
2
3
4
5
6
7
8
9
10
driverClassName=com.mysql.jdbc.Driver # MySQL JDBC驱动程序的类名,用于连接到MySQL数据库
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true # 连接到名为db1的MySQL数据库的URL,不使用SSL加密连接,并开启预处理语句功能
username=root # 连接到MySQL数据库所使用的用户名
password=1234 # 连接到MySQL数据库所使用的密码
# 初始化连接数量,设置为5表示在连接池启动时创建5个连接
initialSize=5
# 最大连接数,设置为10表示连接池中最多同时存在10个连接
maxActive=10
# 最大等待时间,设置为3000表示当所有连接都被占用时,新的请求最多等待3秒钟
maxWait=3000

使用druid的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Druid数据库连接池演示
*/
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//即druid配置文件在项目中的位置
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接Connection
Connection connection = dataSource.getConnection();

...获取到连接后继续进行其它操作
}
}

第一次写这么长的文章,虽然都是抄的黑马,仍希望这是自己好的开始。