Java 之 JDBC 一、JDBC 基础入门 二、详解各个对象 三、数据库工具类 JdbcUtils 四、案例  五、JDBC 控制事务  

  1、概念

    JDBC:Java DataBase Connectivity Java 数据库连接,Java 语言操作数据库。

    JDBC本质:其实就是官方(Sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动 jar 包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动 jar 包中的实现类

    使用JDBC的好处

    (1)程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。

    (2)使用一套 Java 代码,进行少量的修改就可以访问其他 JDBC支持的数据库。

    Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

  2、使用 JDBC 开发使用到的包

会使用到的包 说明
java.sql 所有与 JDBC 访问数据库相关的接口和类
javax.sql 数据库扩展包,提供数据库额外的功能。如:连接池
数据库的驱动 由各大数据库厂商提供,需要额外去下载,是对 JDBC 接口实现的类

  3、JDBC 的核心 API

接口或类 作用
DriverManager 1) 管理和注册数据库驱动
2) 得到数据库连接对象
Connection 接口 一个连接对象,可用于创建 Statement PreparedStatem
Statement 接口 一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器
PreparedStatemen 接口 一个 SQL 语句对象,是 Statement 的子接口
ResultSet 接口 用于封装数据库查询的结果集,返回给客户端 Java 程序

  4、使用步骤

      Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

    (1)导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar

      ① 复制 mysql-connector-java-5.1.37-bin.jar 到项目的 libs 目录下

      ② 右键 --> Add AS Libray

    (2)注册驱动(可以省略)

    (3)获取数据连接对象 Connection

    (4)定义 SQL 语句

    (5)获取执行 SQL 语句的对象 statement

    (6)执行 SQL,接收返回结果

    (7)处理结果

    (8)释放资源

  5、步骤实现

    (1)导入驱动 jar 包

      Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

         Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

        (2)代码实现

 1         //2.注册驱动
 2         Class.forName("com.mysql.jdbc.Driver");
 3         //3.获取数据库连接对象
 4         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root");
 5         //4.定义sql语句
 6         String sql = "update student set score= 500 where id = 1";
 7         //5.获取执行sql的对象 Statement
 8         Statement stmt = conn.createStatement();
 9         //6.执行sql
10         int count = stmt.executeUpdate(sql);
11         //7.处理结果
12         System.out.println(count);
13         //8.释放资源
14         stmt.close();
15         conn.close();

二、详解各个对象

  1、DriverManager:驱动管理对象

    功能:① 管理和注册驱动;② 创建数据库的连接

    (1)管理和注册驱动

      注册驱动就是告诉程序该使用哪一个数据库驱动 jar包,可以发现 DriverManger里面有一个静态方法

static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。 

      写代码使用:

Class.forName("com.mysql.jdbc.Driver");

      通过反射机制将驱动的字节码文件加载入程序里面。

       通过查看源码发现:在 com.mysql.jdbc.Driver 类中存在静态代码块

1 static {
2      try {                            
3          java.sql.DriverManager.registerDriver(new Driver()); // 注册数据库驱动
4      } catch (SQLException E) {
5          throw new RuntimeException("Can't register driver!");
6      }
7  }

      静态代码块会优先执行,自动调用了 DriverManager 类内的方法,不需要手动调用方法,更加方便。

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

    (2)获取数据库的连接

      ① 类中的静态方法

Connection getConnection (String url, String user, String password) 通过连接字符串, 用户名, 密码来得到数据库的连接对象
Connection getConnection (String url, Properties info) 通过连接字符串, 属性对象来得到连接对象

           ② 使用 JDBC 连接数据库的四个参数:   

JDBC 连接数据库的四个参数 说明
username用户名 登录的用户名
password密码 登录的密码
连接字符串 URL 不同的数据库 URL 是不同的, mysql 的写法
jdbc:mysql://localhost:3306/数据库[?参数名=参数值]
驱动类的字符串名 com.mysql.jdbc.Driver

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

       ③ MySQL 写法

      Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

         ④ 乱码的处理:

        如果数据库出现乱码,可以指定参数:?characterEncoding=utf8,表示让数据库以utf-8编码来处理数据。

jdbc:mysql://localhost:3306/数据库?characterEncoding=utf8

        ⑤ 得到数据库连接对象

        a、使用用户名、密码、URL得到连接对象

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 /**
 5 * 得到连接对象
 6 */
 7 public class Demo {
 8     public static void main(String[] args) throws SQLException {
 9         String url = "jdbc:mysql://localhost:3306/school";
10         //1) 使用用户名、密码、 URL 得到连接对象
11         Connection connection = DriverManager.getConnection(url,"root", "root");
12         //com.mysql.jdbc.JDBC4Connection@68de145
13         System.out.println(connection);
14     }
15 }    

        b、使用属性文件和URL 得到连接对象

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 import java.util.Properties;
 5 public class Demo {
 6     public static void main(String[] args) throws SQLException {
 7        //url 连接字符串
 8        String url = "jdbc:mysql://localhost:3306/day24";
 9        //属性对象
10        Properties info = new Properties();
11        //把用户名和密码放在 info 对象中
12        info.setProperty("user","root");
13        info.setProperty("password","root");
14        Connection connection = DriverManager.getConnection(url, info);
15        //com.mysql.jdbc.JDBC4Connection@68de145
16        System.out.println(connection);
17    }
18 }

  2、Connection 数据库连接对象(接口)

      Connection 接口:具体的实现类由数据库的厂商实现,代表一个连接对象。

    作用:① 获取执行 SQL 的对象 ② 管理事务

    (1)获取执行 SQL 的对象

Statement createStatement()   // 创建一条执行 SQL 语句对象
PreparedStatement prepareStatement(String sql)  // 生成预编译SQL的对象

    (2)管理事务

开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
提交事务:commit() 
回滚事务:rollback() 

  

  3、Statement 执行SQL的对象(接口)

    作用:代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。

    方法

boolean execute(String sql) :  可以执行任意的sql 了解 
int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
    返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
ResultSet executeQuery(String sql)  :执行DQL(select)语句,返回查询的结果集

  

  4、ResultSet 结果集对象

    作用:封装数据库查询的结果集,对结果进行遍历,取出每一条记录。

      Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

        接口中的方法

ResultSet 接口中的方法 描述
boolean next() 1) 游标向下移动 1
2) 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false
数据类型 getXxx() 1) 通过字段名,参数是 String 类型。返回不同的类型
2) 通过列号,参数是整数,从 1 开始。返回不同的类型

     Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

      常用数据类型转换表

SQL 类型 Jdbc 对应方法 返回类型
BIT(1) bit(n) getBoolean() boolean
TINYINT getByte() byte
SMALLINT getShort() short
INT getInt() int
BIGINT getLong() long
CHAR,VARCHAR getString() String
Text(Clob) Blob getClob getBlob() Clob Blob
DATE getDate() java.sql.Date 只代表日期
TIME getTime() java.sql.Time 只表示时间
TIMESTAMP getTimestamp() java.sql.Timestamp 同时有日期和时间

        注意java.sql.DateTimeTimestamp(时间戳),三个共同父类是: java.util.Date 

      关于 ResultSet 接口中的注意事项:

     ① 如果光标在第一行之前,使用 rs.getXX()获取列值,报错: Before start of result set

     ② 如果光标在最后一行之后,使用 rs.getXX()获取列值,报错: After end of result set

     ③ 使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection

  5、PreparedStatement:执行 SQL 的对象

      SQL注入问题:SQL语句进行字符串拼接,用户的输入的特殊关键字内容作为了 SQL 语句语法的一部分,改变了SQL真正的意义,会造成安全性问题,称为 SQL 注入。

      (1)PreparedStatement 接口继承结构与作用

               Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

               PreparedStatement 是 statement 接口的子接口,继承与父接口中所有的方法,是一个预编译的 SQL 语句。

      (2)PreparedStatement 的执行原理

Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

       (3)Connection 创建 PreparedStatement 对象

PreparedStatement prepareStatement(String sql) 指定预编译的 SQL 语句, SQL 语句中使用占位符?创建一个语句对象

  

       (4)PreparedStatement 接口中的方法

int executeUpdate() 执行 DML,增删改的操作,返回影响的行数
ResultSet executeQuery() 执行 DQL,查询的操作,返回结果集

        

      (5)PreparedStatement 的好处

        ① prepareStatement()会先将 SQL 语句发送给数据库预编译。 PreparedStatement 会引用着预编译后的结果。可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。

        ② 安全性更高,没有 SQL 注入的隐患。

        ③ 提高了程序的可读性

      (6)使用 PreparedStatement 的步骤

        ① 编写 SQL 语句,未知内容使用?占位: "SELECT * FROM user WHERE name=? AND password=?";

        ② 获得 PreparedStatement 对象

        ③ 设置实际参数: setXxx(占位符的位置, 真实的值)

        ④ 执行参数化 SQL 语句

        ⑤ 关闭资源 

PreparedStatement 中设置参数的方法 描述
void setDouble(int parameterIndex, double x) 将指定参数设置为给定 Java double 值。
void setFloat(int parameterIndex, float x) 将指定参数设置为给定 Java REAL 值。
void setInt(int parameterIndex, int x) 将指定参数设置为给定 Java int 值。
void setLong(int parameterIndex, long x) 将指定参数设置为给定 Java long 值。
void setObject(int parameterIndex, Object x) 使用给定对象设置指定参数的值。
void setString(int parameterIndex, String x) 将指定参数设置为给定 Java String 值。

 

  6、资源的释放

    (1)需要释放的对象,Result结果集、Statement 语句,Connection 连接

    (2)释放原则:先开的后关,后开的先关。ResultSet—> Statement —> Connection

    (3)放在 finally块中,无论如何都执行。

三、数据库工具类 JdbcUtils

  工具类作用:一个经常要用到的功能,把这个功能做成一个工具类,可以在不同的地方重用,简化书写

  将公共的代码抽取出来,封装成一个工具类。同时将需要传递的参数放入配置文件中,直接读取即可。

  配置文件:

jdbc.properties
url=jdbc:mysql://localhost:3306/数据库名
user=root
password=root
Driver=com.mysql.jdbc.Driver

  工具类:

  1 import java.io.FileReader;
  2 import java.io.IOException;
  3 import java.net.URL;
  4 import java.sql.*;
  5 import java.util.Properties;
  6 
  7 /**
  8  * JDBC工具类
  9  */
 10 public class JDBCUtils {
 11     private static String url;
 12     private static String user;
 13     private static String password;
 14     private static String driver;
 15 
 16     /**
 17      * 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
 18      */
 19     static {
 20         //读取资源文件,获取值。
 21 
 22         try {
 23             //1. 创建Properties集合类。
 24             Properties pro = new Properties();
 25 
 26             //获取src路径下的文件的方式--->ClassLoader 类加载器
 27             ClassLoader classLoader = JDBCUtils.class.getClassLoader();
 28             URL res = classLoader.getResource("jdbc.properties");
 29             String path = res.getPath();
 30             // System.out.println(path);///D:/IdeaProjects/ks/out/production/day04_jdbc/jdbc.properties
 31             //2. 加载文件
 32             // pro.load(new FileReader("D:\IdeaProjects\ks\day04_jdbc\src\jdbc.properties")); 绝对路径,不建议使用
 33             pro.load(new FileReader(path));
 34 
 35             //3. 获取数据,赋值
 36             url = pro.getProperty("url");
 37             user = pro.getProperty("user");
 38             password = pro.getProperty("password");
 39             driver = pro.getProperty("driver");
 40             //4. 注册驱动
 41             Class.forName(driver);
 42         } catch (IOException e) {
 43             e.printStackTrace();
 44         } catch (ClassNotFoundException e) {
 45             e.printStackTrace();
 46         }
 47     }
 48 
 49 
 50     /**
 51      * 获取连接
 52      *
 53      * @return 连接对象
 54      */
 55     public static Connection getConnection() throws SQLException {
 56 
 57         return DriverManager.getConnection(url, user, password);
 58     }
 59 
 60     /**
 61      * 释放资源
 62      *
 63      * @param stmt
 64      * @param conn
 65      */
 66     public static void close(Statement stmt, Connection conn) {
 67         if (stmt != null) {
 68             try {
 69                 stmt.close();
 70             } catch (SQLException e) {
 71                 e.printStackTrace();
 72             }
 73         }
 74 
 75         if (conn != null) {
 76             try {
 77                 conn.close();
 78             } catch (SQLException e) {
 79                 e.printStackTrace();
 80             }
 81         }
 82     }
 83 
 84 
 85     /**
 86      * 释放资源
 87      *
 88      * @param stmt
 89      * @param conn
 90      */
 91     public static void close(ResultSet rs, Statement stmt, Connection conn) {
 92         if (rs != null) {
 93             try {
 94                 rs.close();
 95             } catch (SQLException e) {
 96                 e.printStackTrace();
 97             }
 98         }
 99 
100         if (stmt != null) {
101             try {
102                 stmt.close();
103             } catch (SQLException e) {
104                 e.printStackTrace();
105             }
106         }
107 
108         if (conn != null) {
109             try {
110                 conn.close();
111             } catch (SQLException e) {
112                 e.printStackTrace();
113             }
114         }
115     }
116 
117 }

四、案例

  1、执行DDL操作

    需求:使用 JDBC 在 MySQL 的数据库中创建一张学生表
    Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

      代码实现:

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 import java.sql.Statement;
 5 
 6 /**
 7  * 创建一张学生表
 8  */
 9 public class Demo {
10     public static void main(String[] args) {
11         //1. 创建连接
12         Connection conn = null;
13         Statement statement = null;
14         try {
15             conn = DriverManager.getConnection("jdbc:mysql:///school", "root", "root");
16             //2. 通过连接对象得到语句对象
17             statement = conn.createStatement();
18             //3. 通过语句对象发送 SQL 语句给服务器
19             //4. 执行 SQL
20             statement.executeUpdate("create table student (id int PRIMARY key auto_increment, " +
21                     "name varchar(20) not null, gender boolean, birthday date)");
22             //5. 返回影响行数(DDL 没有返回值)
23             System.out.println("创建表成功");
24         } catch (SQLException e) {
25             e.printStackTrace();
26         }
27             //6. 释放资源
28         finally {
29             //关闭之前要先判断
30             if (statement != null) {
31                 try {
32                     statement.close();
33                 } catch (SQLException e) {
34                     e.printStackTrace();
35                 }
36             }
37             if (conn != null) {
38                 try {
39                     conn.close();
40                 } catch (SQLException e) {
41                     e.printStackTrace();
42                 }
43             }
44         }
45     }
46 }
View Code

 

  2、执行DML操作

    需求:向学生表中添加 4 条记录,主键是自动增长

    Java 之 JDBC
一、JDBC 基础入门
二、详解各个对象
三、数据库工具类 JdbcUtils
四、案例
 五、JDBC 控制事务
 

    步骤:

1) 创建连接对象
2) 创建 Statement 语句对象
3) 执行 SQL 语句: executeUpdate(sql)
4) 返回影响的行数
5) 释放资源

      代码实现:

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 import java.sql.Statement;
 5 
 6 /**
 7  * 向学生表中添加 4 条记录,主键是自动增长
 8  */
 9 public class Demo {
10     public static void main(String[] args) throws SQLException {
11         // 1) 创建连接对象
12         Connection connection = DriverManager.getConnection("jdbc:mysql:///school", "root",
13                 "root");
14         // 2) 创建 Statement 语句对象
15         Statement statement = connection.createStatement();
16         // 3) 执行 SQL 语句: executeUpdate(sql)
17         int count = 0;
18         // 4) 返回影响的行数
19         count += statement.executeUpdate("insert into student values(null, '孙悟空', 1, '1993-03-24')");
20         count += statement.executeUpdate("insert into student values(null, '白骨精', 0, '1995-03-24')");
21         count += statement.executeUpdate("insert into student values(null, '猪八戒', 1, '1903-03-24')");
22         count += statement.executeUpdate("insert into student values(null, '嫦娥', 0, '1993-03-11')");
23         System.out.println("插入了" + count + "条记录");
24         // 5) 释放资源
25         statement.close();
26         connection.close();
27     }
28 }
View Code

  3、执行 DQL 操作

    需求:确保数据库中有 3 条以上的记录,查询所有的学员信息
    步骤:

1) 得到连接对象
2) 得到语句对象
3) 执行 SQL 语句得到结果集 ResultSet 对象
4) 循环遍历取出每一条记录
5) 输出的控制台上
6) 释放资源

    代码实现:

 1 import java.sql.*;
 2 
 3 /**
 4  * 查询所有的学生信息
 5  */
 6 public class Demo5 {
 7     public static void main(String[] args) throws SQLException {
 8         //1) 得到连接对象
 9         Connection connection =
10                 DriverManager.getConnection("jdbc:mysql://localhost:3306/school","root","root");
11         //2) 得到语句对象
12         Statement statement = connection.createStatement();
13         //3) 执行 SQL 语句得到结果集 ResultSet 对象
14         ResultSet rs = statement.executeQuery("select * from student");
15         //4) 循环遍历取出每一条记录
16         while(rs.next()) {
17             int id = rs.getInt("id");
18             String name = rs.getString("name");
19             boolean gender = rs.getBoolean("gender");
20             Date birthday = rs.getDate("birthday");
21             //5) 输出的控制台上
22             System.out.println("编号: " + id + ", 姓名: " + name + ", 性别: " + gender + ", 生日: " +
23                     birthday);
24         }
25         //6) 释放资源
26         rs.close();
27         statement.close();
28         connection.close();
29     }
30 }
View Code

 五、JDBC 控制事务

  1、事务概念

    事务:一个包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

    MySQL 事务

  2、API 介绍

Connection 接口中与事务有关的方法 说明
void setAutoCommit(boolean autoCommit) 参数是 true false
如果设置为 false,表示关闭自动提交,相当于开启事务
void commit() 提交事务
void rollback() 回滚事务

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

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

  4、案例

    模拟银行转账的事务。

    开发步骤:

1) 获取连接
2) 开启事务
3) 获取到 PreparedStatement
4) 使用 PreparedStatement 执行两次更新操作
5) 正常情况下提交事务
6) 出现异常回滚事务
7) 最后关闭资源

    代码实现:

 1 import cn.ks.utils.JDBCUtils;
 2 import java.sql.Connection;
 3 import java.sql.PreparedStatement;
 4 import java.sql.SQLException;
 5 public class Demo6 {
 6     //没有异常,提交事务,出现异常回滚事务
 7     public static void main(String[] args) {
 8         //1) 注册驱动
 9         Connection connection = null;
10         PreparedStatement ps = null;
11         try {
12             //2) 获取连接
13             connection = JDBCUtils.getConnection();
14             //3) 开启事务
15             connection.setAutoCommit(false);
16             //4) 获取到 PreparedStatement
17             //从 jack 扣钱
18             ps = connection.prepareStatement("update account set balance = balance - ? where name=?");
19             ps.setInt(1, 500);
20             ps.setString(2,"Jack");
21             ps.executeUpdate();
22             //出现异常
23             System.out.println(100 / 0);
24             //给 rose 加钱
25             ps = connection.prepareStatement("update account set balance = balance + ? where name=?");
26             ps.setInt(1, 500);
27             ps.setString(2,"Rose");
28             ps.executeUpdate();
29             //提交事务
30             connection.commit();
31             System.out.println("转账成功");
32         } catch (Exception e) {
33             e.printStackTrace();
34             try {
35             //事务的回滚
36                 connection.rollback();
37             } catch (SQLException e1) {
38                 e1.printStackTrace();
39             }
40             System.out.println("转账失败");
41         }
42         finally {
43         //7) 关闭资源
44             JDBCUtils.close(ps,connection);
45         }
46     }
47 }
View Code