JDBC介绍

  • JDBC(Java Data Base Connectivity,java数据库连接)是Java访问数据库的标准规范,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成

  • 驱动则是数据库厂商对jdbc接口的具体实现,开发人员只需要学会jdbc接口的调用,导入相应驱动实现就可以实现对不同数据库的操作

  • JDBC的作用:JDBC是用于执行SQL语句的Java API(Java语言通过JDBC可以操作数据库)。

由来

  • 直接写代码操作数据库会产生以下问题:

    • 不同数据库的操作方式和解析方式不同,每个数据库都要写一套代码
    • 不同数据库相互切换麻烦。
  • JDBC规范定义接口,具体的实现由各大数据库厂商来实现

  • JDBC是Java访问数据库的标准规范。真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用JDBC接口中的方法即可。数据库驱动由数据库厂商提供。

JDBC的包

  1. java.sql:JDBC访问数据库的基础包,在JavaSE中的包。如:java.sql.Connection
  2. javax.sql: JDBC访问数据库的扩展包
  3. 数据库的驱动,各大数据库厂商来实现。如:MySQL的驱动:com.mysql.jdbc.Driver

JDBC四个核心对象

这几个类都是在java.sql包中

  1. DriverManager: 用于注册驱动,获取连接
  2. Connection: 表示与数据库创建的连接
  3. Statement: 用于执行静态 SQL 语句并返回它所生成结果的对象
  4. ResultSet: 结果集或一张虚拟表(客户端表数据的对象)

DriverManager

  • java.sql.DriverManager

  • 提供驱动的基础服务,对驱动实现细节进行屏蔽

  • 注册加载驱动,用于获取连接

  • registerDriver():注册驱动

  • 源代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    // Register ourselves with the DriverManager
    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
    }
    }
    }

加载驱动的方式

  • 推荐使用类加载,只注册一次
  1. 创建Driver对象,注册了二次驱动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Driver driver = new com.mysql.jdbc.Driver();
    //注册驱动
    DriverManager.registerDriver(driver);
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while(drivers.hasMoreElements()) {
    nums ++;
    //打印出驱动
    System.out.println(drivers.nextElement());
    }
    //打印出驱动个数
    System.out.println("驱动个数:" + nums);
    1
    2
    3
    4
    5
    6
    //注释掉:DriverManager.registerDriver(driver);可以看到驱动个数为1个
    //说明了DriverManager.registerDriver(driver);这行代码可以去掉,如果加上,就会出现了两个驱动,
    // 因为在创建Driver这个对象的时候,其内的static语句块会自动执行了。
    Driver driver = new com.mysql.jdbc.Driver();
    //注册驱动
    // DriverManager.registerDriver(driver);
  2. 类加载,使用静态代码块

    1
    2
    3
    //创建Class对象时,会执行类的静态代码块
    //在com.mysql.jdbc.Driver类的静态代码块中,注册驱动
    Class.forName("com.mysql.jdbc.Driver");// 静态代码块

Connection

  • 代表客户端程序与数据库的连接

  • 与数据的交互都需要依赖于此连接

方法:

  1. Statement createStatement(): 创建一个 Statement 对象来将 SQL 语句发送到数据库
  2. prepareStatement(sql);
  3. setAutoCommit(false);
  4. commit();
  5. rollback();
  6. getMetaData();获取连接的元数据信息,和连接相关的数据(元数据:解释数据的数据)
  7. getDatabaseProductName():数据库产品的名字
  8. getDriverName():获取驱动的信息
  9. getURL(): 获取连接的URL;
  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // jdbc:公共协议+子协议+ip地址+数据库名字
    // ? 参数
    // useSSL=true SSL(Secure Sockets Layer 安全套接层),
    // 及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议
    Connection connection = null;
    connection = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/bd1807?useSSL=true",
    "root",
    "123456"
    );

    DatabaseMetaData metaData = connection.getMetaData();
    metaData.getDatabaseProductName();//数据库产品的名字
    System.out.println(metaData.getDriverName());//获取驱动的
    metaData.getURL();
    // 能得到connection,说明数据库已经连接
    System.out.println(connection);

    DatabaseMetaData metaData = connection.getMetaData();
    metaData.getDatabaseProductName();//数据库产品的名字
    System.out.println(metaData.getDriverName());//获取驱动的信息
    metaData.getURL();

statement

  1. boolean execute(String sql):此方法可以执行任意sql语句。
    • 返回boolean值,表示是否返回ResultSet结果集。
    • 仅当执行select语句,且有返回结果时返回true,
    • 其它语句都返回false;
  2. ResultSet executeQuery(String sql)
    • 根据查询语句返回结果集,只能执行SELECT语句
  3. int executeUpdate(String sql);
    • 根据执行的DML(INSERT、UPDATE、DELETE)语句
    • 返回受影响的行数;用于增删改
  4. executeBatch();       //批处理,返回int[]

ResultSet

  • 代表返回结果的结果集
  • ResultSet内部有一个指针,刚开始记录开始位置
  • 调用next方法, ResultSet内部指针会移动到下一行数据(遍历一行)
  • 我们可以通过ResultSet得到一行数据 getXxx得到某列数据
    • getMetaData(): 获取结果集的元数据
    • getColumnCount():获取结果的列
    • getColumnName(int column):获取对应列的名字
    • getInt(“字段名”);
    • getString(“字段名”)
  • 遍历的时候,得到字段的名字,通过反射,获得属性Field,赋值封装到对象

jdbc开发

创建项目

  1. 新建java工程
  2. 新建lib文件夹,用来放library文件;
  3. 导入jdbc的实现类(数据库的jar)
  4. 右键jar—> buildPath —-> add to build path

连接数据库

  1. 注册驱动,Drivermanager管理具体的驱动程序,实现对底层屏蔽,对开发人员提供统一的访问

  2. 建立连接

  3. url :    jdbc:公共协议+子协议+ip地址+数据库名字

    • URL地址格式:协议名:子协议://服务器名或IP地址:端口号/数据库名?参数=参数值,localhost:3306可以省略
    • 如果出现乱码需要加上参数: ?characterEncoding=utf8,表示让数据库以UTF-8编码来处理数据。
  4. user:  用户名

  5. password:   密码

发送sql

Statement对象:实现sql发送 Statement statement = connection.createStatement();

  • statement.executeQuery(sql);//查询语句,返回一个结果集
  • statement.executeUpdate(sql); //增删改,DDL,返回影响的行数##
  • statement.executeBatch();//批处理,返回int[]

处理响应结果

ResultSet底层维护了一个指向结果集的游标

程序中每次读取一行,一个一个读(游标指向行的(字段)信息)

  • next():游标向下,返回boolean类型,true有数据
  • getInt(String str):通过字段名称获取
1
ResultSet result = statement.executeQuery(sql);// 查询语句,返回一个结果集

释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
finally {
try {
if(connection!=null) {
connection.close();
}
if(statement!=null) {
statement.close();
}
if(result!=null) {
result.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
    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
    import java.sql.*;
    public class JdbcDemo01 {
    public static void main(String[] args) throws ClassNotFoundException {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = null;
    Statement statement = null;
    ResultSet resultSet = null;
    String url = "jdbc:mysql://localhost:3306/test";
    String username = "root";
    String password = "123456";
    try {
    conn = DriverManager.getConnection(url, username, password);
    statement = conn.createStatement();
    String sql = "select * from user";
    resultSet = statement.executeQuery(sql);
    if (resultSet.next()) {
    String name1 = resultSet.getString("name");
    String username1 = resultSet.getString("username");
    String password1 = resultSet.getString("password");
    System.out.println("姓名:" + name1 + ",用户名:" + username1 + ",密码:" + password1);
    }

    } catch (SQLException e) {
    e.printStackTrace();
    } finally {
    try {
    resultSet.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    try {
    statement.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    try {
    conn.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
    }

JDBC事务

  • 事务的基本概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

  • 事务的特点

特点 描述
原子性 一个事务是不可分割的最小单位
一致性 一个事务在执行之前和之后都必须处于一致性状态
隔离性 多个并发事务之间的操作不会互相干扰
持久性 提交的事务会使得修改的书是永久的

API介绍

1
2
3
4
5
6
7
8
Connection接口中与事务有关的方法

void setAutoCommit(boolean autoCommit) throws SQLException;
//false:开启事务,不自动提交, ture:关闭事务,自动提交

void commit() throws SQLException;//提交事务

void rollback() throws SQLException;//回滚事务

使用步骤

  1. 注册驱动 Class.forName("com.mysql.jdbc.Driver");

  2. 获取连接DriverManager.getConnection(url, username, password);

  3. 获取到Statement Connection.createStatement();

  4. 开启事务 Connection.setAutoCommit(false);//设置不自动提交事务

  5. 使用Statement执行SQL Statement.executeUpdate(sql);

  6. 提交或回滚事务 Connection.commit();//提交事务

  7. 关闭资源 Statement.close(); Connection.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
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
import java.sql.*;
public class JdbcCommitDemo01 {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = null;
Statement statement = null;
ResultSet res = null;

String url = "jdbc:mysql://localhost:3306/day17";
String username = "root";
String password = "339869";

try {
conn = DriverManager.getConnection(url, username, password);
conn.setAutoCommit(false);//设置不自动提交事务
statement = conn.createStatement();

//张三转出500
String sql = "UPDATE account set balance =balance-500 WHERE NAME='张三' ";
statement.executeUpdate(sql);

//设置异常
int a=100/0;

//李四收到500
String sql2 = "UPDATE account set balance =balance+500 WHERE NAME='李四' ";
statement.executeUpdate(sql2);
conn.commit();//提交事务

} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}

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

jdbc工具类

  • 通过上面案例需求我们会发现每次去执行SQL语句都需要注册驱动,获取连接,得到Statement,以及释放资源。发现很多重复的劳动,我们可以将重复的代码定义到某个类的方法中。直接调用方法,可以简化代码。那么我们接下来定义一个JDBCUtil类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中。以后直接调用方法即可。

  • 我们可以将重复的代码定义到某个类的方法中。直接调用方法,可以简化代码。定义一个JDBCUtil类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中,以后直接调用方法即可。

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
编写JDBC工具类步骤
1. 将固定字符串定义为常量
2. 在静态代码块中注册驱动(只注册一次)
3. 提供一个获取连接的方法static Connection getConneciton();
4. 定义关闭资源的方法close(Connection conn, Statement stmt, ResultSet rs)
5. 重载关闭方法close(Connection conn, Statement stmt)

面向对象的思想
* 怎么来封装一个方法:
* 1.修饰符使用什么
* 2.是否要是静态?一般都不封装成静态方法,只有工具类的方法封装成静态
* 3.返回值是什么类型?调用方法的时候需要得到什么数据,就是什么返回值
* 4.方法的参数有几个?都是什么类型?方法里面需要什么,就传递什么参数
* 驱动只需要注册一次即可,没必要每次获取连接都注册驱动,所以我们可以将注册驱动的代码写到静态代码块中
*
* 耦合:模块与模块之间的关联性
* 分类:1.编译期耦合 2.常量硬编码的耦合 解决方法是使用配置文件代替硬编码
* 配置文件的分类:1.properties配置文件 2.xml配置文件
* 配置文件存放的路径:在项目下编写一个resources目录,并且将其Mark成"Resources Root"
* 那么此时,这个resources文件夹,就变成了"配置文件的类路径"
* properties文件的编写语法:key=value


public class JdbcUtilDemo02 {
private static String driverClass;
private static String url;
private static String user;
private static String password;
static {
try {
//创建输入流
// FileInputStream fis = new FileInputStream("E:\\JDBC\\resource\\jdbc.properties");
//使用类加载器将文件读取到流
ClassLoader classLoader = JdbcUtil.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");

Properties properties = new Properties();//构造properties对象,用于从输入流中读取数据
properties.load(is);//从输入流中读取属性列表

//从properties中取出数据
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//加载驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}

//创建数据库连接
public static Connection getConnection() throws SQLException {
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}

//关流的方法
public static void colseStream(Connection conn, Statement st, ResultSet res) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关流的重载方法
public static void colseStream(Connection conn, Statement st) {
colseStream(conn, st, null);
}
}