第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; } }