JDBC Detailed Explanation (3): Using PreparedStatement to Realize CRUD Operations (Super Detailed Explanation)



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 SQLstatements , and to receive the results returned by the database server. In fact, a database connection is a Socketconnection.

⭕ There are 3 interfaces in java.sqlthe package that define different ways of calling the database:

  • Statement: An object used to execute a static SQLstatement and return the results it generates.
  • PrepatedStatement: SQLThe statement is precompiled and stored in this object, which can be used to efficiently execute the statement multiple times.
  • CallableStatement: Used to execute SQLstored procedures

insert image description here

2. Disadvantages of using Statement to operate data tables

⭕ An object is created by Connectioncalling its method. createStatement()This object is used to execute static SQLstatements and return the execution result.

StatementThe following methods are defined in SQLthe ⭕ 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 Statementthere 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.

    • JavaFor , to prevent SQLinjection, just replace with PreparedStatement(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:

insert image description here

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 ⭕ PreparedStatementinterface is a sub-interface Statementof , which represents a precompiled SQL statement

The parameters in the SQL statement represented by the ⭕ PreparedStatementobject are represented by a question mark (?), PreparedStatementand setXxx()the method of the object is called to set these parameters.
setXxx()The method takes two parameters, the first parameter SQLis the index ( 1starting from ) of the parameter in the statement to be set, and the second is the value of the parameter in SQLthe statement

2、PreparedStatement vs Statement

⭕ Code readability and maintainability.

PreparedStatementCan improve performance as much as possible:

  • DBServerPerformance optimizations are provided for prepared statements. Because the precompiled statement may be called repeatedly, the execution code of the statement DBServercompiled 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 statementthe 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)

  • PreparedStatementprevents SQLinjection

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:

insert image description here

4.4 Use PreparedStatement to implement query operations

(1)ResultSet

⭕ The query needs to call the methodPreparedStatement , and the query result is an objectexecuteQuery()ResultSet

⭕The ResultSetobject encapsulates the result set of performing database operations in the form of a logical table, and ResultSetthe interface is provided and implemented by the database manufacturer

⭕What ResultSetis returned is actually a data table. There is a pointer pointing to the front of the first record of the data table.

⭕The ResultSetobject maintains a cursor pointing to the current data row . Initially, the cursor is before the first row, and ResultSetcan next()be moved to the next row through the object method. Call next()the method to check if the next row is valid. If valid, the method returns trueand the pointer moves down. Equivalent to a combination of Iteratorthe object's hasNext()and next()methods.

⭕ When the pointer points to a row, you getXxx(int index)can getXxx(int columnName)get the value of each column by calling or .

  • For example: getInt(1),getString("name")

  • Note: The indexes in Javathe correlation involved in interacting with the database are all from the beginning.Java API1

⭕ Common methods of ResultSet interface:

  • boolean next()
  • getString()

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-jQnvwS3y-1649036189281)(Shang Silicon Valley_Song Hongkang_JDBC.assets/1555580152530.png)]

(2)ResultSetMetaData

⭕ an object that can be used to get information about the type and properties of the columns in ResultSetthe object

ResultSetMetaData meta = rs.getMetaData();

⭕Methods ResultSetMetaDatain 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 ResultSetobject
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

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-SaSiC053-1649036189282)(Shang Silicon Valley_Song Hongkang_JDBC.assets/1555579494691.png)]

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 ResultSetthat describes , ieResultSetMetaData

Question 2: About ResultSetMetaData

⭕How to get ResultSetMetaDataResultSet : getMetaData()Just call the method
⭕Get how many columns there are in the ResultSet : ResultSetMetaDatacall getColumnCount()the method
⭕Get the alias of each column of the ResultSet : call ResultSetMetaDatathe getColumnLabel()method

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-KWNRniOf-1649036189282)(Shang Silicon Valley_Song Hongkang_JDBC.assets/1555579816884.png)]

(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: PreparedStatementThe implemented query operation can be used to replace Statementthe implemented query operation to solve the problem of Statementstring matching and SQLinjection.

4. Release of resources

⭕ Release ResultSet, Statement, Connection.

⭕Database connection ( Connection) is a very rare resource and must be released immediately after use. If Connectionit cannot be closed in time and correctly, the system will crash. ConnectionThe usage principle is to create as late as possible and release as early as possible.

⭕ It can finallybe 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

  • ORMthought ( object relational mapping)

    • A data table corresponds to a javaclass
    • A record in the table corresponds to javaan object of the class
    • A field in the table corresponds to javaan attribute of the class

sqlIt 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:

insert image description here
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:
insert image description here
Add the following data to the data table:
insert image description here
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:
insert image description here

@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
insert image description here

@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("查无此人,请重新输入");
		}
		
	}
}

Guess you like

Origin blog.csdn.net/weixin_52533007/article/details/125241916