JDBC:Java数据库连接

什么是JDBC 

 JDBC 的全称是 Java数据库连接 (Java Database Connectivity),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、更新、新增和删除的操作。

 不同种类的数据库 (如 MySQL、Oracle 等) 在其内部处理数据的方式是不同的,应用程序如果直接使用数据库厂商提供的访问接口操作数据库,应用程序的可移植性就会变得很差。例如,用户当前在程序中使用的是MySQL提供的接口操作数据库,如果换成Oracle数据库,则需要重新使用Oracle数据库提供的接口,这样代码的改动量会非常大。有了JDBC后,这种情况就不复存在了,因为它要求各个数据库厂商按照统一的规范来提供数据库驱动,而在程序中是由JDBC和具体的数据库驱动联系,所以用户就不必直接与底层的数据库交互,这使得代码的通用性更强。

应用程序使用JDBC访问数据库的方式如下图所示。JDBC在应用程序数据库之间起到了一个桥梁作用。

JDBC 常用 API

Driver 接口

  Driver 接口是所有JDBC驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。需要注意的是,在编写JDBC程序时,必须要把所使用的数据库驱动程序或类库加载到项目的 classpath 中(这里指 MySQL驱动JAR包)。

DriverManager 类

  DriverManager 类用于加载JDBC驱动并且创建与数据库的连接。在 DriverManager 类中,定义了两个比较重要的静态方法。

  • registerDriver (Driver driver)  该方法用于向 DriverManager 中注册给定的 JDBC 驱动程序
  • getConnection (String url, String user, String psw)  该方法用于建立和数据库的连接,并返回表示连接的 Connection 对象

Connection 接口

  Connection 接口代表Java程序和数据库的连接,只有获得该连接对象后才能访问数据库,并操作数据表。在Connection接口中,定义了一系列方法,其常用方法如下表所示。

  • getMetaData ()  该方法用于返回表示数据库的元数据的 DatabaseMetaData 对象
  • createStatement ()  用于创建一个 Statement 对象并将SQL语句发送到数据库
  • prepareStatement (String sql)  用于创建—个 PreparedStatement 对象并将参数化的SQL语句发送到数据库
  • prepareCall (String sql)  用于创建一个 CallableStatement 对象来调用数据库存储过程

Statement 接口

  Statement 接口用于执行静态的SQL语句,并返回一个结果对象,该接口的对象通过Connection实例的createStatement()方法获得。利用该对象把静态的SQL语句发送到数据库编译执行,然后返回数据库的处理结果。在Statement 接口中,提供了3个常用的执行SQL语句的方法,具体如下表所示。

  • execute (String sql)  用于执行各种SQL语句,该方法返回一个 boolean 类型的值,如果为 true,表示所执行的SQL语句有查询结果,可通过 Statement 的 getResultSet() 方法获得查询结果
  • executeUpdate (String sql)  用于执行SQL中的 insert 、update 和 delete 语句。该方法返回一个 int 类型的值,表示数据库中受该SQL语句影响的记录条数
  • executeQuery (String sql)  用于执行SQL中的 select 语句,该方法返回一个表示查询结果的 ResultSet 对象

  Statement 接口封装了JDBC执行SQL语句的方法,可以完成Java程序执行SQL语句的操作。然而在实际开发过程中往往需要将程序中的变量作为SQL语句的查询条件,而使用Statement接口操作这些SQL语句会过于繁琐,并且存在安全方面的问题。针对这一问题,JDBC API 中提供了扩展的PreparedStatement接口。

PreparedStatement 接口

  PreparedStatement 是Statement的子接口,用于执行预编译的SQL语句。该接口扩展了带有参数SQL语句的执行操作,应用该接口中的SQL语句可以使用占位符 “?” 来代替其参数,然后通过 setXxx() 方法为SQL语句的参数赋值。在PreparedStatement接口中,提供了一些常用方法,具体如下表所示。

  • executeUpdate (String sql)  在此 PreparedStatement 对象中执行SQL语句,该语句必须是一个DML语句或者是无返回内容的SQL语句,比如DDL语句
  • executeQuery (String sql)  在此 PreparedStatement 对象中执行SQL查询,该方法返回的是 ResultSet 对象
  • setInt (int parameterIndex,  int x)    将指定参数设置为给定的 int 值
  • setFloat (int parameterIndex,  float x)  将指定参数设置为给定的 float 值
  • setString (int parameterIndex,  String x) 将指定参数设置为给定的 String 值
  • setDate (int parameterIndex,  Date x)  将指定参数设置为给定的 Date 值
  • addBatch ()  将一组参数添加到此 PreparedStatement 对象的批处理命令中
  • setCharacterStream (int parameterIndex,  java.io.Reader reader,  int length)  将指定的输入流写入数据库的文本字段
  • setBinaryStream (int parameterIndex,  java.io.InputStream x,  int length)  将二进制的输入流数据写入到二进制字段中

 在通过 setXxx() 方法为SQL语句中的参数赋值时,可以通过输入参数的已定义SQL类型兼容的方法(例如,如果参数具有SQL类型为Integer,那么应该使用setInt 方法),也可以通过setObject()方法设置多种类型的输入参数。具体如下所示:

String sql ="INSERT INTO users(id,name,email) VALUES(?,?,?)";
PreparedStatement preStmt = conn.preparestatement(sql); preStmt.setInt(1,1);  // 使用参数的已定义SQL类型 preStmt.setString(2,"zhangsan");  // 使用参数的已定义SQL类型 preStmt.setObject(3, "zs@sina.com");  // 使用 set0bject() 方法设置参数
preStmt.executeUpdate();

ResultSet 接口

  ResultSet 接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(或指针),ResultSet对象初始化时,游标在表格的第一行之前,调用 next() 方法可将游标移动到下一行。如果下一行没有数据,则返回 false。在应用程序中经常使用 next() 方法作为 while 循环的条件来迭代 ResultSet 结果集。ResultSet接口中的常用方法如下表所示。

  • getSting (int columnIndex)  用于获取指定字段的 string 类型的值,参数 columnIndex 代表字段的索引
  • getString (String columnName)  用于获取指定字段的 String 类型的值,参数 columnName 代表字段的名称
  • getInt (int columnIndex)  用于获取指定字段的 int 类型的值,参数 columnIndex 代表字段的索引
  • getInt (String columnName)  用于获取指定字段的 int 类型的值,参数 columnName 代表字段的索引
  • getDate (int columnIndex)  用于获取指定字段的 Date 类型的值,参数 columnIndex 代表字段的索引
  • getDate (String columnName)  用于获取指定字段的 Date 类型的值,参数 columnName 代表字段的名称
  • next ()  将游标从当前位置向下移一行
  • absolute (int row)  将游标移动到此 ResultSet 对象的指定行
  • afterLast ()  将游标移动到此 ResultSet 对象的末尾,即最后一行之后
  • beforeFirst()  将游标移动到此 ResultSet 对象的开头,即第一行之前
  • previous ()  将游标移动到此 ResultSet 对象的上一行
  • last ()  将游标移动到此 ResultSet 对象的最后一行

 从上面方法可以看出,ResultSet 接口中定义了大量的 getXxx() 方法,而采用哪种 getXxx() 方法取决于字段的数据类型。程序既可以通过字段的名称来获取指定数据,也可以通过字段的索引来获取指定的数据,字段的索引是从1开始编号的。例如,数据表的第一列字段名为id,字段类型为int,那么既可以使用 getInt(1) 字段索引的方式获取该列的值,也可以使用 getInt(“id”) 字段名称的方式获取该列的值。

案例:使用JDBC完成数据的增删改查

1、需求分析

  Statement 对象每次执行SQL语句时,都会对其进行编译。当相同的SQL语句执行多次时,Statement对象就会使数据库频繁编译相同的SQL语句,从而降低数据库的访问效率。为了解决这个问题,Statement提供了一个子类 PreparedStatement。PreparedStatement对象可以对SQL语句进行预编译,预编译的信息会存储在PreparedStatement对象中。当相同的SQL语句再次执行时,程序会使用 PreparedStatement对象中的数据,而不需要对SQL语句再次编译去查询数据库,这样就大大的提高了数据的访问效率。

2、设计思路(实现原理)

  1. 创建一个用于封装数据的 JavaBean
  2. 将加载驱动和获取数据连接等操作封装在一个工具类中,以供其他类调用
  3. 创建一个实现了对数据库添删改查操作的 DAO
  4. 分别创建用于执行对数据表添删改查操作的测试类
  5. 执行程序,测试结果

3、代码实现

3.1. 创建 JavaBean

创建一个用于保存用户数据的User类

import java.util.Date;
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private Date birthday;
    // 此处省略各属性的 getter/setter 方法 和 toString 方法

3.2. 创建工具类 JDBCUtils
由于每次操作数据库时,都需要加载数据库驱动、建立数据库连接以及关闭数据库连接,为了避免代码的重复书写,下面建立一个专门用于数据库相关操作的工具类JDBCUtils

package com.bjpowernode.JDBC;
import java.sql.*;
public class JDBCUtils { // 加载驱动,并建立数据库连接 public static Connection getConnection() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/jdbc"; // 数据库名:jdbc String username = "root"; String password = "root"; Connection conn = DriverManager.getConnection(url, username, password); return conn; } // 关闭数据库连接,释放资源 public static void release(PreparedStatement prestmt, Connection conn, ResultSet rs){ if (prestmt != null) { try { prestmt.close(); } catch (SQLException e){ e.printStackTrace(); } prestmt = null; } if (conn != null) { try { conn.close(); } catch (SQLException e){ e.printStackTrace(); } conn = null; } if (rs != null) { try { rs.close(); } catch (SQLException e){ e.printStackTrace(); } rs = null; } } }

3.3. 创建DAO
创建一个名称为 UsersDao 的类,该类中封装了对 t_user 表的添加、查询、删除和更新等操作。

package com.bjpowernode.JDBC;
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList;
public class UsersDao { // 添加用户的操作 public boolean insert(User user) throws SQLException, ClassNotFoundException { Connection conn = null; PreparedStatement prestmt = null; ResultSet rs = null; try { // 获得数据的连接 conn = JDBCUtils.getConnection(); // 发送SQL语句 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String birthday = sdf.format(user.getBirthday()); String sql = "insert into t_user(id,name,password,email,birthday) " + "values(" + user.getId() + ",'" + user.getUsername() + "','" + user.getPassword() + "','" + user.getEmail() + "','" + birthday + "')"; prestmt = conn.prepareStatement(sql); int num = prestmt.executeUpdate(); if (num > 0) { return true; } return false; } catch (Exception e){ e.printStackTrace(); } finally { JDBCUtils.release(prestmt,conn,rs); } return false; }
// 查询所有的User对象 public ArrayList<User> findaAll(){ Connection conn = null; PreparedStatement prestmt = null; ResultSet rs = null; ArrayList<User> list = new ArrayList<User>(); try { // 获得数据的连接 conn = JDBCUtils.getConnection(); // 发送SQL语句 String sql = "select * from t_user"; prestmt = conn.prepareStatement(sql); rs = prestmt.executeQuery(); // 处理结果集 while (rs.next()){ User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("name")); user.setPassword(rs.getString("password")); user.setEmail(rs.getString("email")); user.setBirthday(rs.getDate("birthday")); list.add(user); } return list; } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { JDBCUtils.release(prestmt,conn,rs); } return null; } // 根据id查找指定的user public User find(int id){ Connection conn = null; PreparedStatement pretmt = null; ResultSet rs = null; try { // 获得数据的连接 conn = JDBCUtils.getConnection(); // 发送SQL语句 String sql = "select * from t_user where id=" + id; pretmt = conn.prepareStatement(sql); rs = pretmt.executeQuery(); // 处理结果集 while (rs.next()){ User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("name")); user.setPassword(rs.getString("password")); user.setBirthday(rs.getDate("birthday")); return user; } return null; } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { JDBCUtils.release(pretmt,conn,rs); } return null; } // 删除用户 public boolean delete(int id){ Connection conn = null; PreparedStatement pretmt = null; ResultSet rs = null; try { // 获得数据的连接 conn = JDBCUtils.getConnection(); // 发送SQL语句 String sql = "delete from t_user where id=" + id; pretmt = conn.prepareStatement(sql); int num = pretmt.executeUpdate(); if (num > 0) { return true; } return false; } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { JDBCUtils.release(pretmt,conn,rs); } return false; } // 修改用户 public boolean update(User user) { Connection conn = null; PreparedStatement prestmt = null; ResultSet rs = null; try { // 获得数据的连接 conn = JDBCUtils.getConnection(); // 发送SQL语句 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String birthday = sdf.format(user.getBirthday()); String sql = "UPDATE t_user set name='" + user.getUsername() + "',password='" + user.getPassword() + "',email='" + user.getEmail() + "',birthday='" + birthday + "' WHERE id=" + user.getId(); prestmt = conn.prepareStatement(sql); int num = prestmt.executeUpdate(); if (num > 0) { return true; } return false; } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.release(prestmt, conn, rs); } return false; } }

3.4. 创建测试类
(1)编写测试类 JdbcInsertTest,实现向 t_user 表中添加一条数据,其代码如下所示。

package com.bjpowernode.JDBC;
import java.sql.SQLException; import java.util.Date;
public class JdbcInsertTest { public static void main(String[] args) throws SQLException, ClassNotFoundException { // 向t_user表插入一个用户信息 UsersDao ud = new UsersDao(); User user=new User(); user.setId(6); user.setUsername("hym"); user.setPassword("1234"); user.setEmail("hym@sina.com"); user.setBirthday(new Date()); boolean b=ud.insert(user); System.out.println(b); // 成功返回:true } }

(2)编写测试类 FindAllUsersTest,该类用于实现读取 t_user 表中所有的数据,其代码如下所示。

package com.bjpowernode.JDBC;
import java.util.ArrayList;
public class FindAllUsersTest { public static void main(String[] args) { UsersDao ud = new UsersDao(); ArrayList<User> list = ud.findaAll(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } }

(3)编写测试类 FindUserByIdTest,该类实现了读取 t_user 表中指定的数据,其代码如下所示。

package com.bjpowernode.JDBC;
public class FindUserByIdTest { public static void main(String[] args) { UsersDao ud = new UsersDao(); User user = ud.find(6); System.out.println(user); } }

(4)编写测试类 UpdateUserTest,该类实现了修改 t_user 表中数据的操作,具体代码如下所示。

package com.bjpowernode.JDBC;
import java.util.Date;
public class UpdateUserTest { public static void main(String[] args) { UsersDao ud = new UsersDao(); User user = new User(); user.setId(6); user.setUsername("hym"); user.setPassword("4321"); user.setEmail("hym@sina.com"); user.setBirthday(new Date()); boolean b=ud.update(user); System.out.println(b); // 成功返回:true } }

(5)编写测试类 DeleteUserTest,该类实现了删除 t_user 表中数据的操作,其代码如下所示。

package com.bjpowernode.JDBC;
public class DeleteUserTest { public static void main(String[] args) { UsersDao ud = new UsersDao(); boolean b = ud.delete(6); System.out.println(b); // 成功返回:true } }

参考:JDBC详解学习文档 (360doc.com)

posted @ 2022-08-11 21:14  鹿先森JIAN  阅读(434)  评论(0编辑  收藏  举报