JDBC Detailed Explanation (3): Using PreparedStatement to Realize CRUD Operations (Super Detailed Explanation)
- foreword
- 1. Operation and access to the database
- 2. Disadvantages of using Statement to operate data tables
- Three, the use of PreparedStatement
-
- 1. Introduction to PreparedStatement
- 2、PreparedStatement vs Statement
- 3. Data type conversion table corresponding to Java and SQL
- 4. Use PreparedStatement to realize add, delete and change operations
- 4. Release of resources
- 5. Summary of JDBC API
foreword
This blogger will use CSDN to record the experience and knowledge he has personally gained and learned on the way to study software development. Interested friends can pay attention to the blogger! Perhaps a person can go fast alone, but a group of people can go farther!
1. Operation and access to the database
⭕ The database connection is used to send commands and
SQL
statements , and to receive the results returned by the database server. In fact, a database connection is aSocket
connection.
⭕ There are 3 interfaces in
java.sql
the package that define different ways of calling the database:
Statement
: An object used to execute a staticSQL
statement and return the results it generates.PrepatedStatement
:SQL
The statement is precompiled and stored in this object, which can be used to efficiently execute the statement multiple times.CallableStatement
: Used to executeSQL
stored procedures
2. Disadvantages of using Statement to operate data tables
⭕ An object is created by
Connection
calling its method.createStatement()
This object is used to execute staticSQL
statements and return the execution result.
Statement
The following methods are defined inSQL
the ⭕ interface for executing statements:
method | effect |
---|---|
int excuteUpdate(String sql) |
perform an update operation INSERT , UPDATE ,DELETE |
ResultSet executeQuery(String sql) |
Execute query operationSELECT |
⭕ But
Statement
there are drawbacks to using operational data tables:
Problem 1: There is a string operation, which is cumbersome
Problem 2: There is a SQL injection problem
SQL injection is to inject illegal SQL statement segments or commands into the user input data by using some systems that do not fully check the user input data.
Such as:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'
, so as to use the system's SQL engine to complete malicious behaviors.
Java
For , to preventSQL
injection, just replace withPreparedStatement
(from extensionStatement
) .Statement
- Code demo:
public class StatementTest {
// 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
@Test
public void testLogin() {
Scanner scan = new Scanner(System.in);
System.out.print("用户名:");
String userName = scan.nextLine();
System.out.print("密 码:");
String password = scan.nextLine();
// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';
String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password
+ "'";
User user = get(sql, User.class);
if (user != null) {
System.out.println("登陆成功!");
} else {
System.out.println("用户名或密码错误!");
}
}
// 使用Statement实现对数据表的查询操作
public <T> T get(String sql, Class<T> clazz) {
T t = null;
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.加载配置文件
InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
// 2.读取配置信息
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
// 3.加载驱动
Class.forName(driverClass);
// 4.获取连接
conn = DriverManager.getConnection(url, user, password);
st = conn.createStatement();
rs = st.executeQuery(sql);
// 获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
// 获取结果集的列数
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
// //1. 获取列的名称
// String columnName = rsmd.getColumnName(i+1);
// 1. 获取列的别名
String columnName = rsmd.getColumnLabel(i + 1);
// 2. 根据列名获取对应数据表中的数据
Object columnVal = rs.getObject(columnName);
// 3. 将数据表中得到的数据,封装进对象
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnVal);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return null;
}
}
⭕ In summary:
Three, the use of PreparedStatement
1. Introduction to PreparedStatement
Connection
⭕ The objectpreparedStatement(String sql)
can be obtained by calling the method of the objectPreparedStatement
The ⭕
PreparedStatement
interface is a sub-interfaceStatement
of , which represents a precompiled SQL statement
The parameters in the SQL statement represented by the ⭕
PreparedStatement
object are represented by a question mark (?),PreparedStatement
andsetXxx()
the method of the object is called to set these parameters.
setXxx()
The method takes two parameters, the first parameterSQL
is the index (1
starting from ) of the parameter in the statement to be set, and the second is the value of the parameter inSQL
the statement
2、PreparedStatement vs Statement
⭕ Code readability and maintainability.
⭕
PreparedStatement
Can improve performance as much as possible:
DBServer
Performance optimizations are provided for prepared statements. Because the precompiled statement may be called repeatedly, the execution code of the statementDBServer
compiled by the compiler is cached, so as long as the same precompiled statement is called next time, it does not need to be compiled, as long as the parameters are directly passed to the compiler The executed statement will be executed in the execution code.In
statement
the statement, even if it is the same operation, because the data content is different, the entire statement itself cannot match, and there is no meaning of caching the statement. The fact is that no database will cache the compiled execution code of the ordinary statement. In this way, the incoming statement is compiled every time it is executed.(syntax checking, semantic checking, translation into binary commands, caching)
PreparedStatement
preventsSQL
injection
3. Data type conversion table corresponding to Java and SQL
Java type | SQL type |
---|---|
boolean |
BIT |
byte |
TINYINT |
short |
SMALLINT |
int |
INTEGER |
long |
BIGINT |
String |
CHAR,VARCHAR,LONGVARCHAR |
byte array |
BINARY , VAR BINARY |
java.sql.Date |
DATE |
java.sql.Time |
TIME |
java.sql.Timestamp |
TIMESTAMP |
4. Use PreparedStatement to realize add, delete and change operations
4.1 Add (insert) operation to the customers table
@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, "小老师ir");
ps.setString(2, "[email protected]");
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();
}
}
}
4.2 Implement the update operation for the customers table
//修改customers表的一条记录(标准)
@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);
}
}
4.3 Operations for general addition, deletion and modification of general tables
- ① Additions, deletions and modifications are common
- ②Different tables are common
//通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)
public void update(String sql,Object ... args){
Connection conn = null;
PreparedStatement ps = null;
try {
//1.获取数据库的连接
conn = JDBCUtils.getConnection();
//2.获取PreparedStatement的实例 (或:预编译sql语句)
ps = conn.prepareStatement(sql);
//3.填充占位符
for(int i = 0;i < args.length;i++){
ps.setObject(i + 1, args[i]);
}
//4.执行sql语句
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally{
//5.关闭资源
JDBCUtils.closeResource(conn, ps);
}
}
Note: When the name of the table in the database is a keyword character, it needs to be enclosed by the emphasis mark ``, such as:
4.4 Use PreparedStatement to implement query operations
(1)ResultSet
⭕ The query needs to call the method
PreparedStatement
, and the query result is an objectexecuteQuery()
ResultSet
⭕The
ResultSet
object encapsulates the result set of performing database operations in the form of a logical table, andResultSet
the interface is provided and implemented by the database manufacturer
⭕What
ResultSet
is returned is actually a data table. There is a pointer pointing to the front of the first record of the data table.
⭕The
ResultSet
object maintains a cursor pointing to the current data row . Initially, the cursor is before the first row, andResultSet
cannext()
be moved to the next row through the object method. Callnext()
the method to check if the next row is valid. If valid, the method returnstrue
and the pointer moves down. Equivalent to a combination ofIterator
the object'shasNext()
andnext()
methods.
⭕ When the pointer points to a row, you
getXxx(int index)
cangetXxx(int columnName)
get the value of each column by calling or .
For example:
getInt(1)
,getString("name")
Note: The indexes in
Java
the correlation involved in interacting with the database are all from the beginning.Java API
1
⭕ Common methods of ResultSet interface:
boolean next()
getString()
- …
(2)ResultSetMetaData
⭕ an object that can be used to get information about the type and properties of the columns in
ResultSet
the object
ResultSetMetaData meta = rs.getMetaData();
⭕Methods
ResultSetMetaData
in classes
method | describe |
---|---|
getColumnName(int column) |
Get the name of the specified column |
getColumnLabel(int column) |
Get the alias of the specified column |
getColumnCount() |
Returns the number of columns in the current ResultSet object |
getColumnTypeName(int column) |
Retrieves the database-specific type name for the specified column |
getColumnDisplaySize(int column) |
Indicates the maximum standard width of the specified column, in characters |
isNullable(int column) |
Indicates whether the values in the specified column can benull |
isAutoIncrement(int column) |
Indicates whether to automatically number specified columns so that they remain read-only |
Question 1: After getting the result set, how to know which columns are in the result set? What are the column names?
need to use an object
ResultSet
that describes , ieResultSetMetaData
Question 2: About ResultSetMetaData
⭕How to get ResultSetMetaData
ResultSet
:getMetaData()
Just call the method
⭕Get how many columns there are in the ResultSet :ResultSetMetaData
callgetColumnCount()
the method
⭕Get the alias of each column of the ResultSet : callResultSetMetaData
thegetColumnLabel()
method
(3) Code demonstration
- version 1.0: a single query operation for the customer table
@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);
}
}
- version 2.0: general query operation for customer table
@Test
public void testQueryForCustomers(){
String sql = "select id,name,birth,email from customers where id = ?";
Customer customer = queryForCustomers(sql, 13);
System.out.println(customer);
sql = "select name,email from customers where name = ?";
Customer customer1 = queryForCustomers(sql,"周杰伦");
System.out.println(customer1);
}
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
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if(rs.next()){
Customer cust = new Customer();
//处理结果集一行数据中的每一个列
for(int i = 0;i <columnCount;i++){
//获取列值
Object columValue = rs.getObject(i + 1);
//获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
//给cust对象指定的columnName属性,赋值为columValue:通过反射
Field field = Customer.class.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(cust, columValue);
}
return cust;
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
- version 3.0: general query operations for the order table (using query aliases)
/*
* 针对于表的字段名与类的属性名不相同的情况:
* 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);
}
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() --不推荐使用
//获取列的别名:getColumnLabel()
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
//通过反射,将对象指定名columnName的属性赋值为指定的值columnValue
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;
}
- version 4.0: general query operations for general tables (using query aliases)
@Test
public void testGetInstance(){
String sql = "select id,name,email from customers where id = ?";
Customer customer = getInstance(Customer.class,sql,12);
System.out.println(customer);
String sql1 = "select order_id orderId,order_name orderName from `order` where order_id = ?";
Order order = getInstance(Order.class, sql1, 1);
System.out.println(order);
}
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
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
// 处理结果集一行数据中的每一个列
for (int i = 0; i < columnCount; i++) {
// 获取列值
Object columValue = rs.getObject(i + 1);
// 获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
- version 5.0: general query operations for general tables (using query aliases)
@Test
public void testGetForList(){
String sql = "select id,name,email from customers where id < ?";
List<Customer> list = getForList(Customer.class,sql,12);
list.forEach(System.out::println);
String sql1 = "select order_id orderId,order_name orderName from `order`";
List<Order> orderList = getForList(Order.class, sql1);
orderList.forEach(System.out::println);
}
public <T> List<T> getForList(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
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
//创建集合对象
ArrayList<T> list = new ArrayList<T>();
while (rs.next()) {
T t = clazz.newInstance();
// 处理结果集一行数据中的每一个列:给t对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
// 获取列值
Object columValue = rs.getObject(i + 1);
// 获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
Description:
PreparedStatement
The implemented query operation can be used to replaceStatement
the implemented query operation to solve the problem ofStatement
string matching andSQL
injection.
4. Release of resources
⭕ Release
ResultSet
,Statement
,Connection
.
⭕Database connection (
Connection
) is a very rare resource and must be released immediately after use. IfConnection
it cannot be closed in time and correctly, the system will crash.Connection
The usage principle is to create as late as possible and release as early as possible.
⭕ It can
finally
be closed in , to ensure that resources can be closed even if other codes are abnormal.
5. Summary of JDBC API
⭕ Two minds
The idea of interface-oriented programming
ORM
thought (object relational mapping
)
- A data table corresponds to a
java
class- A record in the table corresponds to
java
an object of the class- A field in the table corresponds to
java
an attribute of the class
sql
It needs to be written in combination with the column name and the attribute name of the table. Pay attention to the alias.
⭕ Two technologies
- Metadata for JDBC result sets:
ResultSetMetaData
- Get the number of columns:
getColumnCount()
- Get the column alias:
getColumnLabel()
- Through reflection, create an object of the specified class, get the specified attribute and assign it
Exercise 1
Insert a piece of data into the table customers of the database from the console. The table structure is as follows:
Answer:
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 {
// 1.获取数据库的连接
conn = JDBCUtils.getConnection();
// 2.预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
}
// 4.执行
/*
* ps.execute():
* 如果执行的是查询操作,有返回结果,则此方法返回true;
* 如果执行的是增、删、改操作,没有返回结果,则此方法返回false.
*/
//方式一:
// return ps.execute();
//方式二:
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.资源的关闭
JDBCUtils.closeResource(conn, ps);
}
return 0;
}
}
Exercise 2
Create the database table examstudent, the table structure is as follows:
Add the following data to the data table:
Code implementation 1: Insert a new student information
Please enter candidate details
Type: IDCard: ExamCard: StudentName: Location: Grade:
Information entered successfully!
Answer:
@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 {
// 1.获取数据库的连接
conn = JDBCUtils.getConnection();
// 2.预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
}
// 4.执行
/*
* ps.execute():
* 如果执行的是查询操作,有返回结果,则此方法返回true;
* 如果执行的是增、删、改操作,没有返回结果,则此方法返回false.
*/
// 方式一:
// return ps.execute();
// 方式二:
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.资源的关闭
JDBCUtils.closeResource(conn, ps);
}
return 0;
}
Code implementation 2: Create a java program in eclipse: Enter the ID card number or admission ticket number to query the basic information of the students. The result is as follows:
@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)){
//if(selection.equalsIgnoreCase("a")){
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);
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);
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
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
// 处理结果集一行数据中的每一个列
for (int i = 0; i < columnCount; i++) {
// 获取列值
Object columValue = rs.getObject(i + 1);
// 获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
Code implementation 3: complete the delete function of student information
@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 sql = "delete from examstudent where examCard = ?";
int deleteCount = update(sql, examCard);
if(deleteCount > 0){
System.out.println("删除成功");
}else{
System.out.println("查无此人,请重新输入");
}
}
}