Java

Java Statement class

승모근뭉치 2023. 2. 6. 21:43

프로젝트 내 src 내 javabasic 패키지 내 Ex8SelectPerson.java

package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

/*
 * 번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균 <=이 순서로 출력
 * 
 * 이때
 * 총점 평균은 자바에서 자바점수와 스프링 점수를 가져온다음에 계산해서 출력
 * 혈액형은 대문자로 출력후 뒤에 '형'을 붙여서 출력
 * 
 * 전체 데이타 출력후
 * 
 * 자바점수의 전체 평균 : 78.9 (예)
 * 스프링점수의 전체 평균 : 89.7
 */
public class Ex8SelectPerson {

	public Ex8SelectPerson() {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// System.out.println("오라클 드라이버 클래스 성공");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("오라클 드라이버가 없어요:" + e.getMessage());
		}
	}

	// public void selectPerson()
	// {
	// String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	// String sql="select * from person2";
	//
	// Connection conn=null;
	// Statement stmt=null;
	// ResultSet rs=null;
	//
	// try {
	// conn=DriverManager.getConnection(url, "사용자이름", "a1234");
	// stmt=conn.createStatement();
	// rs=stmt.executeQuery(sql);
	// int tot=0;
	// double avg=0.0;
	//
	// System.out.printf("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균\n");
	//
	//
	// while(rs.next())
	// {
	// int number=rs.getInt(1);
	// String name=rs.getString(2);
	//
	// String blood=(rs.getString(3)).toUpperCase();
	//
	// float height=rs.getFloat(6);
	// Date birthDay=rs.getDate("birthday");
	// int java=rs.getInt("java");
	// int spring=rs.getInt("spring");
	// tot=java+spring;
	// avg=tot/2.0;
	//
	// System.out.printf(number+"\t"+name+"\t"+blood+"형\t"+height+"\t"+birthDay+"\t"+java+"\t"+spring+"\t"+tot+"\t"+avg+"\n");
	//
	// }
	//
	// sql="select round(avg(java),1) java,round(avg(spring),1) spring from
	// person2";
	//
	// rs=stmt.executeQuery(sql);
	// System.out.printf("\n");
	// while(rs.next())
	// {
	// float java=rs.getFloat("java");
	// float spring=rs.getFloat("spring");
	//
	// System.out.printf("자바점수의 전체 평균 : "+java+"\n");
	// System.out.printf("스프링점수의 전체 평균 : "+spring+"\n");
	// }
	// } catch (SQLException e) {
	// // TODO Auto-generated catch block
	// System.out.println("오류 : "+e.getMessage());
	// } finally {
	// try {
	// if(rs!=null) rs.close();
	// if(stmt!=null) stmt.close();
	// if(conn!=null) conn.close();
	// }catch (SQLException e) {
	// // TODO: handle exception
	// }
	// }
	//
	//
	// }

	public void writePerson() {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
		String sql = "select * from person2";
		System.out.println("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균");
		System.out.println("----------------------------------------------------------------------------");

		try {
			conn = DriverManager.getConnection(url, "사용자이름", "a1234");
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);
			while (rs.next()) {
				String num = rs.getString("num");
				String name = rs.getString("name");
				String blood = rs.getString("blood");
				int java = rs.getInt("java");
				int spring = rs.getInt("spring");
				double height = rs.getDouble("height");
				Date birthday = rs.getDate("birthday");
				int tot = java + spring;
				double avg = tot / 2.0;
				System.out.println(num + "\t" + name + "\t" + blood.toUpperCase() + "형\t" + height + "\t" + birthday
						+ "\t" + java + "\t" + spring + "\t" + tot + "\t" + avg);
			}
			System.out.println();
			sql = "select round(avg(java),1) avgjava,round(avg(spring),1) avgspring from person2";
			rs = stmt.executeQuery(sql);
			if (rs.next()) {
				double avgjava = rs.getDouble("avgjava");
				double avgspring = rs.getDouble("avgspring");
				System.out.println("자바점수의 전체 평균:" + avgjava);
				System.out.println("스프링점수의 전체 평균:" + avgspring);

			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.println("오류:" + e.getMessage());
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (stmt != null)
					stmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO: handle exception
			}
		}

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex8SelectPerson ex = new Ex8SelectPerson();
		// ex.selectPerson();
		ex.writePerson();
	}

}
번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균
----------------------------------------------------------------------------
4	이미자	AB형	156.8	1978-12-20	100	90	190	95.0
5	김미자	O형	167.2	1988-02-12	98	70	168	84.0
7	김철수	AB형	156.9	2001-12-12	88	90	178	89.0
8	이승기	B형	187.2	1982-08-30	90	79	169	84.5
10	나엄형	O형	145.3	1999-09-12	30	20	50	25.0
11	안노오	A형	166.3	2002-04-02	90	100	190	95.0
28	손호남	B형	167.9	2020-09-23	8	9	17	8.5
29	이순자	O형	156.8	2020-09-23	78	56	134	67.0
31	안소니	B형	189.2	1989-11-11	89	99	188	94.0
33	제니퍼	A형	155.8	1990-12-25	89	90	179	89.5
41	마이리	AB형	100.2	0086-11-11	50	20	70	35.0
27	남희석	O형	189.1	2020-09-23	56	78	134	67.0
39	용주리	AB형	300.2	1986-01-29	44	22	66	33.0
40	구형구	O형	302.1	1985-01-11	100	100	200	100.0
42	이태리	AB형	167.0	1978-11-12	67	78	145	72.5

자바점수의 전체 평균:71.8
스프링점수의 전체 평균:66.7

위 코드를 본다.

try 블록 안에 

rs = stmt.executeQuery(sql);

...

rs = stmt.executeQuery(sql);

요 문이 두 번 쓰였다.

 

코드에 경고 표시가 뜬다.

Resource leak: 'rs' is not closed at this location

 

finally 블록을 보면

if (rs != null)
	rs.close();

위 코드 처럼 분명히 자원을 닫아 주었는데도 경고가 뜬다.

 

위 코드에 추가를 해본다.

프로젝트 내 src 내 javabasic 패키지 내 Ex8SelectPerson.java

package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

/*
 * 번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균 <=이 순서로 출력
 * 
 * 이때
 * 총점 평균은 자바에서 자바점수와 스프링 점수를 가져온다음에 계산해서 출력
 * 혈액형은 대문자로 출력후 뒤에 '형'을 붙여서 출력
 * 
 * 전체 데이타 출력후
 * 
 * 자바점수의 전체 평균 : 78.9 (예)
 * 스프링점수의 전체 평균 : 89.7
 */
public class Ex8SelectPerson {

	public Ex8SelectPerson() {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// System.out.println("오라클 드라이버 클래스 성공");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("오라클 드라이버가 없어요:" + e.getMessage());
		}
	}

	// public void selectPerson()
	// {
	// String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	// String sql="select * from person2";
	//
	// Connection conn=null;
	// Statement stmt=null;
	// ResultSet rs=null;
	//
	// try {
	// conn=DriverManager.getConnection(url, "사용자이름", "a1234");
	// stmt=conn.createStatement();
	// rs=stmt.executeQuery(sql);
	// int tot=0;
	// double avg=0.0;
	//
	// System.out.printf("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균\n");
	//
	//
	// while(rs.next())
	// {
	// int number=rs.getInt(1);
	// String name=rs.getString(2);
	//
	// String blood=(rs.getString(3)).toUpperCase();
	//
	// float height=rs.getFloat(6);
	// Date birthDay=rs.getDate("birthday");
	// int java=rs.getInt("java");
	// int spring=rs.getInt("spring");
	// tot=java+spring;
	// avg=tot/2.0;
	//
	// System.out.printf(number+"\t"+name+"\t"+blood+"형\t"+height+"\t"+birthDay+"\t"+java+"\t"+spring+"\t"+tot+"\t"+avg+"\n");
	//
	// }
	//
	// sql="select round(avg(java),1) java,round(avg(spring),1) spring from
	// person2";
	//
	// rs=stmt.executeQuery(sql);
	// System.out.printf("\n");
	// while(rs.next())
	// {
	// float java=rs.getFloat("java");
	// float spring=rs.getFloat("spring");
	//
	// System.out.printf("자바점수의 전체 평균 : "+java+"\n");
	// System.out.printf("스프링점수의 전체 평균 : "+spring+"\n");
	// }
	// } catch (SQLException e) {
	// // TODO Auto-generated catch block
	// System.out.println("오류 : "+e.getMessage());
	// } finally {
	// try {
	// if(rs!=null) rs.close();
	// if(stmt!=null) stmt.close();
	// if(conn!=null) conn.close();
	// }catch (SQLException e) {
	// // TODO: handle exception
	// }
	// }
	//
	//
	// }

	public void writePerson() {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
		String sql = "select * from person2";
		System.out.println("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균");
		System.out.println("----------------------------------------------------------------------------");

		try {
			conn = DriverManager.getConnection(url, "사용자이름", "a1234");
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);
			while (rs.next()) {
				String num = rs.getString("num");
				String name = rs.getString("name");
				String blood = rs.getString("blood");
				int java = rs.getInt("java");
				int spring = rs.getInt("spring");
				double height = rs.getDouble("height");
				Date birthday = rs.getDate("birthday");
				int tot = java + spring;
				double avg = tot / 2.0;
				System.out.println(num + "\t" + name + "\t" + blood.toUpperCase() + "형\t" + height + "\t" + birthday
						+ "\t" + java + "\t" + spring + "\t" + tot + "\t" + avg);
			}
			System.out.println();
			sql = "select round(avg(java),1) avgjava,round(avg(spring),1) avgspring from person2";
			rs = stmt.executeQuery(sql);
			if (rs.next()) {
				double avgjava = rs.getDouble("avgjava");
				double avgspring = rs.getDouble("avgspring");
				System.out.println("자바점수의 전체 평균:" + avgjava);
				System.out.println("스프링점수의 전체 평균:" + avgspring);

			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.println("오류:" + e.getMessage());
		} finally {
			try {
//				if (rs != null)
//					rs.close();
				if (rs != null) {
					rs.close();
					System.out.println("ResultSet 자원을 닫았습니까? : " + rs.isClosed());
				}
				if (stmt != null)
					stmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO: handle exception
			}
		}

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex8SelectPerson ex = new Ex8SelectPerson();
		// ex.selectPerson();
		ex.writePerson();
	}

}

다음과 같이 한 줄을 추가하였다.

if (rs != null) {
    rs.close();
    System.out.println("ResultSet 자원을 닫았습니까? : " + rs.isClosed());
}

실행 결과

번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균
----------------------------------------------------------------------------
4	이미자	AB형	156.8	1978-12-20	100	90	190	95.0
5	김미자	O형	167.2	1988-02-12	98	70	168	84.0
7	김철수	AB형	156.9	2001-12-12	88	90	178	89.0
8	이승기	B형	187.2	1982-08-30	90	79	169	84.5
10	나엄형	O형	145.3	1999-09-12	30	20	50	25.0
11	안노오	A형	166.3	2002-04-02	90	100	190	95.0
28	손호남	B형	167.9	2020-09-23	8	9	17	8.5
29	이순자	O형	156.8	2020-09-23	78	56	134	67.0
31	안소니	B형	189.2	1989-11-11	89	99	188	94.0
33	제니퍼	A형	155.8	1990-12-25	89	90	179	89.5
41	마이리	AB형	100.2	0086-11-11	50	20	70	35.0
27	남희석	O형	189.1	2020-09-23	56	78	134	67.0
39	용주리	AB형	300.2	1986-01-29	44	22	66	33.0
40	구형구	O형	302.1	1985-01-11	100	100	200	100.0
42	이태리	AB형	167.0	1978-11-12	67	78	145	72.5

자바점수의 전체 평균:71.8
스프링점수의 전체 평균:66.7
ResultSet 자원을 닫았습니까? : true

ResultSet 자원은 닫혔다고 결과를 출력한다.

그러므로 runtime 에서 resource leak (자원 누수) 은 없다.

그러나 compiler 가 JDBC 표준을 모른다.

try-with-resources 구문을 생각해본다.

ResultSet 자원은 AutoCloseable 인터페이스를 구현하여 try 구문이 종료 될 때 close() 메서드를 호출하게 된다.

하지만, JDBC 를 쓸 때의 JDBC 표준 관점에서 생각하지 말고, 일반 Java 프로그래밍을 할 때의 관점으로 생각하면 위 코드에서는 resource leak (자원 누수) 가 있다. 왜냐하면 만약에 첫 번째 rs = stmt.executeQuery(sql); 문이 실행될 때 

executeQuery(String sql) 메서드 자체는 SQLException 을 발생시킬 수 있는 가능성이 있어서 SQLException 이 발생되면

catch 절로 간 후에 finally 절로 가서 rs.close(); 로 자원을 닫게 된다. 하지만 두번째 rs = stmt.executeQuery(sql); 를 실행하면 먼저 executeQuery(sql) 메서드를 실행하게 된다. 그런데 executeQuery(String sql) 메서드는 주어진 String sql 문을 실행하고 그 결과 한 개의 단일 ResultSet 객체를 반환한다. 첫 번째 rs = stmt.executeQuery(sql); 문을 실행시켰을 때 rs 변수가 참조하는 주소와 두 번째 rs = stmt.executeQuery(sql); 문을 실행시켰을 때 rs 변수가 참조하는 주소가 다른 듯 하다..

그래서 첫 번째 rs = stmt.executeQuery(sql); 에서 예외가 발생 시 finally 절로 갔을 때 첫 번째 받은 ResultSet 객체에 대한 자원 해제는 했지만 두 번째 rs = stmt.executeQuery(sql); 문에서 예외 발생 시 그에 대한 ResultSet 객체에 대한 자원처리는 안되니 JDBC 입장이 아닌 Java 프로그래밍 입장에서는 경고를 낼 수 밖에 없다. 

첫 번째 rs = stmt.executeQuery(sql); 문과 두 번째 rs = stmt.executeQuery(sql); 문 둘다 성공적으로 처리 되어 SQLException 이 나지 않는다면 첫 번째 문에서 나온 ResultSet 객체와 두 번째 문에서 참조하게 되는 ResultSet 객체 요렇게 두 ResultSet 객체가 생겨 나는 듯 하다.. 그래서 ResultSet 객체 자원이 두개가 되어서 둘 다 닫아야 하지만, finally 에서 결국 닫아야 하는 것은 rs 변수로 표현할 수 있으니 나머지 한 개의 ResultSet 자원이 안닫혀서 resource leak (자원 누수) 가 난다. 그래서 try-catch-finally 구문 보다는 try-with-resources 구문을 쓰는 것이 좋다. 컴파일러는 JDBC 입장에서 생각하지 않기 때문이다. 즉, 위 코드는 Java 프로그래밍 입장에서 보자면 잘못되었다. JDBC 입장에서 보자면 위 코드는 맞다. 그래서 경고가 뜰 때 Add @SuppressWarnings 'resource' to 'writePerson()' 을 써서 경고 문제를 고치라는 조언이 나온다. 때때로 이렇게 컴파일러는 잘못 해석한다.

 

위의 코드를 바꾸어 본다.

프로젝트 내 src 내 javabasic 패키지 내 Ex8SelectPerson.java

package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

/*
 * 번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균 <=이 순서로 출력
 * 
 * 이때
 * 총점 평균은 자바에서 자바점수와 스프링 점수를 가져온다음에 계산해서 출력
 * 혈액형은 대문자로 출력후 뒤에 '형'을 붙여서 출력
 * 
 * 전체 데이타 출력후
 * 
 * 자바점수의 전체 평균 : 78.9 (예)
 * 스프링점수의 전체 평균 : 89.7
 */
public class Ex8SelectPerson {

	public Ex8SelectPerson() {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// System.out.println("오라클 드라이버 클래스 성공");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("오라클 드라이버가 없어요:" + e.getMessage());
		}
	}

	// public void selectPerson()
	// {
	// String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	// String sql="select * from person2";
	//
	// Connection conn=null;
	// Statement stmt=null;
	// ResultSet rs=null;
	//
	// try {
	// conn=DriverManager.getConnection(url, "사용자이름", "a1234");
	// stmt=conn.createStatement();
	// rs=stmt.executeQuery(sql);
	// int tot=0;
	// double avg=0.0;
	//
	// System.out.printf("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균\n");
	//
	//
	// while(rs.next())
	// {
	// int number=rs.getInt(1);
	// String name=rs.getString(2);
	//
	// String blood=(rs.getString(3)).toUpperCase();
	//
	// float height=rs.getFloat(6);
	// Date birthDay=rs.getDate("birthday");
	// int java=rs.getInt("java");
	// int spring=rs.getInt("spring");
	// tot=java+spring;
	// avg=tot/2.0;
	//
	// System.out.printf(number+"\t"+name+"\t"+blood+"형\t"+height+"\t"+birthDay+"\t"+java+"\t"+spring+"\t"+tot+"\t"+avg+"\n");
	//
	// }
	//
	// sql="select round(avg(java),1) java,round(avg(spring),1) spring from
	// person2";
	//
	// rs=stmt.executeQuery(sql);
	// System.out.printf("\n");
	// while(rs.next())
	// {
	// float java=rs.getFloat("java");
	// float spring=rs.getFloat("spring");
	//
	// System.out.printf("자바점수의 전체 평균 : "+java+"\n");
	// System.out.printf("스프링점수의 전체 평균 : "+spring+"\n");
	// }
	// } catch (SQLException e) {
	// // TODO Auto-generated catch block
	// System.out.println("오류 : "+e.getMessage());
	// } finally {
	// try {
	// if(rs!=null) rs.close();
	// if(stmt!=null) stmt.close();
	// if(conn!=null) conn.close();
	// }catch (SQLException e) {
	// // TODO: handle exception
	// }
	// }
	//
	//
	// }

	public void writePerson() {
//		Connection conn = null;
//		Statement stmt = null;
//		ResultSet rs = null;
//		String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
//		String sql = "select * from person2";
//		System.out.println("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균");
//		System.out.println("----------------------------------------------------------------------------");

//		try {
//			conn = DriverManager.getConnection(url, "사용자이름", "a1234");
//			stmt = conn.createStatement();
//			rs = stmt.executeQuery(sql);
//			while (rs.next()) {
//				String num = rs.getString("num");
//				String name = rs.getString("name");
//				String blood = rs.getString("blood");
//				int java = rs.getInt("java");
//				int spring = rs.getInt("spring");
//				double height = rs.getDouble("height");
//				Date birthday = rs.getDate("birthday");
//				int tot = java + spring;
//				double avg = tot / 2.0;
//				System.out.println(num + "\t" + name + "\t" + blood.toUpperCase() + "형\t" + height + "\t" + birthday
//						+ "\t" + java + "\t" + spring + "\t" + tot + "\t" + avg);
//			}
//			System.out.println();
//			sql = "select round(avg(java),1) avgjava,round(avg(spring),1) avgspring from person2";
//			rs = stmt.executeQuery(sql);
//			if (rs.next()) {
//				double avgjava = rs.getDouble("avgjava");
//				double avgspring = rs.getDouble("avgspring");
//				System.out.println("자바점수의 전체 평균:" + avgjava);
//				System.out.println("스프링점수의 전체 평균:" + avgspring);
//
//			}
//
//		} catch (SQLException e) {
//			// TODO Auto-generated catch block
//			System.out.println("오류:" + e.getMessage());
//		} finally {
//			try {
////				if (rs != null)
////					rs.close();
//				if (rs != null) {
//					rs.close();
//					System.out.println("ResultSet 자원을 닫았습니까? : " + rs.isClosed());
//				}
//				if (stmt != null)
//					stmt.close();
//				if (conn != null)
//					conn.close();
//			} catch (SQLException e) {
//				// TODO: handle exception
//			}
//		}

		String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
		String sql = "select * from person2";
		System.out.println("번호\t이름\t혈액형\t키\t생년월일\t자바\t스프링\t총점\t평균");
		System.out.println("----------------------------------------------------------------------------");
		
		try (
				Connection conn = DriverManager.getConnection(url, "사용자이름", "a1234");
				Statement stmt = conn.createStatement();
		) {
			ResultSet rs = stmt.executeQuery(sql);				
			while (rs.next()) {
				String num = rs.getString("num");
				String name = rs.getString("name");
				String blood = rs.getString("blood");
				int java = rs.getInt("java");
				int spring = rs.getInt("spring");
				double height = rs.getDouble("height");
				Date birthday = rs.getDate("birthday");
				int tot = java + spring;
				double avg = tot / 2.0;
				System.out.println(num + "\t" + name + "\t" + blood.toUpperCase() + "형\t" + height + "\t" + birthday
						+ "\t" + java + "\t" + spring + "\t" + tot + "\t" + avg);
			}
			System.out.println();
			sql = "select round(avg(java),1) avgjava,round(avg(spring),1) avgspring from person2";
			// 아랫줄은 JDK 7 과 JDK 8 에서 오류가 난다.
			// try (...) {...} 구문에서 (...) 안에 선언한 변수는 implicitly final (암묵적으로 final) 이다.
			// 그래서 OpenJDK 11 로 올려서 
//			Connection conn = DriverManager.getConnection(url, "angel", "a1234");
//			Statement stmt = conn.createStatement();
//			ResultSet rs = stmt.executeQuery(sql);
			// 위 세줄을 try 구문 밖에다 쓰고 try (...) {...} 구문 중에 (...) 요 괄호 안에다가 변수를 썼다.
			// try ( conn; stmt; rs; ) {...} 요런식으로 썼다. 그 후에 try ( conn; stmt; rs; ) {...rs = stmt.executeQuery(sql);...} 과 같이 써봤지만
			// 오류가 났다. 그래서,
			// ResultSet rs = stmt.executeQuery(sql); 문을 try (...) {...ResultSet rs = stmt.executeQuery(sql);...} try 블록 안에 쓰던가
			// 두번째로 rs = stmt.executeQuery(sql); 문을 써서 대입할 때 다음과 같이
			// ResultSet rs2 = stmt.executeQuery(sql);
			// 아예 다른 변수이름으로 선언하고 할당하던지 해서 rs2 를 따로 닫는다.
			rs = stmt.executeQuery(sql); // 오류 : The resource rs of a try-with-resources statement cannot be assigned
			
			if (rs.next()) {
				double avgjava = rs.getDouble("avgjava");
				double avgspring = rs.getDouble("avgspring");
				System.out.println("자바점수의 전체 평균:" + avgjava);
				System.out.println("스프링점수의 전체 평균:" + avgspring);

			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.println("오류:" + e.getMessage());
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex8SelectPerson ex = new Ex8SelectPerson();
		// ex.selectPerson();
		ex.writePerson();
	}

}
번호	이름	혈액형	키	생년월일	자바	스프링	총점	평균
----------------------------------------------------------------------------
4	이미자	AB형	156.8	1978-12-20	100	90	190	95.0
5	김미자	O형	167.2	1988-02-12	98	70	168	84.0
7	김철수	AB형	156.9	2001-12-12	88	90	178	89.0
8	이승기	B형	187.2	1982-08-30	90	79	169	84.5
10	나엄형	O형	145.3	1999-09-12	30	20	50	25.0
11	안노오	A형	166.3	2002-04-02	90	100	190	95.0
28	손호남	B형	167.9	2020-09-23	8	9	17	8.5
29	이순자	O형	156.8	2020-09-23	78	56	134	67.0
31	안소니	B형	189.2	1989-11-11	89	99	188	94.0
33	제니퍼	A형	155.8	1990-12-25	89	90	179	89.5
41	마이리	AB형	100.2	0086-11-11	50	20	70	35.0
27	남희석	O형	189.1	2020-09-23	56	78	134	67.0
39	용주리	AB형	300.2	1986-01-29	44	22	66	33.0
40	구형구	O형	302.1	1985-01-11	100	100	200	100.0
42	이태리	AB형	167.0	1978-11-12	67	78	145	72.5

자바점수의 전체 평균:71.8
스프링점수의 전체 평균:66.7

위 코드에서는 try-with-resources 구문을 썼으나

ResultSet 인스턴스 변수 rs 자원을 닫지 않았다.

위의 코드에서 rs = stmt.executeQuery(sql); 문처럼

재대입하지 말고,

 

ResultSet rs = stmt.executeQuery(sql); 문과

ResultSet rs2 = stmt.executeQuery(sql); 문을 try (...) 괄호안에 두 줄 추가하고

if (rs2.next()) {
   double avgjava = rs.getDouble("avgjava");
   double avgspring = rs.getDouble("avgspring");
   System.out.println("자바점수의 전체 평균:" + avgjava);
   System.out.println("스프링점수의 전체 평균:" + avgspring);
}

위의 if 구문에서

rs2.next() 로 조건문을 쓸 수 있다.