JDBC核心技术1

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JDBC核心技术1

第1章:JDBC概述

1.1 数据的持久化

●持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用, 数据持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成。

●持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中


1.2 java中的数据存储技术

JDBC直接访问数据库

JDO (Java Data Object)技术

第三方O/R工具,如Hibernate, Mybatis等

JDBC是java访问数据库的基石,jDO、Hibernate.MyBatis等只是更好的封装了JDBC。

1.3 JDBC 介绍

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。


JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题


jDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

如果没有JDBC,那么Java程序访问数据库时是这样的:


有了JDBC,Java程序访问数据库时是这样的:


总结如下:



1.4 JDBC 体系结构

JDBC接口(API)包括两个层次:

面向应用的API: Java APl,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
面向数据库的API: Java Driver API,供开发商开发数据库驱动程序用。

JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。 不同的数据库厂商,需针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。     --------------------面向接口编程



1.5 JDBC程序编写步骤



第二章 获取数据库连接

2.1要素一:Driver接口实现类

2.1.1 Driver接口介绍

java.sql.Driver接口是所有JDBC驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据 库厂商提供不同的实现。

在程序中不需要直接去访问实现了Driver接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调 用这些Driver实现。

Oracle的驱动:oraclejdbc.driver.OracleDriver

mySq的驱动:com.mysql.jdbc.Driver

2.2要素二:URL

  • JDBC URL用于标识一个被注册的驱动程序,驱动程序管理器通过这个URL选择正确的驱动程序,从而建立到数据库的连接。
  • JDBCURL的标准由三部分组成,各部分间用冒号分隔。
    jdbc:子协议:子名称
  • 协议:JDBCURL中的协议总是jdbc
  • 子协议:子协议用于标识一个数据库驱动程序
  • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库 提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
    举例:


    几种常用数据库的JDBCURL
  • MySQL的连接URL编写方式:
  • jdbc:mysl://主机名称:mysq|服务端口号/数据库名称?参数=值&参数=值
  • jdbcmysql://localhost:3306/atguigu

2.3 要素三:用户名与密码

2.4 数据库连接方式举例

ConnectionTest.java

package com._1.connection;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.junit.Test;
public class ConnectionTest {
  //方式一:
  @Test
    public void testConnection1() throws SQLException{
    //获取Driver的实现类对象
    Driver driver =new com.mysql.jdbc.Driver();
    //jdbc:mysql:协议
    //localhost:IP地址
    //3306:默认mysql的端口号
    //xyz:mysql中的数据库
    String url="jdbc:mysql://localhost:3306/xyz";
    //将用户名和密码封装在Properties中
    Properties info=new Properties();
    info.setProperty("user", "root");
    info.setProperty("password", "root");
    Connection conn=driver.connect(url, info);
    System.out.println(conn);
  }
  //方式二:对方式一的迭代:在如下程序中不出现第三方的api,使得程序具有更好的可移植性 
  @Test
  public void testConnection2() throws Exception {
    //1、获取Driver的实现类对象:使用反射
    Class clazz = Class.forName("com.mysql.jdbc.Driver");
    Driver driver=(Driver) clazz.newInstance();
    //2.提供要连接的数据库
    String url="jdbc:mysql://localhost:3306/xyz";
    //3.将用户名和密码封装在Properties中
    Properties info=new Properties();
    info.setProperty("user", "root");
    info.setProperty("password", "root");
    //4.获取连接
    Connection conn=driver.connect(url, info);
    System.out.println(conn);
  }
  //方式三:使用DriverManage替换Driver
  @Test
  public void testConnection3() throws Exception {
    //1.获取Driver的实现类对象
    Class clazz = Class.forName("com.mysql.jdbc.Driver");
    Driver driver=(Driver) clazz.newInstance();
    //2.提供另外三个连接的基本信息
    String url="jdbc:mysql://localhost:3306/xyz";
    String user="root";
    String password="root";
    //注册驱动
    DriverManager.registerDriver(driver);
    //获取连接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
  }
  //方式四:可以只是加载驱动,不用显示的注册驱动了。
  @Test
  public void testConnection4() throws Exception {
    //1.提供另外三个连接的基本信息
    String url="jdbc:mysql://localhost:3306/xyz";
    String user="root";
    String password="root";
    //2.加载Driver
     Class.forName("com.mysql.jdbc.Driver");//甚至在mysql可以被省,最后不要
     //相较于方式三:可以省略如下的操作:
//    Driver driver=(Driver) clazz.newInstance();
//    //注册驱动
//    DriverManager.registerDriver(driver);
    //为什么可以省略上述的操作呢?
     /*
      * 在mysql的Driver实现类中,声明了如下的操作:
      * static{
      *   try{
      *     java.sql.DriverManager.registerDriver(new Driver());
      *   }catch(SQLException e){
      *     throw new RuntimeException("Can't register driver!");
      *   }
      * }
      * 
      * 
      */
    //3.获取连接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
  }
  //方式五(final版):将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
  /*
   * 此种方法的好处?
   * 1.实现了数据与代码的分离。实现了解耦
   * 2.如果需要修改配置文件信息,可以避免程序重新打包。 
   */
  @Test
  public void testConnection5() throws Exception {
    //1.读取配置文件的4个基本信息
    InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    Properties pros=new Properties();
    pros.load(is);
    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    String url = pros.getProperty("url");
    String driverClass = pros.getProperty("driverClass");
    //2.加载驱动
    Class.forName(driverClass);
    //3.获取连接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
  }
}

jdbc.properties(5.1.7)

user=root
password=root
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

jdbc.properties(8.0.20)

user=root
password=root
url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&userUnicode=true&characterEncoding=utf-8&autoReconnect=TRUE&useSSL=false&rewriteBatchedStatements=true
driverClass=com.mysql.cj.jdbc.Driver
jdbc.driver=com.mysql.cj.jdbc.Driver

第三章 使用PreparedStatement实现CRUD操作

3.1操作和访问数据库

数据库连接被用于向数据库服务器发送命令和SQL语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。

在java.sql包中有3个接口分别定义了对数据库的调用的不同方式:

Statement:用于执行静态SQL语句并返回它所生成结果的对象。

PrepatedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。

CallableStatement:用于执行SQL存储过程



3.2使用Statement操作数据表的弊端

  • 通过调用Connection对象的createStatement()方法创建该对象。该对象用于执行静态的SQL语句,并且返回执行结果。
  • Statement接口中定义了下列方法用于执行SQL语句:
int excuteUpdate(string sql):执行更新操作INSERT、 UPDATE、 DELETE
Resultset executeQuery(String sq1):执行查询操作SELECT

但是使用Statement操作数据表存在弊端:

问题一:存在拼串操作,繁琐

问题二:存在SQL注入问题

SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句 段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1='AND password=‘OR’1’ ='1),从而利用系统的SQL引擎完成恶意行为的做法。

对于Java而言,要防范SQL注入,只要用PreparedStatement(从Statement扩展而来)取代Statement就 可以了。

代码演示:

综上:



3.3 PreparedStatement 的使用

3.3.1 PreparedStatement 的介绍

3.3.2 PreparedStatement VS Statement

代码的可读性和可维护性。

PreparedStatement能最大可能提高性能:

DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的 编译最编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的 意义,事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一 次。

(语法检查,语义检查,翻译成二进制命令,缓存

PreparedStatement可以防止SQL注入

3.3.3 Java 与 SQL 对应数据类型转换表



3.3.4 使用 PreparedStatement 实现增、删、改操作

PreparedStatementUpdateTest.java

package com._3.preparedstatement.crud;
/*
 * 使用PreparedStatement来替换Statement,实现对数据表的增删改操作
 * 
 * 增删改:
 * 
 * 
 * 
 * 
 * 
 */
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Properties;
import org.junit.Test;
import com._3.util.JDBCUtils;
public class PreparedStatementUpdateTest {
  @Test
  public void testCommonUpdate() {
    String sql="delete from customers where id=?";
    update(sql, 3);
  }
  //通用的增删改操作
  public void update(String sql,Object ... args) {//sql中占位符的个数与可变形参的长度一致
    Connection conn=null;
    PreparedStatement ps=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for(int i=0;i<args.length;i++) {
        ps.setObject(i+1, args[i]);//小心参数声明错误
      }
      ps.execute();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps);
    }
  }
  //修改costumers表中的一条记录
  @Test
  public void testUpdate() {
    Connection conn=null;
    PreparedStatement ps=null;
    try {
      //1.获取数据库连接
      conn = JDBCUtils.getConnection();
      //2.预编译sql语句,返回PreparedStatement的实例
      String sql="update customers set name = ? where id = ? ";
      ps = conn.prepareStatement(sql);
      //3.填充占位符
      ps.setObject(1, "莫扎特");
      ps.setObject(2,18);
      //4.执行操作
      ps.execute();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      //5.资源关闭
      JDBCUtils.closeResource(conn, ps);
    }
  }
  //向表中添加一条记录
  @Test
  public void testInsert() {
    Connection conn=null;
    PreparedStatement ps=null;
    try {
      //1.读取配置文件的4个基本信息
      InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
      Properties pros=new Properties();
      pros.load(is);
      String user = pros.getProperty("user");
      String password = pros.getProperty("password");
      String url = pros.getProperty("url");
      String driverClass = pros.getProperty("driverClass");
      //2.加载驱动
      Class.forName(driverClass);
      //3.获取连接
      conn = DriverManager.getConnection(url, user, password);
//    System.out.println(conn);
      //4.预编译sql语句,返回PreparedStatement的实例
      String sql="insert into customers(name,email,birth)values(?,?,?)";//?占位符
      ps = conn.prepareStatement(sql);
      //5.填充占位符
      ps.setString(1, "哪吒");
      ps.setString(2, "nezha@gmail.com");
      SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
      java.util.Date date=sdf.parse("1000-01-01");
      ps.setDate(3, new Date(date.getTime()));
      //6.执行操作
      ps.execute();
    } catch (Exception e) {     
      e.printStackTrace();
    }finally {
      //7.资源关闭
      try {
        if (ps!=null) {
          ps.close();                 
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
      try {
        if (conn!=null) {
          conn.close();
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
}

3.3.5 使用 PreparedStatement 实现查询操作

**CustomerForQuery **

package com._3.preparedstatement.crud;
/**
 * 
 * @Description 针对于Customers表的查询操作
 * @author jishuo Email:3063494684@qq.com
 * @version
 * @date 2021年7月28日下午3:00:07
 */
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.junit.Test;
import com._3.bean.Customer;
import com._3.util.JDBCUtils;
public class CustomerForQuery {
  @Test
  public void testQueryForCustomes() {
    String sql="select id,name,birth,email from customers where id=?";
    Customer customer = queryForCustomers(sql, 2);
    System.out.println(customer);
    String sql1="select name,email from customers where name=?";
    Customer customer1=queryForCustomers(sql1, "王菲");
    System.out.println(customer1);
  }
  /**
   * 
   * @Description 针对于customers表的通用的查询操作
   * @author jishuo 
   * @date 2021年7月28日下午3:53:20
   * @param 
   * @return
   * @throws Exception 
   */
  public Customer queryForCustomers(String sql,Object ...args) {
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i+1, args[i]);
      }
      rs = ps.executeQuery();
      //获取结果集的元数据
      ResultSetMetaData rsmd = rs.getMetaData();
      //通过ResultSetMetaData获取结果集中的列数
      int columnCount = rsmd.getColumnCount();
      if (rs.next()) {
        Customer cust=new Customer();
        //处理异或数据中的每一列
        for(int i=0;i<columnCount;i++) {
          //获取列值
          Object columnValue = rs.getObject(i+1);
          //获取每个列的列名
          String columnName = rsmd.getColumnName(i+1);
          //给cust对象指定的某个属性赋值为columnValue:通过反射
          Field field = Customer.class.getDeclaredField(columnName);
          field.setAccessible(true);
          field.set(cust,columnValue);
        }
        return cust;
      }
    }  catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps, rs);
    }
    return null;
  }
  @Test
  public void testQuery1() {
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet resultSet=null;
    try {
      conn = JDBCUtils.getConnection();
      String sql="select id,name,email,birth from customers where id=?";
      ps = conn.prepareStatement(sql);
      ps.setObject(1, 1);
      //执行,并返回结果集
      resultSet = ps.executeQuery();
      //处理结果集
      if (resultSet.next()) {//next():判断结果集的下一条是否有数据,如果有数据返回true,并指向下一条,如果没有返回false,结束
        //获取当前这条数据的各个字段值
        int id = resultSet.getInt(1);
        String name = resultSet.getString(2);
        String email = resultSet.getString(3);
        Date birth = resultSet.getDate(4);
        //方式一:
//    System.out.println("id = "+ id+",name = "+name+",email = "+email+",birth ="+birth);
        //方式二:
//    Object[] data =new Object[]{id,name,email,birth};
        //方式三:将数据封装为一个对象(推荐)
        Customer customer=new Customer(id,name,email,birth);
        System.out.println(customer);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      //关闭资源 
      JDBCUtils.closeResource(conn, ps,resultSet);
    }
  }
}

Customer

package com._3.bean;
/*
 * ORM编程思想(object relation mapping)
 * 一个数据表对应一个java类
 * 表中的一条记录对应java类的一个对象
 * 表中的一个字段对应java类的一个属性
 * 
 */
import java.sql.Date;
public class Customer {
  private int id;
  private String name;
  private String email;
  private Date birth;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public Date getBirth() {
    return birth;
  }
  public void setBirth(Date birth) {
    this.birth = birth;
  }
  public Customer(int id, String name, String email, Date birth) {
    super();
    this.id = id;
    this.name = name;
    this.email = email;
    this.birth = birth;
  }
  public Customer() {
    super();
  }
  @Override
  public String toString() {
    return "Customer [id=" + id + ", name=" + name + ", email=" + email + ", birth=" + birth + "]";
  }
}






3.4 ResultSet 与 ResultSetMetaData

3.4.1 ResultSet

3.4.2 ResultSetMetaData


OrderForQuery

package com._3.preparedstatement.crud;
/**
 * 
 * @Description 针对于Order表的通用查询操作
 * @author jishuo Email:3063494684@qq.com
 * @version
 * @date 2021年7月28日下午4:22:14
 */
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import javax.sound.midi.Soundbank;
import org.junit.Test;
import com._3.bean.Order;
import com._3.util.JDBCUtils;
public class OrderForQuery {
  /*
   * 针对于表的字段名和类的属性名不相同的情况,
   * 1.必须声明SQL时,使用类的属性名来命名字段的别名
   * 2.在使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName(),
   *  获取列的别名
   * 
   * 说明:如果sql中 没有给字段起别名,getColumnLabel()获取的就是列名
   * 
   */
  @Test
  public void testOrderForQuery() {
    String sql="select order_id orderId ,order_name orderName ,order_date orderDate from `order` where order_id=?";
    Order order = orderForQuery(sql, 1);
    System.out.println(order);
  }
  /**
   * 
   * @Description 通用的针对于order表的查询操作
   * @author jishuo 
   * @date 2021年7月28日下午4:53:56
   * @param 
   * @return
   */
  public Order orderForQuery(String sql,Object ...args){
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for(int i=0;i<args.length;i++) {
        ps.setObject(i+1, args[i]);
      }
      //执行,获取结果集
      rs = ps.executeQuery();
      //获取结果集的元数据
      ResultSetMetaData rsmd = rs.getMetaData();
      //获取列数
      int columnCount = rsmd.getColumnCount();
      if (rs.next()) {
        Order order=new Order();
        for(int i=0;i<columnCount;i++) {
          //获取每个列的列值:通过ResultSet
          Object columnValue = rs.getObject(i+1);
          //通过ResultSetMetaData
          //获取每个列的列名:getColumnName ---不推荐使用
//          String columnName = rsmd.getColumnName(i+1);
          //获取列的别名:getColumnLabel
          String columnLabel = rsmd.getColumnLabel(i+1);
          //通过反射,将对象的指定名columnName的属性赋值为指定的值
          Field field = Order.class.getDeclaredField(columnLabel);
          field.setAccessible(true);
          field.set(order, columnValue);
        }
        return order;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps, rs);
    }
    return null;
  }
  @Test
  public void testQuery1() {
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    try {
      conn = JDBCUtils.getConnection();
      String sql="select order_id,order_name,order_date from `order` where order_id=?";
      ps = conn.prepareStatement(sql);
      ps.setObject(1, 1);
      rs = ps.executeQuery();
      if (rs.next()) {
        int id = (int)rs.getObject(1);
        String name=(String)rs.getObject(2);
        Date date=(Date)rs.getObject(3);
        Order order = new Order(id,name,date);
        System.out.println(order);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn,ps,rs);
    }
  }
}

Order

package com._3.bean;
import java.sql.Date;
public class Order {
  private int orderId;
  private String orderName;
  private Date orderDate;
  public Order(int orderId, String orderName, Date orderDate) {
    super();
    this.orderId = orderId;
    this.orderName = orderName;
    this.orderDate = orderDate;
  }
  public Order() {
    super();
  }
  public int getOrderId() {
    return orderId;
  }
  public void setOrderId(int orderId) {
    this.orderId = orderId;
  }
  public String getOrderName() {
    return orderName;
  }
  public void setOrderName(String orderName) {
    this.orderName = orderName;
  }
  public Date getOrderDate() {
    return orderDate;
  }
  public void setOrderDate(Date orderDate) {
    this.orderDate = orderDate;
  }
  @Override
  public String toString() {
    return "Order [orderId=" + orderId + ", orderName=" + orderName + ", orderDate=" + orderDate + "]";
  }
}




注意 order的符号是Tab键上面那个键

3.5 资源的释放

JDBC API 小结

两种思想

  • 面向接口编程的思想
  • ORM思想(object relational mapping)
  • 一个数据表对应一个java类
  • 表中的一条记录对应java类的一个对象
  • 表中的一个字段对应java类的一个属性
  • sq|是需要结合列名和表的属性名来写。注意起别名。
  • 两种技术
  • JDBC结果集的元数据:ResultSetMetaData
  • 获取列数:getColumnCount()
  • 获取列的别名:getColumnLabel()
  • 通过反射,创建指定类的对象,获取指定的属性并赋值

章节练习










Exer1Test.java

package com._4.exer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Scanner;
import org.junit.Test;
import com._3.util.JDBCUtils;
public class Exer1Test {
  @Test
  public void testInsert() {
    Scanner scanner = new Scanner(System.in);
    System.out.print("输入用户名:");
    String name = scanner.next();
    System.out.print("输入邮箱:");
    String email = scanner.next();
    System.out.print("输入生日:");
    String birthday = scanner.next();//'1992-09-08'
    String sql="insert into customers(name,email,birth)values(?,?,?)";
    int insertCount = update(sql, name,email,birthday);
    if(insertCount>0) {
      System.out.println("添加成功");
    }else{
      System.out.println("添加失败");
    }
  }
  public int update(String sql,Object ... args) {//sql中占位符的个数与可变形参的长度一致
    Connection conn=null;
    PreparedStatement ps=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for(int i=0;i<args.length;i++) {
        ps.setObject(i+1, args[i]);//小心参数声明错误
      }
      /*
       * ps.execute();
       * 如果执行的是查询操作,有返回结果,此方法返回true;
       * 如果执行的是增删改结果,没有返回结果,此方法返回false。
       */
      //方式一:
//      return ps.execute();
      //方式二:
      return ps.executeUpdate();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps);
    }
    return 0;
  }
}

Exer2Test.java

package com._4.exer;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Scanner;
import org.junit.Test;
import com._3.util.JDBCUtils;
//课后练习2
public class Exer2Test {
  //问题1:向examstudent添加一条数据
  @Test
  public void testInsert() {
    Scanner scanner = new Scanner(System.in);
    System.out.print("四级/六级:");
    int type = scanner.nextInt();
    System.out.print("身份证号:");
    String IDcard = scanner.next();
    System.out.print("准考证号:");
    String examCard = scanner.next();
    System.out.print("学生姓名:");
    String studentName = scanner.next();
    System.out.print("所在城市:");
    String location = scanner.next();
    System.out.print("考试成绩:");
    int grade = scanner.nextInt();
    String sql="insert into examstudent(type,IDcard,examCard,studentName,location,grade)values(?,?,?,?,?,?)";
    int insertCount = update(sql, type,IDcard,examCard,studentName,location,grade);
    if (insertCount>0) {
      System.out.println("添加成功");
    }else {
      System.out.println("添加失败");
    }
  }
  public int update(String sql,Object ... args) {//sql中占位符的个数与可变形参的长度一致
    Connection conn=null;
    PreparedStatement ps=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for(int i=0;i<args.length;i++) {
        ps.setObject(i+1, args[i]);//小心参数声明错误
      }
      /*
       * ps.execute();
       * 如果执行的是查询操作,有返回结果,此方法返回true;
       * 如果执行的是增删改结果,没有返回结果,此方法返回false。
       */
      //方式一:
//      return ps.execute();
      //方式二:
      return ps.executeUpdate();
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps);
    }
    return 0;
  }
  //问题2:根据身份证号或准考证号查询学生成绩信息
  @Test
  public void queryWithIDcardOrExamCard() {
    System.out.println("请选择你要输入的类型");
    System.out.println("a.准考证号");
    System.out.println("b.身份证号");
    Scanner scanner=new Scanner(System.in);
    String selection=scanner.next();
    if("a".equalsIgnoreCase(selection)) {
      System.out.println("请输入准考证号:");
      String examCard = scanner.next();
      String sql="select FlowID flowID,Type type,IDcard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard=?";
      Student student = getInstance(Student.class, sql, examCard);
      System.out.println("=======查询结果=======");
      if (student!=null) {
        System.out.println(student);        
      }else {
        System.out.println("输入的准考证号有误");
      }
    }else if("b".equalsIgnoreCase(selection)) {
      System.out.println("请输入身份证号:");
      String IDcard = scanner.next();
      String sql="select FlowID flowID,Type type,IDcard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where IDcard=?";
      Student student = getInstance(Student.class, sql,IDcard );
      System.out.println("=======查询结果=======");
      if (student!=null) {
        System.out.println(student);        
      }else {
        System.out.println("输入的身份证号有误");
      }
    }else {
      System.out.println("你的输入有误,请重新进入程序");
    }
  }
  public <T> T getInstance (Class<T> clazz ,String sql,Object...args) {
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i+1, args[i]);
      }
      rs = ps.executeQuery();
      //获取结果集的元数据
      ResultSetMetaData rsmd = rs.getMetaData();
      //通过ResultSetMetaData获取结果集中的列数
      int columnCount = rsmd.getColumnCount();
      if (rs.next()) {
        T t = clazz.newInstance();
        //处理异或数据中的每一列
        for(int i=0;i<columnCount;i++) {
          //获取列值
          Object columnValue = rs.getObject(i+1);
          //获取每个列的列名
          String columnLabel = rsmd.getColumnLabel(i+1);
          //给t对象指定的某个属性赋值为columnValue:通过反射
          Field field = clazz.getDeclaredField(columnLabel);
          field.setAccessible(true);
          field.set(t,columnValue);
        }
        return t;
      }
    }  catch (Exception e) {
      e.printStackTrace();
    }finally {
      JDBCUtils.closeResource(conn, ps, rs);
    }
    return null;
  }
  //问题3:删除指定的学生信息
  @Test
  public void testDeleteByExamCard() {
    System.out.println("请输入学生的考号:");
    Scanner scanner = new Scanner(System.in);
    String examCard=scanner.next();
    //查询指定准考证号的学生
    String sql="select FlowID flowID,Type type,IDcard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard=?";
    Student student = getInstance(Student.class, sql, examCard);
    if (student==null) {
      System.out.println("查无此人,请重新输入");
    }else {
      String sql1="delete from examstudent where examCard=?";
      int deleteCount = update(sql1, examCard);
      if (deleteCount>0) {
        System.out.println("删除成功");   
      }
    }
  }
  //优化以后的操作
  @Test
  public void testDeleteByExamCard1() {
    System.out.println("请输入学生的考号:");
    Scanner scanner = new Scanner(System.in);
    String examCard=scanner.next();
    String sql1="delete from examstudent where examCard=?";
    int deleteCount = update(sql1, examCard);
    if (deleteCount>0) {
      System.out.println("删除成功");   
    }else {
      System.out.println("查无此人,请重新输入");
    }
  }
}

Student.java

package com._4.exer;
public class Student {
  private int flowID;
  private int type;
  private String IDcard;
  private String examCard;
  private String name;
  private String location;
  private int grade;
  public int getFlowID() {
    return flowID;
  }
  public void setFlowID(int flowID) {
    this.flowID = flowID;
  }
  public int getType() {
    return type;
  }
  public void setType(int type) {
    this.type = type;
  }
  public String getIDcard() {
    return IDcard;
  }
  public void setIDcard(String iDcard) {
    IDcard = iDcard;
  }
  public String getExamCard() {
    return examCard;
  }
  public void setExamCard(String examCard) {
    this.examCard = examCard;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getLocation() {
    return location;
  }
  public void setLocation(String location) {
    this.location = location;
  }
  public int getGrade() {
    return grade;
  }
  public Student(int flowID, int type, String iDcard, String examCard, String name, String location, int grade) {
    super();
    this.flowID = flowID;
    this.type = type;
    IDcard = iDcard;
    this.examCard = examCard;
    this.name = name;
    this.location = location;
    this.grade = grade;
  }
  public Student() {
    super();
  }
  @Override
  public String toString() {
    return info();
  }
  private String info() {
    return "流水号:"+flowID+"\n四级/六级:"+type+"\n身份证号:"+IDcard+"\n准考证号:"+examCard+
        "\n学生姓名:"+name+"\n区域:"+location+"\n成绩:"+grade;
  }
}
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
探索Java数据库连接的奥秘:JDBC技术全攻略
58 8
|
5月前
|
Java 数据库连接 API
后端开发之用Mybatis简化JDBC的开发快速入门2024及数据库连接池技术和lombok工具详解
后端开发之用Mybatis简化JDBC的开发快速入门2024及数据库连接池技术和lombok工具详解
63 3
|
5月前
|
存储 设计模式 搜索推荐
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(下)
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(下)
34 1
|
5月前
|
XML 前端开发 Java
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(上)
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(上)
31 0
|
5月前
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
【6月更文挑战第24天】Java的JDBC是连接数据库的标准,提供统一API访问多种数据库。本文涵盖JDBC的基本概念、核心组件(如DriverManager、Connection、Statement、PreparedStatement和ResultSet)和最佳实践。示例展示了如何用JDBC连接MySQL,执行查询并处理结果。最佳实践包括使用PreparedStatement防SQL注入,妥善管理资源,处理异常,使用事务以及优化性能。了解和掌握JDBC能提升数据库操作的效率和安全性。
41 0
|
5月前
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
【6月更文挑战第24天】Java的JDBC是连接Java和数据库的标准,提供统一的API访问各种数据库。核心组件包括DriverManager(加载驱动和创建连接)、Connection(表示数据库连接)、Statement(执行SQL)和PreparedStatement(参数化查询,防止SQL注入)。
32 0
|
5月前
|
SQL Java 关系型数据库
Java与数据库连接技术JDBC关键核心之PreparedStatement以及SQL注入演示解决和原理
Java与数据库连接技术JDBC关键核心之PreparedStatement以及SQL注入演示解决和原理
41 0
|
5月前
|
缓存 监控 druid
对比各大数据库连接池技术-Jdbc-Dbcp-C3p0-Druid-Hikaricp
对比各大数据库连接池技术-Jdbc-Dbcp-C3p0-Druid-Hikaricp
72 0
|
6月前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
6月前
|
SQL Java 关系型数据库
JDBC技术文章
JDBC技术文章