<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>삽질화장이</title>
    <link>https://sapwha.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 21:39:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>볼뭉치</managingEditor>
    <item>
      <title>Java setAutoCommit(boolean autoCommit)</title>
      <link>https://sapwha.tistory.com/574</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 DbConn.java&lt;/p&gt;
&lt;pre id=&quot;code_1683643817350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

public class DbConn { // DbManager 역할하는 클래스

	private static Connection dbConn; // 멤버로 선언

	public static Connection getConnection() {
		if (dbConn == null) {
			try {
				String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
				String user = &quot;scott&quot;;
				String pwd = &quot;a1234&quot;;

				Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;); // 클래스에 동적으로 바인딩하는 부분
				dbConn = DriverManager.getConnection(url, user, pwd);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println(e.toString());
			}
		} // end of if
		return dbConn;
	}// getConnection()

	public static Connection getConnection(String url, String user, String pwd) {
		if (dbConn != null) {
			try {
				Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
				dbConn = DriverManager.getConnection(url, user, pwd);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return dbConn;
	}

	public static void dbClose() {
		if (dbConn != null) {
			try {
				if (!dbConn.isClosed())
					dbConn.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		dbConn = null; // 초기화하지 않으면 다시 사용할 수가 없기 때문에 꼭 실행함
	}

	public static void dbClose(PreparedStatement ps, Connection conn) {
		try {
			if (ps != null)
				ps.close();
			if (conn != null)
				conn.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		conn = null;
		ps = null; // 항상 자원을 반납 후 널값 처리 해줌
	}

	public static void dbClose(Statement st, Connection conn) {
		try {
			if (st != null)
				st.close();
			if (conn != null)
				conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		conn = null;
		st = null;
	}

	public static void dbClose(ResultSet rs, PreparedStatement ps, Connection conn) {
		try {
			if (rs != null)
				rs.close();
			if (ps != null)
				ps.close();
			if (conn != null)
				conn.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		rs = null;
		ps = null;
		conn = null; // 항상 자원을 반납 후 널값 처리 해줌
	}

	public static void dbClose(ResultSet rs, Statement st, Connection conn) {
		try {
			if (rs != null)
				rs.close();
			if (st != null)
				st.close();
			if (conn != null)
				conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		conn = null;
		st = null;
		rs = null;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 TsDTO.java&lt;/p&gt;
&lt;pre id=&quot;code_1683643287732&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

public class TsDTO {
	//멤버를 데이타베이스의 필드로 설정 생성한 테이블의 필드를 모두 변수로 선언
		//tr1, tr2, tr3 테이블의 필드(열, 컬럼)를 변수로 선언
		//private은캡슐화
		private String id, name, birthday, tel;	//아이디, 이름, 생년월일,
												//전화번호
		//멤버변수에 데이터를 입출력 하는 전용 메소드 : getter, setter 메소드

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getBirthday() {
			return birthday;
		}

		public void setBirthday(String birthday) {
			this.birthday = birthday;
		}

		public String getTel() {
			return tel;
		}

		public void setTel(String tel) {
			this.tel = tel;
		}
		
		//toString메소드 오버라이딩
		@Override
		public String toString() {
			return String.format(&quot;%s %s %s %s&quot;, id, name, birthday, tel);
		}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 TsDAO.java&lt;/p&gt;
&lt;pre id=&quot;code_1683643345050&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

public class TsDAO {
	Connection conn;
	Statement stmt;
	
	//전체 출력
	public ArrayList&amp;lt;TsDTO&amp;gt; outputData() {
		ArrayList&amp;lt;TsDTO&amp;gt; lists = new ArrayList&amp;lt;TsDTO&amp;gt;();
		
		try {
			conn = DbConn.getConnection();
			stmt = conn.createStatement();
			String query = &quot;select tr1.id, name, TO_CHAR(birthday,'YYYY-MM-DD') as birthday, tel&quot;
					+ &quot; from tr1, tr2, tr3&quot;
					+ &quot; where tr1.id=tr2.id&quot;
					+ &quot; and tr1.id=tr3.id&quot;
					+ &quot; order by tr1.id asc&quot;;	//3개으테이블을 조인처리
			
			ResultSet rs = stmt.executeQuery(query);
			
			while(rs.next()) {
				TsDTO dto = new TsDTO();
				dto.setId(rs.getString(&quot;id&quot;));
				dto.setName(rs.getString(&quot;name&quot;));
				dto.setBirthday(rs.getString(&quot;birthday&quot;));
				dto.setTel(rs.getString(&quot;tel&quot;));
				lists.add(dto);	//TsDTO라는 하나의묶음객체, 패키지화됨.추가
				//레코드가추가되면 DTO 형태로 묶어놓고 추가함
			}
			rs.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DbConn.dbClose();
		return lists;
	}//outputData()
	
	//트랜잭션 처리 안된 입력 메소드, 커밋과 롤백을 적용할 수 없다.
	public int notTs_in(TsDTO dto) {
		
		int result=0;
		try {
			conn = DbConn.getConnection();
			//tr1테이블에 입력
			String query = String.format(&quot;insert into tr1(id, name) values('%s','%s')&quot;,
					dto.getId(), dto.getName());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
			
			//tr2테이블에 입력
			query = String.format(&quot;insert into tr2(id, birthday) values('%s','%s')&quot;,
					dto.getId(), dto.getBirthday());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
			
			//tr3테이블에 입력
			query = String.format(&quot;insert into tr3(id, tel) values('%s','%s')&quot;,
					dto.getId(), dto.getTel());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.println(e.toString());
			result = 0;	//결과는 에러발생했을 경우 다시 0으로 처리
		}
		return result;
	}//notTs_in()
	
	//트랜잭션 처리가된 입력 메소드
	public int ts_in(TsDTO dto) {
		int result=0;
		try {
			conn = DbConn.getConnection();
			
			//트랜잭션 시작-------------------------
			conn.setAutoCommit(false);//이제부터 밑에는 에라가 있으면 DB 에 반영이안된다
			//에라가 없으면 커밋이 수행된다, 밑에 DML 부분은 하나의 트랜잭션이 된다
			
			//tr1테이블에 입력
			String query = String.format(&quot;insert into tr1(id, name) values('%s','%s')&quot;,
					dto.getId(), dto.getName());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
			
			//tr2테이블에 입력
			query = String.format(&quot;insert into tr2(id, birthday) values('%s','%s')&quot;,
					dto.getId(), dto.getBirthday());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
			
			//tr3테이블에 입력
			//tr3에서 오류가 나면 나머지 tr1 tr2 가 취소가 되야지 트랜잭션
			//3개의 DML를 한꺼번에 하나의 트랜잭션으로 설정하겠다
			//tr3에서 난 오류가 있지만 tr1, tr2 테이블에는 값이 전달 되었다.
			query = String.format(&quot;insert into tr3(id, tel) values('%s','%s')&quot;,
					dto.getId(), dto.getTel());	//오라클과 자바에서 쓰는 %의미가 다르므로 홑따옴표 처리
			
			stmt = conn.createStatement();
			result = stmt.executeUpdate(query);
			stmt.close();
			
			conn.commit();//setAutoCommit메소드부터 여기까지 하나의 통트랜잭션
			//동시에 tr1, tr2, tr3 테이블에 반영이 될때만 하나의 트랜잭션이 성사,거래가 이루어지는것
			//트랜잭션 끝-------------------------
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			try {
				//에러발생시 앞에 내렸던 명령은 모두 취소된다
				conn.rollback();
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				System.out.println(e1.toString());
			}
			System.out.println(e.toString());
			result = 0;
		}
		return result;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 TsProcess.java&lt;/p&gt;
&lt;pre id=&quot;code_1683643426641&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;

public class TsProcess {
	
	//select 문의 조회결과를 확인하기 위한 메소드
		public void selectData() {
			TsDAO dao = new TsDAO();
			ArrayList&amp;lt;TsDTO&amp;gt; lists = dao.outputData();

			Iterator&amp;lt;TsDTO&amp;gt; it = lists.iterator();
			while(it.hasNext()) {
				TsDTO dto = it.next();
				System.out.println(dto.toString());
			}
		}

		//사용자 데이터 입력을 통해 데이타베이스에 반영하는 메소드(트랜잭션 처리불)
		public void insertData1() {
			TsDAO dao = new TsDAO();
			TsDTO dto = new TsDTO();

			//BufferedReader를 통해 입력값을 전달한다
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			//불러와서 버퍼를 이용. 입력을 받아야 하니 화면에
			try {
				System.out.println(&quot;아이디 입력: &quot;);
				dto.setId(br.readLine());
				System.out.println(&quot;이름 입력: &quot;);
				dto.setName(br.readLine());
				System.out.println(&quot;생일 입력: &quot;);
				dto.setBirthday(br.readLine());
				System.out.println(&quot;전화번호 입력: &quot;);
				dto.setTel(br.readLine());

				int result = dao.notTs_in(dto);
				if(result != 0) {
					System.out.println(&quot;입력 성공!!!&quot;);
				}else{
					System.out.println(&quot;입력 실패!!!&quot;);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}//end of insertData1()

		//트랜잭션 입력처리
		public void insertData2() {
			TsDAO dao = new TsDAO();
			TsDTO dto = new TsDTO();

			//BufferedReader를 통해 입력값을 전달한다
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			//불러와서 버퍼를 이용. 입력을 받아야 하니 화면에
			try {
				System.out.println(&quot;아이디 입력: &quot;);
				dto.setId(br.readLine());
				System.out.println(&quot;이름 입력: &quot;);
				dto.setName(br.readLine());
				System.out.println(&quot;생일 입력: &quot;);
				dto.setBirthday(br.readLine());
				System.out.println(&quot;전화번호 입력: &quot;);
				dto.setTel(br.readLine());

				int result = dao.ts_in(dto);
				if(result != 0) {
					System.out.println(&quot;입력 성공!!!&quot;);
				}else{
					System.out.println(&quot;입력 실패!!!&quot;);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 TsMain.java&lt;/p&gt;
&lt;pre id=&quot;code_1683643474840&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.io.IOException;

public class TsMain {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 메인메뉴 구성
		// 1. 출력 2. 입력 3. 트랜잭션 입력처리 4. 종료

		char ch;
		TsProcess obj = new TsProcess();

		try {
			while (true) {
				do {
					System.out.println(&quot;------------&amp;lt;MENU&amp;gt;------------&quot;);
					System.out.println(&quot;1.출력 2.입력 3.트랜잭션 입력처리 4.종료&quot;);
					System.out.println(&quot;------------------------------&quot;);
					System.out.println(&quot;위의 메뉴번호를 선택하시오.!!!--&amp;gt; &quot;);
					ch = (char) System.in.read();
                    // System.in.read(); // 버퍼에 남은 엔터를 없애는 작업을 한다
                    // 맨 앞으로 가는 \r 과 한 줄 밑으로 가는 \n 가 엔터이다
                    // 아랫 줄과 같이 skip(건너뛸 칸 숫자) 메서드를 쓰면 
                    // 위에 System.in.read() 메서드와 같은 역할을 한다
					System.in.skip(2);// 입력스트림에서 두개의 문잣값을 건너뛰겠다.
					// (엔터값 입력이 된다면...)
				} while (ch &amp;lt; '1' || ch &amp;gt; '4');
				switch (ch) {
				case '1':
					obj.selectData();
					break;
				case '2':
					obj.insertData1();
					break;
				case '3':
					obj.insertData2();
					break;
				case '4':
					DbConn.dbClose();
					System.exit(0);
				}// switch
			} // while
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1683643972637&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
0
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
6
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
21 김장비 1990-05-22 010-1111-0000
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
43
이름 입력: 
감우리
생일 입력: 
2020-01-01
전화번호 입력: 
010-1111-1010
java.sql.SQLDataException: ORA-01841: 년은 영이 아닌 -4713 과 +4713 사이의 값으로 지정해야 합니다.

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
43
이름 입력: 
강호동
생일 입력: 
20200101
전화번호 입력: 
010-1111-1010
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 무결성 제약 조건(SCOTT.SYS_C0024845)에 위배됩니다

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
54
이름 입력: 
고주희
생일 입력: 
20200101
전화번호 입력: 
010-1111-1010
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
65
이름 입력: 
공감용
생일 입력: 
20020102
전화번호 입력: 
010-1222-1222
java.sql.SQLDataException: ORA-01841: 년은 영이 아닌 -4713 과 +4713 사이의 값으로 지정해야 합니다.

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
76
이름 입력: 
기수현
생일 입력: 
20230508
전화번호 입력: 
010-1234-1212
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
87
이름 입력: 
가미연
생일 입력: 
20020223
전화번호 입력: 
010-1235-1231
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
21 김장비 1990-05-22 010-1111-0000
54 고주희 2020-01-01 010-1111-1010
76 기수현 2023-05-08 010-1234-1212
87 가미연 2002-02-23 010-1235-1231
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
3
아이디 입력: 
98
이름 입력: 
길수호
생일 입력: 
20001112
전화번호 입력: 
010-1444-1222
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
21 김장비 1990-05-22 010-1111-0000
54 고주희 2020-01-01 010-1111-1010
76 기수현 2023-05-08 010-1234-1212
87 가미연 2002-02-23 010-1235-1231
98 길수호 2000-11-12 010-1444-1222
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
09
이름 입력: 
경수자
생일 입력: 
20090909
전화번호 입력: 
010-0002-0001
java.sql.SQLDataException: ORA-01841: 년은 영이 아닌 -4713 과 +4713 사이의 값으로 지정해야 합니다.

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
12
이름 입력: 
고길동
생일 입력: 
20091109
전화번호 입력: 
010-1029-1232
java.sql.SQLDataException: ORA-01841: 년은 영이 아닌 -4713 과 +4713 사이의 값으로 지정해야 합니다.

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
13
이름 입력: 
견아라
생일 입력: 
20090911
전화번호 입력: 
010-2938-2121
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
14
이름 입력: 
권유라
생일 입력: 
2009119
전화번호 입력: 
010-4852-1212
java.sql.SQLDataException: ORA-01861: 리터럴이 형식 문자열과 일치하지 않음

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
15
이름 입력: 
간소라
생일 입력: 
19991201
전화번호 입력: 
010-1231-1938
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
3
아이디 입력: 
16
이름 입력: 
구준희
생일 입력: 
2020-11-18
전화번호 입력: 
010-4352-5455
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
17
이름 입력: 
노계연
생일 입력: 
1998-12-12
전화번호 입력: 
010-9444-2222
입력 성공!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
3
아이디 입력: 
18
이름 입력: 
나하나
생일 입력: 
2001-04-29
전화번호 입력: 

java.sql.SQLIntegrityConstraintViolationException: ORA-01400: NULL을 (&quot;SCOTT&quot;.&quot;TR3&quot;.&quot;TEL&quot;) 안에 삽입할 수 없습니다

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
18
이름 입력: 
나하나
생일 입력: 
2001-04-29
전화번호 입력: 

java.sql.SQLIntegrityConstraintViolationException: ORA-01400: NULL을 (&quot;SCOTT&quot;.&quot;TR3&quot;.&quot;TEL&quot;) 안에 삽입할 수 없습니다

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
3
아이디 입력: 
18
이름 입력: 
나하나
생일 입력: 
2001-04-29
전화번호 입력: 
123-456789-0123456-7890123
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: 무결성 제약 조건(SCOTT.SYS_C0024845)에 위배됩니다

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
13 견아라 2009-09-11 010-2938-2121
15 간소라 1999-12-01 010-1231-1938
16 구준희 2020-11-18 010-4352-5455
21 김장비 1990-05-22 010-1111-0000
54 고주희 2020-01-01 010-1111-1010
76 기수현 2023-05-08 010-1234-1212
87 가미연 2002-02-23 010-1235-1231
98 길수호 2000-11-12 010-1444-1222
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
18
이름 입력: 나하나
생일 입력: 
2009-01-25
전화번호 입력: 
12345678901234567890123456
java.sql.SQLDataException: ORA-01841: 년은 영이 아닌 -4713 과 +4713 사이의 값으로 지정해야 합니다.

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
3
아이디 입력: 
19
이름 입력: 
남기남
생일 입력: 
1993-12-28
전화번호 입력: 
1234567-890123-4567890123
java.sql.SQLException: ORA-12899: &quot;SCOTT&quot;.&quot;TR3&quot;.&quot;TEL&quot; 열에 대한 값이 너무 큼(실제: 25, 최대값: 20)

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
13 견아라 2009-09-11 010-2938-2121
15 간소라 1999-12-01 010-1231-1938
16 구준희 2020-11-18 010-4352-5455
21 김장비 1990-05-22 010-1111-0000
54 고주희 2020-01-01 010-1111-1010
76 기수현 2023-05-08 010-1234-1212
87 가미연 2002-02-23 010-1235-1231
98 길수호 2000-11-12 010-1444-1222
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
2
아이디 입력: 
19
이름 입력: 
남기남
생일 입력: 
1932-09-30
전화번호 입력: 
12345678901-1234567890-123456
java.sql.SQLException: ORA-12899: &quot;SCOTT&quot;.&quot;TR3&quot;.&quot;TEL&quot; 열에 대한 값이 너무 큼(실제: 29, 최대값: 20)

입력 실패!!!
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
1
11 김관우 1990-10-30 010-333-3333
13 견아라 2009-09-11 010-2938-2121
15 간소라 1999-12-01 010-1231-1938
16 구준희 2020-11-18 010-4352-5455
21 김장비 1990-05-22 010-1111-0000
54 고주희 2020-01-01 010-1111-1010
76 기수현 2023-05-08 010-1234-1212
87 가미연 2002-02-23 010-1235-1231
98 길수호 2000-11-12 010-1444-1222
------------&amp;lt;MENU&amp;gt;------------
1.출력 2.입력 3.트랜잭션 입력처리 4.종료
------------------------------
위의 메뉴번호를 선택하시오.!!!--&amp;gt; 
4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TsMain.java Java Application 을 실행 해서 값을 입력 할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이타베이스 데이타 형식이 DATE 인 칼럼 BIRTHDAY 에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력한 날짜 중에 2자리 일을 쓰는데 앞자리에 0 이 들어가는 한자릿 수 일(01 일 ~09 일) 을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰면 다음과 같이 오류가 뜬다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.sql.SQLDataException:&amp;nbsp;ORA-01841:&amp;nbsp;년은&amp;nbsp;영이&amp;nbsp;아닌&amp;nbsp;-4713&amp;nbsp;과&amp;nbsp;+4713&amp;nbsp;사이의&amp;nbsp;값으로&amp;nbsp;지정해야&amp;nbsp;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 안 뜰 때도 있어서 왜 그런지 모르겠다&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/574</guid>
      <comments>https://sapwha.tistory.com/574#entry574comment</comments>
      <pubDate>Wed, 10 May 2023 00:17:07 +0900</pubDate>
    </item>
    <item>
      <title>Java getActionCommand()</title>
      <link>https://sapwha.tistory.com/573</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SwingJDBC.java&lt;/p&gt;
&lt;pre id=&quot;code_1680791792418&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;
/**
 * 2차원 배열로 데이타를 저장하다가 크기가 모잘라서 오류가 난다.
 * 벡터를 이용하였으나 JTable 에서 인자로 벡터만 받으며
 * 벡터 배열 형태를 받지 않아 오류가 난다
 * 2차원 배열과 같은 의미를 지니도록 벡터 내부에 값이 벡터가 되도록 하였지만
 * JTable 생성자 함수 인자에서 벡터 배열 형태를 가지는 메서드가 없다.
 * showData() 메서드에서 배열 크기를 자동으로 늘려주도록 만들었지만
 * 수정과 삭제를 눌렀을 때 테이블을 다시 그려주는 repaint() 메서드가
 * 제대로 작동하지 않는다.
 */
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;

@SuppressWarnings(&quot;unchecked&quot;)
public class SwingJDBC extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2732383441775678655L;
	private ResultSet rs = null;
	private Statement stmt = null;
	private PreparedStatement pst = null;

	private JButton[] btn = new JButton[4];
	private JLabel[] label = new JLabel[8];
	private JTextField[] tf = new JTextField[8];
	private JTable table;
	private JScrollPane jp = new JScrollPane();

	// 선언만 해놓는다. 생성은 생성자안에서 한다.
	private JPanel labelTextP[] = new JPanel[4];// 레이블과 텍스트필드를 묶는 패널

	private Vector&amp;lt;String&amp;gt;[] dataA = new Vector[8];
	private String[][] data = new String[50][8];
	private String[][] dataT;
	private String[] colName = { &quot;empno     &quot;, &quot;ename     &quot;, &quot;job       &quot;, &quot;mgr       &quot;, &quot;hiredate  &quot;, &quot;sal       &quot;,
			&quot;comm      &quot;, &quot;deptno    &quot; };
	private Vector&amp;lt;String&amp;gt; colNameV = new Vector&amp;lt;String&amp;gt;();
	private String[] str = { &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot; };// 처음 초기에 실제 값은 널값으로 처리

	// 생성자
	public SwingJDBC() throws Exception {
		super(&quot;사원정보&quot;);

		for (int i = 0; i &amp;lt; dataA.length; i++) {
			dataA[i] = new Vector&amp;lt;String&amp;gt;();
		}

		colNameV.add(0, &quot;empno     &quot;);
		colNameV.add(1, &quot;ename     &quot;);
		colNameV.add(2, &quot;job       &quot;);
		colNameV.add(3, &quot;mgr       &quot;);
		colNameV.add(4, &quot;hiredate  &quot;);
		colNameV.add(5, &quot;sal       &quot;);
		colNameV.add(6, &quot;comm      &quot;);
		colNameV.add(7, &quot;deptno    &quot;);
		
		// DB에 접속
		Connection conn = DbConn.getConnection();// scott계정
		stmt = conn.createStatement();

		// 레이블과 텍스트필드, 버튼 컴포넌트를 포함하는 패널
		JPanel inputPanel = new JPanel();
		inputPanel.setLayout(new GridLayout(5, 1));

		// 레이블 작성 로직
		for (int i = 0; i &amp;lt; 8; i = i + 1) {
			label[i] = new JLabel(colName[i]);
		}

		// 텍스트 필드 생성
		for (int i = 0; i &amp;lt; 8; i = i + 1) {
			tf[i] = new JTextField(15);
		}

		for (int i = 0; i &amp;lt; 4; i = i + 1) {
			labelTextP[i] = new JPanel();
		}

		// labelTextP패널에 레이블과 텍스트 필드를 담는 로직
		int j = -1;
		for (int i = 0; i &amp;lt; 8; i = i + 1) {
			if (i % 2 == 0) {
				j = j + 1; // j++;
			}
			labelTextP[j].add(label[i]);
			labelTextP[j].add(tf[i]);
		}

		JPanel btnPanel = new JPanel(); // 버튼을 담는 패널

		btn[0] = new JButton(&quot;선택&quot;);
		btn[1] = new JButton(&quot;입력&quot;);
		btn[2] = new JButton(&quot;수정&quot;);
		btn[3] = new JButton(&quot;삭제&quot;);

		// 패널에 버튼을 담는 로직
		for (int i = 0; i &amp;lt; 4; i = i + 1) {
			btn[i].addActionListener(eh);
			btnPanel.add(btn[i]);
		}

		inputPanel.add(labelTextP[0]);
		inputPanel.add(labelTextP[1]);
		inputPanel.add(labelTextP[2]);
		inputPanel.add(labelTextP[3]);
		inputPanel.add(btnPanel); // 버튼 패널 삽입

		table = new JTable(data, colName);
		jp = new JScrollPane(table);

		jp.addMouseListener(new MouseAdapter() {
		});// 이벤트는 없고 단지 선택했다는 동작만 해주시면 된다 선택해서 파란색으로뜬다.

		// container역할을 하는 패널구해오기
		Container cp = this.getContentPane();
		cp.setLayout(new GridLayout(2, 1));

		cp.add(jp);
		cp.add(inputPanel);

		// X버튼 눌렀을 때 닫힐 수 있다
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setBounds(100, 100, 500, 500); // 프레임의 크기 설정
		setVisible(true);
		showData();
	}// 생성자

	public void showData() {
		table.removeAll();
		System.out.println(&quot;showData 에서 data.length : &quot; + data.length);
		try {
			for (int i = 0; i &amp;lt; data.length; i = i + 1) {
				for (int j = 0; j &amp;lt; 8; j = j + 1) {
					data[i][j] = &quot;&quot;;
				}
			} // for문
//			System.out.println(&quot;dataA 길이 : &quot; + dataA.length);
//			for (int i = 0; i &amp;lt; dataA.length; i = i + 1) {
//				for (int j = 0; j &amp;lt; 50; j = j + 1) {
//					dataA[i].add(j, &quot;&quot;);
//				}
//			}

//			rs = stmt.executeQuery(&quot;select count(*) from emp&quot;);
//			rs.next();
//			System.out.println(rs.getInt(1));
//			if (rs.getInt(1) &amp;gt; 50) {
//				for (int i = 0; i &amp;lt; dataA.length; i = i + 1) {
//					dataA[i].ensureCapacity(625);
//				}
//			}

			rs = stmt.executeQuery(&quot;select * from emp&quot;);
			
			System.out.println(&quot;sql 문을 실행하였습니다.&quot;);
			
			int i = 0;
			int j = 1;
			int pos = 0;
			while (rs.next()) {
				data[i][0] = rs.getString(1);
				data[i][1] = rs.getString(2);
				data[i][2] = rs.getString(3);
				data[i][3] = rs.getString(4);
				data[i][4] = rs.getString(5);
				data[i][5] = rs.getString(6);
				data[i][6] = rs.getString(7);
				data[i++][7] = rs.getString(8);
				if (i &amp;gt; data.length - 1) {
					System.out.println(&quot;현재 i 값 : &quot; + i);
					System.out.println(&quot;data.length 값 : &quot; + data.length);
					j = j + 1;
					dataT = new String[data.length * j][8];
					
					pos = data.length;
					
					for (int k = 0; k &amp;lt; data.length; k = k + 1) {
						dataT[k][0] = data[k][0];
						dataT[k][1] = data[k][1];
						dataT[k][2] = data[k][2];
						dataT[k][3] = data[k][3];
						dataT[k][4] = data[k][4];
						dataT[k][5] = data[k][5];
						dataT[k][6] = data[k][6];
						dataT[k][7] = data[k][7];
					}
					
					System.out.println(&quot;dataT.length 값 : &quot; + dataT.length);
					System.out.println(&quot;pos 값 : &quot; + pos);
					data = new String[dataT.length][8];
					
					System.out.println(&quot;data 배열 크기를 늘린 후 data.length 값 : &quot; + data.length);
					
					for (int l = 0; l &amp;lt; pos; l = l + 1) {
						data[l][0] = dataT[l][0];
						data[l][1] = dataT[l][1];
						data[l][2] = dataT[l][2];
						data[l][3] = dataT[l][3];
						data[l][4] = dataT[l][4];
						data[l][5] = dataT[l][5];
						data[l][6] = dataT[l][6];
						data[l][7] = dataT[l][7];
					}
				}
//				dataA[0].add(i, rs.getString(1));
//				dataA[1].add(i, rs.getString(2));
//				dataA[2].add(i, rs.getString(3));
//				dataA[3].add(i, rs.getString(4));
//				dataA[4].add(i, rs.getString(5));
//				dataA[5].add(i, rs.getString(6));
//				dataA[6].add(i, rs.getString(7));
//				dataA[7].add(i++, rs.getString(8));
			} // while
			System.out.println(&quot;1번째 로우 값 : &quot; + data[1][0] + data[1][1] + data[1][2] + data[1][3] + data[1][4] + data[1][5] + data[1][6] + data[1][7]);
			table.repaint();
			System.out.println(&quot;table 을 다시 그렸습니다.&quot;);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// showData

	// 내부클래스를 바로 생성해서 사용한다
	EventHandler eh = new EventHandler();

	// 이벤트핸들러 내부클래스로 정의
	// 이벤트핸들러가 중개역할을 해준다
	class EventHandler implements ActionListener {
		public void actionPerformed(ActionEvent ae) {
			if (ae.getActionCommand().equals(&quot;선택&quot;)) {
				// 테이블의 선택한 로우값을 얻어온다.
				int row = table.getSelectedRow();
				System.out.println(&quot;선택한 로웃값 : &quot; + row);

				for (int i = 0; i &amp;lt; 8; i = i + 1) {
//					System.out.println(&quot;data[&quot; + row + &quot;][&quot; + i + &quot;] 값 : &quot; + data[row][i]);
					tf[i].setText(data[row][i]);
				}
			} else if (ae.getActionCommand().equals(&quot;입력&quot;)) {
				try {
					for (int i = 0; i &amp;lt; 8; i = i + 1) {
						if (tf[i].getText().equals(&quot;&quot;)) {
							if (i == 0 || i == 3 || i == 5 || i == 6 || i == 7)
								str[i] = &quot;''&quot;;// 숫자형의 데이타값을 널값일때 처리해주는방법 안그러면오류남다
							else
								str[i] = &quot;&quot;;// 숫자형이 아닌 데이타칼럼에 널값을 넣을 때의 방법
						} else {// 널값이 아닐때는
							str[i] = tf[i].getText();
						}
					} // for문
					stmt.executeQuery(&quot;insert into emp values(&quot; + str[0] + &quot;,'&quot; + str[1] + &quot;','&quot; + str[2] + &quot;',&quot;
							+ str[3] + &quot;,'&quot; + str[4] + &quot;',&quot; + str[5] + &quot;,&quot; + str[6] + &quot;,&quot; + str[7] + &quot;)&quot;);
					stmt.execute(&quot;commit&quot;);
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					System.out.println(&quot;입력 오류!!!&quot;);
				} // try catch문

				// 화면에 출력
				showData();// repaint처리

				// 텍스트 필드에 있는 내용을 삭제
				for (int i = 0; i &amp;lt; 8; i = i + 1) {
					tf[i].setText(&quot;&quot;);
				}
			} else if (ae.getActionCommand().equals(&quot;수정&quot;)) {
				try {
					for (int i = 0; i &amp;lt; 8; i = i + 1) {
						if (tf[i].getText().equals(&quot;&quot;)) {
							if (i == 0 || i == 3 || i == 5 || i == 6 || i == 7)
								str[i] = &quot;''&quot;;
							else
								str[i] = &quot;&quot;;
						} else {
							str[i] = tf[i].getText();
						} // if
					} // for

					// 오라클 Date형식에 맞게 문자열을 잘라낸다.
					if (str[4].length() &amp;gt; 0) {
						str[4] = str[4].substring(0, 10);
					} // if

					stmt.executeUpdate(&quot;update emp set empno = &quot; + str[0] + &quot;, ename='&quot; + str[1] + &quot;', job='&quot; + str[2]
							+ &quot;',&quot; + &quot;mgr=&quot; + str[3] + &quot;, hiredate='&quot; + str[4] + &quot;',sal=&quot; + str[5] + &quot;, comm=&quot; + str[6]
							+ &quot;, deptno=&quot; + str[7] + &quot; where empno = &quot; + str[0]);
					stmt.executeQuery(&quot;commit&quot;);
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					System.out.println(&quot;수정 오류!!!&quot;);
				} // try catch
					// 화면에 수정된 내용 출력
				showData();
				for (int i = 0; i &amp;lt; 8; i = i + 1) {
					tf[i].setText(&quot;&quot;);// 널값으로처리해서돌려준다
				} // for
			} else if (ae.getActionCommand().equals(&quot;삭제&quot;)) {
				try {
					stmt.executeQuery(&quot;delete from emp where&quot; + &quot; empno = &quot; + tf[0].getText());
					stmt.executeQuery(&quot;commit&quot;);
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					System.out.println(&quot;삭제시 에러 발생!!!!&quot;);
				}
				// 삭제된 내용을 테이블에 반영해서 화면 출력
				showData();
				for (int i = 0; i &amp;lt; 8; i = i + 1) {
					tf[i].setText(&quot;&quot;);
				}
			} // if문
		}// actionPerformed()
	}////// EventHandler Class//////

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		new SwingJDBC();
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String java.awt.event.ActionEvent.getActionCommand()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getActionCommand() 메서드는 고 action(행동)과 연관된 명령 문자열을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 담는 이차원 배열 data 크기를 가변적으로 했더니 수정 이나 삭제 버튼을 누른 후에 테이블을 다시 페인트 할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그려지지가 않는다. 왜 그런지는 모르겠다. 이차원 배열 data 크기를 고정으로 두면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제대로 작동한다.&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/573</guid>
      <comments>https://sapwha.tistory.com/573#entry573comment</comments>
      <pubDate>Thu, 6 Apr 2023 23:45:45 +0900</pubDate>
    </item>
    <item>
      <title>Java ResultSetMetaData</title>
      <link>https://sapwha.tistory.com/572</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SqlPlus_emulator.java&lt;/p&gt;
&lt;pre id=&quot;code_1680534406266&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class SqlPlus_emulator {
	static Connection conn;
	static ResultSet rs;
	// 데이터베이스에접속을하기위해서는드라이버로딩을해야한다
	static {
		// static block 초기화
		// static block 초기화는 기본적으로 메인메서드보다 더 클래스가
		// 로딩이되면서 바로 실행이 되기때문에 static method보다
		// 먼저 실행되는.클래스 로딩됨과 동시에 실행되는곳
		try {
			Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println(&quot;JDBC드라이버를 찾을 수 없습니다.!!!&quot;);
		}
	}// STATIC 초기화 블럭에 드라이버 로딩

	// 데이타베이스에접속하기위한 과정
	// 메서드로만듦
	static public void dbConn() throws Exception {
		String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
		String user, pwd;
		user = readEntry(&quot;사용자명 입력 :&quot;);
		pwd = readEntry(&quot;비밀번호 입력 :&quot;);

		conn = DriverManager.getConnection(url, user, pwd);
		System.out.println(&quot;오라클 데이타베이스에 접속됨... ....&quot;);
	}

	// 우리가입력한데이타값받아오기 키보드로부터 읽어온 데이타문자열을 리턴하는 메소드
	static public String readEntry(String prompt) {
		StringBuffer buf = new StringBuffer(); // String을만들기위한버퍼,String에내용을입력시버퍼에저장
		System.out.print(prompt);
		// 키보드로부터입력받기

		try {
			int ch = System.in.read();// 한문자씩읽기
			// 엔터치면 뉴라인이라는값이들어옴
//			while (ch != '\n' &amp;amp;&amp;amp; ch != -1) {// 개행이 아니고 파일의 끝 -1이 아님
			while (ch != '\n') {
				buf.append((char) ch); // 스트링버퍼에다가 하나씩 형변환해서 데이타값을 넣어준다
				// 스트링버퍼에 데이타값 보내기(위)
				ch = System.in.read();// 한문자씩 읽어 버퍼에 계속 누적시킴append
			} // while
				// 읽은 문자열들으 readEntry메소드를 호출한 곳에 넘겨준다
			return buf.toString().trim(); // 버퍼에있는내용을문자열로공백값제거해서넘기기
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return &quot;&quot;;
		} // 하나하나씩 데이타를 읽어오기

	}

	static public void inputQuery() throws Exception {// 키보드로부터입력받은값불러오기
		// 버퍼드리더는키보드로부터입력받는노드스트림하나필요 시스템 인이라는인풋스트림이용
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		String query = &quot;&quot;;
		Statement stmt = conn.createStatement();

		System.out.print(&quot;SQL&amp;gt; &quot;);

		while ((query = bufr.readLine()) != null) {
			if (query.equals(&quot;&quot;)) {
				System.out.print(&quot;SQL&amp;gt; &quot;);
				continue;
			} else {
				try {
					boolean isRs = stmt.execute(query.trim());
					// System.out.println(isRs);
					if (isRs) {// select문일 경우
						rs = stmt.getResultSet();
						// resultSet의 내용을 출력 메소드
						outResultSet(rs);

					} else { // 셀렉트 문이 아닐경우
						int cnt = stmt.getUpdateCount();
						// System.out.println(cnt);
						// 로우=레코드
						// String str = (cnt &amp;gt; 0) ? cnt+&quot;개의 로우가 변경되었음&quot;:&quot;변경된 레코드가 없습니다.&quot;;
						String str = (cnt &amp;gt; 0) ? cnt + &quot;개의 레코드가 변경되었음&quot; : &quot;변경된 레코드가 없습니다.&quot;;
						System.out.println(str);
					} // if
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					System.out.println(&quot;알수없는 명령어... .... ....&quot;);
				}
			} // if
			System.out.print(&quot;SQL&amp;gt; &quot;);
		} // while
	}

	static public void outResultSet(ResultSet res) throws SQLException {
		ResultSetMetaData md = res.getMetaData(); // 칼럼에 대한 정보를 얻기 위해서 ResultSetMetaData를 얻어오는 과정
		int cCount = md.getColumnCount();
		int cSize[] = new int[cCount]; // 열(칼럼/필드)의 사이즈를 얻기위한 배열 생성
		String cNames[] = new String[cCount]; // 필드명의 이름을 얻어오기 위한 배열 생성

		int totalCsize = 0;

		for (int i = 0; i &amp;lt; cCount; i = i + 1) {
			cNames[i] = md.getColumnName(i + 1);
			cSize[i] = md.getColumnDisplaySize(i + 1);
			totalCsize = totalCsize + cSize[i] + 3; // totalCsize += cSize[i]+5;
		}
		// 라인을 출력
		String line = makeDisplay('-', totalCsize);
		System.out.println(line);

		// 컬럼명을 화면에 출력
		System.out.print(&quot;  &quot;);
		for (int i = 0; i &amp;lt; cCount; i = i + 1) {
			outValue(cNames[i], cSize[i]);
		}
		System.out.println();
		System.out.println(line);

		// 데이터를 추출하는 과정(Fetch 작업)후 화면에 출력
		while (res.next()) {
			System.out.print(&quot;  &quot;);
			// 하나의레코드에여러개의칼럼이있다
			for (int i = 0; i &amp;lt; cCount; i = i + 1) {
				String val = res.getString(i + 1);
				// 데이타값 출력부분 화면크기에 맞춰출력
				// 해당 데이타값을 출력을 하는데 그냥 한번 출력해보겠다.
				// 사이즈계산하고 공백을 만들어주고 데이타를 출력했었지만
				// 공백을 안주면 내용을 알아볼수가없다 다 붙어나온다
				// 해당 칼럼수만큼 공백을 넣어준다
				// outValue()메소드를 사용하려면 전체 칼럼 크기알아야겠죠
				outValue(val, cSize[i]);
			}
			System.out.println();
			System.out.println(line);
		}
	}

	// 화면에 알맞게 출력하기위한 메소드
	static public void outValue(String cName, int cSize) {
		if (cName == null)
			cName = &quot;NULL&quot;;
		else
			System.out.print(cName);

		byte b[] = cName.getBytes(); // 바이트의수만큼 배열이 생긴다 씨네임이 갖고있는 실제 바이트수구함
		int bSize = b.length;
		// 화면에 출력할때 필드명을 구해오는데 필드명이 ID일때 해당ID에대한 바이트길이
		// 가 있다. 만약 20이 길이이면 ID에 해당되는 값이 나온다.만약 Name같은경우
		// 이름만 출력했을때 실제 데이타값출력하려했을때 이름을 그냥 길게 출력하면
		// 보기가 안좋다. 데이타 내용은 길고, 필드 사이즈만큼 크기가 설정되므로
		// 데이타들이 막 섞여서 보기어려울수있다.필드영역크기 정해놓고그안에데이타씀
		int pSize = cSize - bSize; // 여백사이즈,현재 원래 칼럼의 영역사이즈가있고 c네임,네임필드가 되는데
		// 화면에 출력하려면 네임이 출력이 되고, 그 담에 연봉이 붙어나올텐데실제 칼럼 사이즈에서
		// 네임이 차지하는 자릿수를 빼게 되면,나머지 영역이 생긴다.그 나머지 영역만큼 다시 화면에 추가를시킨다.
		// 실제 칼럼 사이즈만큼 영역잡는다.

		// 화면에 필드명을 찍어주고 그 필드명이 만약 작을 경우에는 영보다 작으면
		// psize안구해도 되지만 클경우에는 실제 psize가 0보다 크다는건
		// cname보다 칼럼사이즈가 크다는거라서 큰 거 만큼 psize만큼 공백으로
		// 채우겠다는 의미

		// int pSize = cSize - cName.length();

		if (pSize &amp;lt; 0) {
			pSize = 0;
		}

		String pStr = makeDisplay(' ', pSize);// 화면에공백출력pSize만큼
		System.out.print(pStr);
	}

	static public String makeDisplay(char ch, int size) {
		// 화면을 만듦 size만큼 화면을 만들자 ch들어온문자를 담는 배열
		char makeLine[] = new char[size];

		for (int i = 0; i &amp;lt; makeLine.length; i = i + 1) {
			makeLine[i] = ch;
		}

		return new String(makeLine);// 스트링타입으로만들어출력하겠다의미
	}

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		dbConn();
		inputQuery();
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1680534493345&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;사용자명 입력 :scott
비밀번호 입력 :a1234
오라클 데이타베이스에 접속됨... ....
SQL&amp;gt; 
SQL&amp;gt; SELECT * FROM MEMBER
-----------------------------------------------------------------------------------------------------------------------
  NO                    NAME                HP             ADDR                                              
-----------------------------------------------------------------------------------------------------------------------
  16                    송인자           010-4321-3214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  16                    이지연           010-4221-2214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  16                    장진미           010-4121-2254  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  17                    오원석           010-4129-3254  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  18                    박건우           010-4121-2214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  9                     양호중           010-999-9999   '서울시강남구도곡동'                     
-----------------------------------------------------------------------------------------------------------------------
  10                    양호호           010-999-9299   서울시강남구양재동                       
-----------------------------------------------------------------------------------------------------------------------
  11                    안소희           010-199-9299   %서울시                                        
-----------------------------------------------------------------------------------------------------------------------
  6                     남보라           010-333-2323   경기도 성남시 분당구 서현동           
-----------------------------------------------------------------------------------------------------------------------
  14                    김수기           010-090-2309   전라남도 해남시 해남군 땅끝마을     
-----------------------------------------------------------------------------------------------------------------------
  1                     홍길동           010-1111-1111  서울시 종로구 흥인동                     
-----------------------------------------------------------------------------------------------------------------------
  12                    강민정           010-199-9291   충청남도 강진                               
-----------------------------------------------------------------------------------------------------------------------
  3                     안다미           010-1111-2131  서울시 관악구 신림동                     
-----------------------------------------------------------------------------------------------------------------------
  7                     김나래           010-1111-2121  서울시 송파구 잠실새내동               
-----------------------------------------------------------------------------------------------------------------------
  4                     김지성           010-1111-9121  서울시 강동구 상일동                     
-----------------------------------------------------------------------------------------------------------------------
  5                     박만구           010-1121-9121  경기도 하남시 미사동                     
-----------------------------------------------------------------------------------------------------------------------
  2                     임평화           010-2121-9121  서울시 은평구 한옥마을                  
-----------------------------------------------------------------------------------------------------------------------
  8                     이문형           010-1237-1237  서울시                                         
-----------------------------------------------------------------------------------------------------------------------
  13                    금미진           010-3434-3434  서울시 강북구 수유동                     
-----------------------------------------------------------------------------------------------------------------------
  15                    김소전           010-190-2309   경기도 부천시 상미동                     
-----------------------------------------------------------------------------------------------------------------------
  6                     장동민           010-212-2121   서울 마포구 아현동                        
-----------------------------------------------------------------------------------------------------------------------
SQL&amp;gt; INSERT INTO MEMBER(NO, NAME, HP, ADDR) VALUES (19, '공성구', '010-9999-9999', '서울시 종로구 낙원동 91-909')
1개의 레코드가 변경되었음
SQL&amp;gt; SELECT * FROM MEMBER;
알수없는 명령어... .... ....
SQL&amp;gt; SELECT * FROM MEMBER
-----------------------------------------------------------------------------------------------------------------------
  NO                    NAME                HP             ADDR                                              
-----------------------------------------------------------------------------------------------------------------------
  16                    송인자           010-4321-3214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  16                    이지연           010-4221-2214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  16                    장진미           010-4121-2254  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  17                    오원석           010-4129-3254  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  18                    박건우           010-4121-2214  충청도                                         
-----------------------------------------------------------------------------------------------------------------------
  19                    공성구           010-9999-9999  서울시 종로구 낙원동 91-909              
-----------------------------------------------------------------------------------------------------------------------
  9                     양호중           010-999-9999   '서울시강남구도곡동'                     
-----------------------------------------------------------------------------------------------------------------------
  10                    양호호           010-999-9299   서울시강남구양재동                       
-----------------------------------------------------------------------------------------------------------------------
  11                    안소희           010-199-9299   %서울시                                        
-----------------------------------------------------------------------------------------------------------------------
  6                     남보라           010-333-2323   경기도 성남시 분당구 서현동           
-----------------------------------------------------------------------------------------------------------------------
  14                    김수기           010-090-2309   전라남도 해남시 해남군 땅끝마을     
-----------------------------------------------------------------------------------------------------------------------
  1                     홍길동           010-1111-1111  서울시 종로구 흥인동                     
-----------------------------------------------------------------------------------------------------------------------
  12                    강민정           010-199-9291   충청남도 강진                               
-----------------------------------------------------------------------------------------------------------------------
  3                     안다미           010-1111-2131  서울시 관악구 신림동                     
-----------------------------------------------------------------------------------------------------------------------
  7                     김나래           010-1111-2121  서울시 송파구 잠실새내동               
-----------------------------------------------------------------------------------------------------------------------
  4                     김지성           010-1111-9121  서울시 강동구 상일동                     
-----------------------------------------------------------------------------------------------------------------------
  5                     박만구           010-1121-9121  경기도 하남시 미사동                     
-----------------------------------------------------------------------------------------------------------------------
  2                     임평화           010-2121-9121  서울시 은평구 한옥마을                  
-----------------------------------------------------------------------------------------------------------------------
  8                     이문형           010-1237-1237  서울시                                         
-----------------------------------------------------------------------------------------------------------------------
  13                    금미진           010-3434-3434  서울시 강북구 수유동                     
-----------------------------------------------------------------------------------------------------------------------
  15                    김소전           010-190-2309   경기도 부천시 상미동                     
-----------------------------------------------------------------------------------------------------------------------
  6                     장동민           010-212-2121   서울 마포구 아현동                        
-----------------------------------------------------------------------------------------------------------------------
SQL&amp;gt; 
SQL&amp;gt;  
알수없는 명령어... .... ....
SQL&amp;gt; 	
알수없는 명령어... .... ....
SQL&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.sql.ResultSetMetaData&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한개의 ResultSet 객체 안에서 열들으 종류(형태,유형)와 속성들에 대한 정보를 얻기 위하여 사용되어 질 수 있는 한 객체이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EOF (End Of File)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일의 끝, 더 이상 읽을 수 있는 데이타가 없다는 것을 말한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDE 나 터미널이나 콘솔창에서 EOF 을 발생시키려면 윈도우 운영체제 기준으로 Ctrl + z (Ctrl + Z) 로 입력을 해주어야 한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@haramiee/Java-EOF-End-Of-File&quot;&gt;[Java]   EOF (End Of File) (velog.io)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680535013215&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]   EOF (End Of File)&quot; data-og-description=&quot;파일의 끝 (End Of File), 즉 더 이상 읽을 수 있는 데이터가 존재하지 않는 것을 뜻한다. IDE나 터미널에서 EOF를 발생시키려면 윈도우 기준 ctrl+z로 입력을 주어야 한다.ScannerhasNext()를 사용한다. 입력&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@haramiee/Java-EOF-End-Of-File&quot; data-og-url=&quot;https://velog.io/@haramiee/Java-EOF-End-Of-File&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dp79s5/hyR9M85xmH/64khARKIQUhzEKqbCICt5K/img.png?width=800&amp;amp;height=440&amp;amp;face=0_0_800_440,https://scrap.kakaocdn.net/dn/EYjJZ/hyR9HmnR4H/BZ8bJpodVBJfU9vLYhHitK/img.png?width=800&amp;amp;height=440&amp;amp;face=0_0_800_440&quot;&gt;&lt;a href=&quot;https://velog.io/@haramiee/Java-EOF-End-Of-File&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@haramiee/Java-EOF-End-Of-File&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dp79s5/hyR9M85xmH/64khARKIQUhzEKqbCICt5K/img.png?width=800&amp;amp;height=440&amp;amp;face=0_0_800_440,https://scrap.kakaocdn.net/dn/EYjJZ/hyR9HmnR4H/BZ8bJpodVBJfU9vLYhHitK/img.png?width=800&amp;amp;height=440&amp;amp;face=0_0_800_440');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java]   EOF (End Of File)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;파일의 끝 (End Of File), 즉 더 이상 읽을 수 있는 데이터가 존재하지 않는 것을 뜻한다. IDE나 터미널에서 EOF를 발생시키려면 윈도우 기준 ctrl+z로 입력을 주어야 한다.ScannerhasNext()를 사용한다. 입력&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String java.io.BufferedReader.readLine() throws IOException&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;readLine() 메서드는 어떠한 줄-끝맺음 문자들을 포함하지 않는 상태로 그 줄의 내용들을 포함하는 문자열을 반환하거나, 만약에 스트림의 끝에 도달하였다면 null 을 반환한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자명을 입력받고 비밀번호를 입력받을 때 쓰는 사용자 정의 메서드인 readEntry(String prompt) 에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한문자씩 읽는 read() 메서드가 있는데 입력장치로 입력받은 데이타의 다음 바이트를 정수형으로 반환하거나, 만약에 스트림의 마지막에 도달된다면 -1 을 반환하게 된다. 그런데 read() 메서드 다음 줄에 쓴 while 반복문에서 정수형 값 ch 변수에 개행이 아니거나 파일의 끝(스트림의 끝, 즉 -1 값)이 아닐 때 까지 실행하라고 되어 있다. Enter 키를 치면 개행이라는 값이 들어오는데 while 문 내에 조건문에서 개행이면 반복문을 그만두고 파일의 끝(스트림의 끝, 즉 -1 값)이어도 반복문을 그만두라고 되있지만 Ctrl + z (Ctrl + Z) 를 쳐서 파일의 끝이라고 신호를 보냈지만 오류가 난다. 이클립스 IDE 콘솔창 오류 문제라고 하는 말도 있다. 자세한 것은 파악이 되지 않아서 찾아서 따라 해봐도 오류가 계속 나오거나 생각한 대로 실행되지를 않아서 찾는데도 시간이 오래 걸린다. 개행문자를 입력받을 경우에만 반복문을 나오는 것으로 쓴다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/572</guid>
      <comments>https://sapwha.tistory.com/572#entry572comment</comments>
      <pubDate>Tue, 4 Apr 2023 01:23:09 +0900</pubDate>
    </item>
    <item>
      <title>Java Singleton Type Class</title>
      <link>https://sapwha.tistory.com/571</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonEx1.java&lt;/p&gt;
&lt;pre id=&quot;code_1680184837858&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

public class SingleTonEx1 {// 인스턴스를 하나만 생성하고, 더이상 생성못함
	private static SingleTonEx1 instance = new SingleTonEx1();

	// 인스턴스를 하나만 생성하도록하는 싱글톤타입으로 클래스를 만드려면 생성자를
	// private으로 외부에서 접근못하게 해야 한다 클래스생성자를 private으로설정
	// static 키워드는 클래스를 로딩할 때 컴파일타임에 이미 만들어져버리기 때문에
	// 실행중에 어떤 다른 처리가 필요하다면 불편하다
	private SingleTonEx1() {
	}

	public static SingleTonEx1 getInstance() {
		return instance;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonEx2.java&lt;/p&gt;
&lt;pre id=&quot;code_1680184919415&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.util.Random;

public class SingleTonEx2 {
	private static SingleTonEx2 instance = null;

	private int randomNumber;

	// 생성자를 private 이면 요 클래스 내에서만 생성할 수 있다는 것
	private SingleTonEx2() {
	}

	// getInstance() 메소드를 호출하지 않는다면 아예 이클래스의 인스턴스는 생성안된다
	// 한번도 생성되지않는 그런 패턴이 될수있다
	public static SingleTonEx2 getInstance() {
		if (instance == null) {
			instance = new SingleTonEx2();
			// SingleTonEx1은 클래스가 static이라 시작하자마자 바로 인스턴스가 생성되었지만 아예 객체가 미리 만들어져버리지만
			// 요 SingleTonEx2는 getInstance()를 실행했을 때 동시에 바로 어떤 새로운 다른 처리를 할 수 있다.
			Random rand = new Random();
			// static 메소드에서는 non-static 변수를 못쓰므로
			// instance의 randomNumber 자기자신의자식멤버로 접근한다
			instance.randomNumber = rand.nextInt(5) + 1;
		}

		return instance;
	}

	public int getRandomNumber() {
		return randomNumber;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonEx3.java&lt;/p&gt;
&lt;pre id=&quot;code_1680185006255&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.util.Random;

public class SingleTonEx3 {
	private static SingleTonEx3 instance = null;

	private int randomNumber;

	// 생성자를 private 이면 요 클래스 내에서만 생성할 수 있다는 것
	private SingleTonEx3() {
	}
	// getInstance() 메소드를 호출하지 않는다면 아예 이클래스의 인스턴스는 생성안된다
	// 한번도 생성되지않는 그런 패턴이 될수있다

	// 객체를 두사람이 동시에 만들려고 이 클래스의 인스턴스를 동시에 만들면
	// 객체가 2개 생길 문제가 있다. 그럴때 동기화 synchronized 를 쓴다
	// 동시에 이 영역을 침범하지 못한다. 다른 프로그램은 먼저 또다른 프로그램이
	// 이 영역을 쓰고 나서 요 자원을 쓴다. 두번째 예제를 해결...두번째예제는 첫예제를 해결
	public static synchronized SingleTonEx3 getInstance() {
		if (instance == null) {
			instance = new SingleTonEx3();
			// SingleTonEx1은 클래스가 static이라 시작하자마자 바로 인스턴스가 생성되었지만 아예 객체가 미리 만들어져버리지만
			// 요 SingleTonEx2는 getInstance()를 실행했을 때 동시에 바로 어떤 새로운 다른 처리를 할 수 있다.
			Random rand = new Random();
			// static 메소드에서는 non-static 변수를 못쓰므로
			// instance의 randomNumber 자기자신의자식멤버로 접근한다
			instance.randomNumber = rand.nextInt(5) + 1;
		}

		return instance;
	}

	public int getRandomNumber() {
		return randomNumber;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonEx4.java&lt;/p&gt;
&lt;pre id=&quot;code_1680185126702&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.util.Random;

public class SingleTonEx4 {
	private static SingleTonEx4 instance = null;

	private int randomNumber;

	// 생성자를 private 이면 요 클래스 내에서만 생성할 수 있다는 것
	private SingleTonEx4() {
	}
	// getInstance() 메소드를 호출하지 않는다면 아예 이클래스의 인스턴스는 생성안된다
	// 한번도 생성되지않는 그런 패턴이 될수있다

	// 객체를 두사람이 동시에 만들려고 이 클래스의 인스턴스를 동시에 만들면
	// 객체가 2개 생길 문제가 있다. 그럴때 동기화 synchronized 를 쓴다
	// 동시에 이 영역을 침범하지 못한다. 다른 프로그램은 먼저 또다른 프로그램이
	// 이 영역을 쓰고 나서 요 자원을 쓴다. 두번째 예제를 해결...두번째예제는 첫예제를 해결
	// 이번에는 인스턴스화 하기 전의 작업.고작업만 동기화를 시켜줄것이다
	// 함수전체에다 동기화걸지않고 생성직전에 영역만 잡아줄수있다.효율.
	// 싱크로나이즈드 동기화 이용하면 여러가지 효율적면에서 좀 떨어지는 면이 있다
	// 동시접근이 안되니깐 프로세스 처리가 길다고 가정하면 계속기다려야 하는 불편암이
	// 있다.그래서 밑에 처럼 인스턴스화 하기 전의 생성 직전의 영역만 잡는다. 함수전체
	// 보다는 좀더 효율적인 작업을 할 수 있다.
	public static SingleTonEx4 getInstance() {
		synchronized (SingleTonEx4.class) {
			if (instance == null) {
				instance = new SingleTonEx4();
				// SingleTonEx1은 클래스가 static이라 시작하자마자 바로 인스턴스가 생성되었지만 아예 객체가 미리 만들어져버리지만
				// 요 SingleTonEx2는 getInstance()를 실행했을 때 동시에 바로 어떤 새로운 다른 처리를 할 수 있다.
				Random rand = new Random();
				// static 메소드에서는 non-static 변수를 못쓰므로
				// instance의 randomNumber 자기자신의자식멤버로 접근한다
				instance.randomNumber = rand.nextInt(5) + 1;
			}
		}

		return instance;
	}

	public int getRandomNumber() {
		return randomNumber;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonTest.java&lt;/p&gt;
&lt;pre id=&quot;code_1680186829701&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

public class SingleTonTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(&quot;------------시작------------&quot;);
		// 싱글톤 객체를 만들어야 하는데 우리는 싱클톤객체를 생성하지 못하고
		// 반환만 받을수있다.
		SingleTonEx1 singleton1 = SingleTonEx1.getInstance();
		SingleTonEx1 singleton2 = SingleTonEx1.getInstance();

		if (singleton1 == singleton2) {
			System.out.println(&quot;서로 같은 객체입니다...&quot;);
		} else {
			System.out.println(&quot;서로 다른 객체입니다....&quot;);
			System.out.println(&quot;-------------end-------------&quot;);
		}

//		SingleTonEx2 singleton3 = SingleTonEx2.getInstance();
//		SingleTonEx2 singleton4 = SingleTonEx2.getInstance();
//		
//		if(singleton3 == singleton4) {
//			System.out.println(&quot;서로 같은 객체입니다...&quot;);
//		}else {
//			System.out.println(&quot;서로 다른 객체입니다....&quot;);
//			System.out.println(&quot;-------------end-------------&quot;);
//		}
//		
//		System.out.printf(&quot;singleton3 : %d, singleton4 : %d\n&quot;, singleton3.getRandomNumber(), singleton4.getRandomNumber());

		ThreadSt threadSt1 = new ThreadSt();
		ThreadSt threadSt2 = new ThreadSt();
		Thread thread1 = new Thread(threadSt1, &quot;1&quot;);
		Thread thread2 = new Thread(threadSt2, &quot;2&quot;);

		thread1.start();
		thread2.start();

//		System.out.println(&quot;-----SingleTonEx2 를 여러 사람이 동시에 만든다.-----&quot;);
//		
//		ThreadStEx2 threadStEx2_1 = new ThreadStEx2();
//		ThreadStEx2 threadStEx2_2 = new ThreadStEx2();
//		Thread thread3 = new Thread(threadStEx2_1, &quot;3&quot;);
//		Thread thread4 = new Thread(threadStEx2_2, &quot;4&quot;);
//		
//		thread3.start();
//		thread4.start();
	}

}

class ThreadSt implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		long start = System.currentTimeMillis();

		for (int i = 0; i &amp;lt; 6; i = i + 1) {

//			System.out.println(&quot;SingleTonEx2 : &quot; + SingleTonEx2.getInstance().getRandomNumber());
//			System.out.println(&quot;SingleTonEx3 : &quot; + SingleTonEx3.getInstance().getRandomNumber());
//			System.out.println(&quot;SingleTonEx4 : &quot; + SingleTonEx4.getInstance().getRandomNumber());
			// 위와 같이 SingleTonEx2, SingleTonEx3, SingleTonEx4 세 개를
			// for 반복문에서 함께 돌리면 확률적으로 SingleTonEx2 객체에서 무작위수가
			// 다른 값이 나올 경우가 낮아지기 때문에 SingleTonEx2 와 SingleTonEx3
			// 두 개만 돌린다. 그러면 확률적으로 겹치지 않는 값이 나오고,
			// SingleTonEx2 를 동시에 두 스레드가 run() 함수를 돌릴 때
			// 싱글톤 패턴이 아닌 객체가 2개가 생기는 경우가 잘 나오게 된다.
			// 위와 같이 생각하고 나서 아래와 같이 SingleTonEx2 와 SingleTonEx3
			// 만 출력하도록 하였지만 SingleTonEx2, SingleTonEx3,
			// SingleTonEx4 세 가지 다 출력하였을 때와 차이 없이 다른 값이 잘
			// 나오지 않았다.그냥 계속 빠르게 연속적으로 Java Application 을
			// 실행하지 않고 시간여유를 두면서 실행하거나 Remove All Terminated
			// Launches 라는 Eclipse IDE 하단에 콘솔창에 콘솔탭 옆에 엑스2개표시를
			// 누르고 다시 실행하다보면 어쩌다가 SingleTonEx2 객체 2개가 생기면서
			// 랜덤값이 다르게
			// 배정되어 나온다.

			System.out.println(&quot;SingleTonEx2 : &quot; + SingleTonEx2.getInstance().getRandomNumber());
			System.out.println(&quot;SingleTonEx3 : &quot; + SingleTonEx3.getInstance().getRandomNumber());

			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		long end = System.currentTimeMillis();
		System.out.println(&quot;실행 시간 : &quot; + (end - start) / 1000.0);
		// SingleTonEx3 와 SingleTonEx4 에서 동기화를 걸어주는 위치에 따라서
		// 실행속도가 달라진다는 가정하에 시간을 재어보았지만 별 차이가 나지 않는다.
		// 동기화를 걸어주는 함수 내에 프로세스 처리가 길어야 하는데 그렇지 않아서 그런 듯 하다..
	}

}

class ThreadStEx2 implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i &amp;lt; 2; i++) {
			System.out.println(SingleTonEx2.getInstance().getRandomNumber());
		}

		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1680186915523&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;------------시작------------
서로 같은 객체입니다...
SingleTonEx2 : 0
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx3 : 3
SingleTonEx2 : 4
SingleTonEx3 : 3
실행 시간 : 1.275
실행 시간 : 1.275&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 SingleTonTest2.java&lt;/p&gt;
&lt;pre id=&quot;code_1680186983906&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

public class SingleTonTest2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(&quot;------------시작------------&quot;);
		// 싱글톤 객체를 만들어야 하는데 우리는 싱클톤객체를 생성하지 못하고
		// 반환만 받을수있다.
		SingleTonEx1 singleton1 = SingleTonEx1.getInstance();
		SingleTonEx1 singleton2 = SingleTonEx1.getInstance();

		if (singleton1 == singleton2) {
			System.out.println(&quot;서로 같은 객체입니다...&quot;);
		} else {
			System.out.println(&quot;서로 다른 객체입니다....&quot;);
			System.out.println(&quot;-------------end-------------&quot;);
		}

		ThreadSt2 threadSt1 = new ThreadSt2();
		ThreadSt2 threadSt2 = new ThreadSt2();
		Thread thread1 = new Thread(threadSt1, &quot;1&quot;);
		Thread thread2 = new Thread(threadSt2, &quot;2&quot;);

		thread1.start();
		thread2.start();

	}

}

class ThreadSt2 implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		long start = System.currentTimeMillis();

		for (int i = 0; i &amp;lt; 6; i = i + 1) {

			System.out.println(&quot;SingleTonEx2 : &quot; + SingleTonEx2.getInstance().getRandomNumber());
			System.out.println(&quot;SingleTonEx4 : &quot; + SingleTonEx4.getInstance().getRandomNumber());

			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		long end = System.currentTimeMillis();
		System.out.println(&quot;실행 시간 : &quot; + (end - start) / 1000.0);
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1680187009138&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;------------시작------------
서로 같은 객체입니다...
SingleTonEx2 : 0
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx2 : 5
SingleTonEx2 : 5
SingleTonEx4 : 5
SingleTonEx4 : 5
실행 시간 : 1.272
실행 시간 : 1.273&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/571</guid>
      <comments>https://sapwha.tistory.com/571#entry571comment</comments>
      <pubDate>Thu, 30 Mar 2023 23:37:24 +0900</pubDate>
    </item>
    <item>
      <title>Java afterLast()</title>
      <link>https://sapwha.tistory.com/570</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 ScrollResultSetEx.java&lt;/p&gt;
&lt;pre id=&quot;code_1679929508956&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

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

public class ScrollResultSetEx {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
		String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
		Connection conn = DriverManager.getConnection(url, &quot;scott&quot;, &quot;a1234&quot;);
		
		System.out.println(&quot;접속 완료!!&quot;);
		
		Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);	//양방향이 가능한 스크롤타입,단지 커서의위치에서 데이타를 동적으로 내용을 수정할수있는가에 대해서는 동적으로 데이타내용을 수정할수는 없다
		
		String query = &quot;select * from person order by no&quot;;
		ResultSet rs = st.executeQuery(query);
		System.out.println(&quot;번호\t이름\t몸무게\t생일&quot;);
		
		rs.afterLast();	//마지막행 다음이후에 커서위치 옮김
		while(rs.previous()) {
			int no = rs.getInt(1);
			String name = rs.getString(2);
			Double weight = rs.getDouble(3);
			Date birthday = rs.getDate(4);
			System.out.println(no+&quot;\t&quot;+name+&quot;\t&quot;+weight+&quot;\t&quot;+birthday);
		}
		
		System.out.println(&quot;----커서위치 바꾸기----&quot;);
		rs.absolute(5);
		System.out.println(rs.getInt(1)+&quot;,&quot;+rs.getString(2)+&quot;,&quot;+rs.getRow());
		
		if(rs != null) rs.close();
		if(st != null) st.close();
		if(conn != null) conn.close();
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1679929526658&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;접속 완료!!
번호	이름	몸무게	생일
0	null	0.0	null
0	null	0.0	null
5	김말똥	100.2	2023-02-20
4	장관우	96.5	2022-02-23
3	김관우	96.5	2022-02-23
2	유비	96.5	2022-02-23
2	김관우	90.9	2023-02-19
1	장비	96.5	2022-02-21
----커서위치 바꾸기----
4,장관우,5&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;void java.sql.ResultSet.afterLast() throws SQLException&lt;/div&gt;
&lt;div&gt;요 ResultSet 객체의 끝으로 커서를 이동시킨다, 바로 마지막 행 뒤로 이동시킨다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/570</guid>
      <comments>https://sapwha.tistory.com/570#entry570comment</comments>
      <pubDate>Tue, 28 Mar 2023 00:07:06 +0900</pubDate>
    </item>
    <item>
      <title>Java JDBC&amp;trade; 4.2 API</title>
      <link>https://sapwha.tistory.com/569</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 Query_insert.java&lt;/p&gt;
&lt;pre id=&quot;code_1677508355018&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.sql.*;

public class Query_insert {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		try {
			// Class.forName이 다음의 4가지를 모두 처리해준다
			// 동적메모리 드라이버객체 로딩
			// Class.forName 메소드가 다음의 3가지 일을 모두 한다.
			// 1.JDBC 드라이버를 메모리에 로딩
			// 2.JDBC 드라이버 객체를 만든다.
			// 3.드라이버 객체를 DriverManager에 등록
			Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);

			System.out.println(&quot;드라이버 로딩되었습니다..!!!&quot;);

			// 드라이버매니저를 이용해 등록해주기
			String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;; // JDBC 는 프로토콜,약속,여러가지타입중에 thin타입
			String user = &quot;scott&quot;, pw = &quot;a1234&quot;;

			// Driver매니저이용하면서 그 연결에 관련된 커넥션객체반환된다
			// CONNECTION 을 얻어오는 과정
			Connection c = DriverManager.getConnection(url, user, pw);
			System.out.println(&quot;데이타베이스에 접속 성공!!&quot;);
			// 질의문을 전송하기위한 STATEMENT 객체 생성
			Statement st = c.createStatement();// connection 객체가 여러가지 연결 정보를 담고있어 이를 이용한다
			String sql = &quot;insert into member values(6, '장동민', '010-212-2121', '서울 마포구 아현동')&quot;;

			int cnt = st.executeUpdate(sql);
			System.out.println(cnt + &quot;개 로우가 삽입되었습니다..!!&quot;);

			if (st != null)
				st.close();
			if (c != null)
				c.close();

		} catch (ClassNotFoundException | SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1677508369569&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;드라이버 로딩되었습니다..!!!
데이타베이스에 접속 성공!!
1개 로우가 삽입되었습니다..!!&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JDBC&amp;trade; 4.2 API 가 포함하는 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC&amp;trade; 4.2 API 는 JDBC 코어(핵심) API 라고 불리는 java.sql 모음과 JDBC 선택적 모음 API 라고 불리는 javax.sql 묶음을 둘 다 포함한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;java.sql 패키지가 포함하는 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.sql 패키지는 다음의 것들을 위해 API 를 포함한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DriverManager 장치를 통해 데이타베이스에 연결하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DriverManager class -- 드라이버에 연결한다.&lt;/li&gt;
&lt;li&gt;SQLPermission class -- applet 과 같은 Security Manager 내부에서 실행하는 코드가 DriverManager 를 통하여 logging 스트림을 설정하려고 시도할 때 허가를 내준다.&lt;/li&gt;
&lt;li&gt;Driver interface -- JDBC 기술(&quot;JDBC 드라이버들&quot;) 에 기반하여 드라이버들을 등록하고 드라이버들에 연결하기 위해 API 를 제공한다; 일반적으로 DriverManager 클래스에 의해서만 사용된다.&lt;/li&gt;
&lt;li&gt;DriverPropertyInfo class -- JDBC 드라이버 속성들을 제공한다; 일반적인 사용자가 사용하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이타베이스에 SQL 문들을 보내기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Statement -- 기본 SQL 문들을 보내려고 사용된다.&lt;/li&gt;
&lt;li&gt;PreparedStatement -- 준비된 기재문들 이나 기본 SQL 문들 (Statement 에서 파생된) 을 보내기 위해 사용된다.&lt;/li&gt;
&lt;li&gt;CallableStatement -- 데이타베이스에 저장된 절차들 (PreparedStatement 에서 파생된) 을 호출하기 위해서 사용된다.&lt;/li&gt;
&lt;li&gt;Connection interface -- 기재문들을 생성하고 연결들과 그 연결들의 속성들을 관리하기 위한 메서드들을 제공한다.&lt;/li&gt;
&lt;li&gt;Savepoint -- 트랜잭션(상호작용의 단위, 거래) 내에서 특정저장지점들을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;한개의 질의문의 그 결과들의 정보를 끌어내거나 새로운 정보로 만들기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ResultSet interface&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Java 프로그래밍 언어에서 클래스들과 인터페이스(규격)들에 대해서 일치하는 SQL 형식들을 위한 표준 사상(어떤 값을 다른 값에 대응시키는 과정)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Array interface -- SQL ARRAY 에 사상&lt;/li&gt;
&lt;li&gt;Blob interface -- SQL BLOB 에 사상&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Clob interface -- SQL CLOB 에 사상&lt;/li&gt;
&lt;li&gt;Date class -- SQL DATE 에 사상&lt;/li&gt;
&lt;li&gt;NClob interface -- SQL NCLOB 에 사상&lt;/li&gt;
&lt;li&gt;Ref interface -- SQL REF 에 사상&lt;/li&gt;
&lt;li&gt;RowId interface -- SQL ROWID 에 사상&lt;/li&gt;
&lt;li&gt;Struct interface -- SQL STRUCT 에 사상&lt;/li&gt;
&lt;li&gt;SQLXML interface -- SQL XML 에 사상&lt;/li&gt;
&lt;li&gt;Time class -- SQL TIME 에 사상&lt;/li&gt;
&lt;li&gt;Timestamp class -- SQL TIMESTAMP 에 사상&lt;/li&gt;
&lt;li&gt;Types class -- SQL types 를 위한 상수들을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/569</guid>
      <comments>https://sapwha.tistory.com/569#entry569comment</comments>
      <pubDate>Tue, 28 Feb 2023 00:09:28 +0900</pubDate>
    </item>
    <item>
      <title>Java - java.sql</title>
      <link>https://sapwha.tistory.com/568</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 PreparedStatementEx1.java&lt;/p&gt;
&lt;pre id=&quot;code_1677506897516&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class PreparedStatementEx1 {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
		String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
		Connection conn = DriverManager.getConnection(url, &quot;scott&quot;, &quot;a1234&quot;);

		System.out.println(&quot;접속 완료!&quot;);

		String sql = &quot;select count(*) from member where addr = ?&quot;;

		String addr = args[0];

		PreparedStatement pst = conn.prepareStatement(sql);

		pst.setString(1, addr);

		ResultSet rs = pst.executeQuery();

		rs.next();
		int n = rs.getInt(1);

		if (n &amp;gt; 0) {
			System.out.println(addr + &quot;지역 회원은 &quot; + n + &quot;명입니다.&quot;);

			// addr에 사는 사람의 정보를 출력

			String sql2 = &quot;select * from member where addr = ?&quot;;

			PreparedStatement pst2 = conn.prepareStatement(sql2);
			pst2.setString(1, addr);
			ResultSet rs2 = pst2.executeQuery();

			while (rs2.next()) {
				int no = rs2.getInt(&quot;no&quot;);
				String name = rs2.getString(&quot;name&quot;);
				String hp = rs2.getString(&quot;hp&quot;);
				String address = rs2.getString(&quot;addr&quot;);
				System.out.println(no + &quot;\t&quot; + name + &quot;\t&quot; + hp + &quot;\t&quot; + address);
			} // while
			if (rs2 != null)
				rs2.close();
			if (pst2 != null)
				pst2.close();
		} else {
			System.out.println(addr + &quot;지역 회원은 없습니다....&quot;);
		}
		if (rs != null)
			rs.close();
		if (pst != null)
			pst.close();
		if (conn != null)
			conn.close();
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eclipse IDE 메뉴 &amp;gt; Run &amp;gt; Run Configurations... &amp;gt; Arguments &amp;gt; Program arguments: 밑에 TextArea 에 찾고 싶은 주소를 입력한다. &amp;gt; Apply &amp;gt; Run&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경 을 TextArea 에 쓰고 나서 실행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1677506912188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;접속 완료!
경지역 회원은 없습니다....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충청도 를 TextArea 에 쓰고 나서 실행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1677507433592&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;접속 완료!
충청도지역 회원은 5명입니다.
16	송인자	010-4321-3214	충청도
16	이지연	010-4221-2214	충청도
16	장진미	010-4121-2254	충청도
17	오원석	010-4129-3254	충청도
18	박건우	010-4121-2214	충청도&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;java.sql&lt;/div&gt;
&lt;div&gt;sql 패키지는 JavaTM 프로그래밍 언어를 사용하여 데이타 출처 (대개 관계형 데이타베이스) 안에 저장된 데이타에 접근하고 가공(처리)하기 위해서 API 를 제공한다.&lt;/div&gt;
&lt;div&gt;요 API 는 다른 다양한 데이타 출처들 (관계형 데이타베이스들) 에 접근하기 위해서 다른 다양한 드라이버들이 동적으로 설치되어질 수 있도록 하는 방법(수단)인 한개의 프레임워크(뼈대)를 포함한다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/568</guid>
      <comments>https://sapwha.tistory.com/568#entry568comment</comments>
      <pubDate>Mon, 27 Feb 2023 23:27:08 +0900</pubDate>
    </item>
    <item>
      <title>Java CharArrayReader class</title>
      <link>https://sapwha.tistory.com/567</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 OracleClob.java&lt;/p&gt;
&lt;pre id=&quot;code_1677503705779&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import oracle.jdbc.OracleResultSet;
import oracle.sql.CLOB;

public class OracleClob {
	/*
	 * 오라클에 CLOB데이터를 입력하기위해서는 다른 field의 데이터와 함께 넣을 수 없다. CLOB데이터 혼자서만 입력 가능하다.
	 * 
	 * 순서&amp;gt;&amp;gt;&amp;gt; 1. CLOB를 제외한 Field 데이타를 가지는 로우를 먼저 입력한다. 2. 해당 로우에 lock 을 걸어준다.현재 이
	 * ROW에 접근을 할 수 없게 만들어 준다. 3. 해당 CLOB 필드(컬럼)에 데이터를 입력한다. 로우를 사용하는 사용자만이 그 ROW를
	 * 사용할 수 있다. 입력이 다 끝나게 되면 LOCK 이 풀린다. 다른 사람들이 사용할 수 없게 LOCK 을 걸었던 것이다.
	 * 
	 * SQL&amp;gt; create table clob_table( no number(8), title varchar2(100) not null,
	 * author varchar2(10) not null, contents clob );
	 */
//	public static void main(String[] args) throws Exception {
//		// TODO Auto-generated method stub
//		Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
//		String user = &quot;scott&quot;, pwd = &quot;a1234&quot;;
//		String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
//		Connection conn = DriverManager.getConnection(url, user, pwd);
//
//		conn.setAutoCommit(false);// 중간에오류났을때 커밋실행 안되도록한다
//
//		// 동시성(Concurrency)
//		// 웹 서비스에서는 다수의 사용자들이 데이타베이스에 동시에 접근하는 경우가 빈번히
//		// 발생한다. 때문에 데이타의일관성에 대한 처리가 필요하다. 이를 동시성문제 라고
//		// 한다. 동시성 문제란, 공통된 자원에 동시에 들어온 여러 개의 요청이 모두 읽고
//		// 쓰는 작업을 하려고 하는 경우에 발생할 수 있는 문제를 말한다.
//		// 동시성 문제는 완전한 해결이 아닌 적절한 해결(제어)에 더 적합하다고 한다.
//		// 동시성과 일관성은 하나가 증가하면 다른 하나는 감소하는 트레이드오프의 관계라고
//		// 하며 그렇기 때문에 해당되는 로직의 특성에 따라서 적절하게 균형을 설정하는 것이
//		// 중요하다고 한다.
//		// 비관적 락(Pessimistic Lock)
//		// 자원에 대한 동시 요청이 발생하여 일관성에 문제가 생길 것이라고 비관적으로 생각
//		// 하고 이를 방지하기 위해 트랜잭션이 시작될 때 락을 먼저 거는 방식이다.
//		// 비관적 락은 배타 락 (exclusive lock) 과 공유 락 (shared lock) 이라는
//		// 두가지 옵션이 있다고 한다.
//		// 공유 락을 걸면 다른 트랜잭션에서는 읽기는 가능하지만 쓰기가 불가능하다. 반면
//		// 배타 락을 걸면 다른 트랜잭션에서 읽기와 쓰기가 모두 불가능하다.
//		// 배타 락은 쿼리로 보면 SELECT ~ FOR UPDATE 로 나타낼 수 있다.
//		// 'SELECT ~ FOR UPDATE'
//		// 비관적 락(Pessimistic Lock) 중 배타 락(exclusive lock) 을 적용
//		// 하는 쿼리로 'UPDATE 를 하기 위해 SELECT 를 한다.' 즉, '이 데이타는
//		// 내가 조회하여 수정 중이기 때문에 다른 사람은 건드릴 수 없다.'는 뜻이라고 하며,
//		// 다르게 이야기하면 동시성 제어를 위해 특정 데이타에 대해서 Lock 을 거는 방식
//		// 이라고 한다.
//		String query = &quot;insert into clob_table values(?,?,?,empty_clob())&quot;;
//		// clob 데이타필드의 경우 기본적으로 empty_clob()를 선언해서 locator값.필드의 초기화상태로 만든다.
//		PreparedStatement pst = conn.prepareStatement(query);
//		// clob만 빼고 나머지 값 세팅
//		pst.setInt(1, 1);
//		pst.setString(2, &quot;자바 JDBC 프로그래밍 연습&quot;);
//		pst.setString(3, &quot;아무개&quot;);
//
//		int rowCnt = pst.executeUpdate();
//		pst.close();
//		// 방금 생성한 레코드,행,row에 락을 걸어준다.insert문으로 넣었던 로우를 제어.
//		if (rowCnt == 1) {
//			// for update 절이 lock 을 거는 그러한 그 sql 명령어가 된다.
//			// no가 1인 데이타 로우에 락을 걸겠다.
//			// 결과값은 empty_clob로 해서 locator만 가져와 진다.
//			// lock 걸어준다.
//			String sql = &quot;select contents from clob_table where no = ? for update&quot;;
//			pst = conn.prepareStatement(sql);// 생성
//			pst.setInt(1, 1);// 번호가 1번인 레코드를 락을 거는데 그거로부터 컨텐츠 가져오겠다.
//			ResultSet rs = pst.executeQuery();
//
//			String strClob = &quot;String query = \&quot;insert into clob_table values(?,?,?,empty_clob())\&quot;;&quot;;
//
//			if (rs.next()) {
//				// oracleresultset 으로 캐스팅을 해줘야 한다.
//				// 가져온 resultset은 컨텐츠에 있는 값이니깐 locator값을 가져온다
//				// 요에 대한 값을 얻어오기 위해서 rs라는 놈은 캐스팅해줘야 한다. 오라클 리절트 셋으로다.
//				// clob 타입을 가져오려면, clob는 오라클사 객체이므로 캐스팅해줘야 한다
//				CLOB clob = ((OracleResultSet) rs).getCLOB(&quot;contents&quot;);
//				// 데이타출력위한 출력스트림 만들기
//				@SuppressWarnings(&quot;deprecation&quot;)
//				Writer writer = clob.getCharacterOutputStream();
//				// 하나하나 캐릭터 배열로 읽어오겠다.
//				Reader reader = new CharArrayReader(strClob.toCharArray());
//
//				// 버퍼하나만든다
//				char[] buffer = new char[1024];
//				int read = 0;// 해당 크기가 몇바이트인가
//
//				// read는 몇바이트인지 체크해 주는 변수이다.한바이트씩 읽어온다.
//				// 버퍼의 크기가 1024이다. 위치가 0에서부터 1024크기까지 해서 읽어오겠다.
//				// 그럼 strClob를 읽어온 수만큼 버퍼의 크기를 설정할 수 있다.
//				// 읽어온 수만큼 늫겠다.
//				// 데이터가 -1이 아니면 1024만큼 한꺼번에 읽어서 버퍼에 집어넣고,...
//				// 여기 있는 데이타를 가져와서 clob에 넣어야 겠다.(쓴다 wirte)
//				// 읽어온만큼만 적어준다.
//				// wirter 아웃풋스트림은 clob 에 적을 수 있는 출력스트림이다.
//				while ((read = reader.read(buffer, 0, 1024)) != -1) {
//					// 읽어온 바이트 수 만큼(=read)만 clob 에 쓰겠다는 의미다.
//					// 해당 컨텐츠 필드의 clob 에다가 쓰겠다. 읽어온 만큼(read수)
//					// 적어주겠다.
//					writer.write(buffer, 0, read);
//				}
//
//				reader.close();
//				writer.close();
//			} // if
//
//			conn.commit();
//			conn.setAutoCommit(true);
//
//			if (rs != null)
//				rs.close();
//		}
//		if (conn != null)
//			conn.close();
//	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
			String user = &quot;scott&quot;, pwd = &quot;a1234&quot;;
			String url = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
			Connection conn = DriverManager.getConnection(url, user, pwd);
			conn.setAutoCommit(false);// 중간에오류났을때 커밋실행 안되도록한다
			String query = &quot;insert into clob_table values(?,?,?,empty_clob())&quot;;
			// clob 데이타필드의 경우 기본적으로 empty_clob()를 선언해서 locator값.필드의 초기화상태로 만든다.
			PreparedStatement pst = conn.prepareStatement(query);
			// clob만 빼고 나머지 값 세팅
			pst.setInt(1, 1);
			pst.setString(2, &quot;자바 JDBC 프로그래밍 연습&quot;);
			pst.setString(3, &quot;아무개&quot;);
			int rowCnt = pst.executeUpdate();
			pst.close();
			// 방금 생성한 레코드,행,row에 락을 걸어준다.insert문으로 넣었던 로우를 제어.
			if (rowCnt == 1) {
				// for update 절이 lock 을 거는 그러한 그 sql 명령어가 된다.
				// no가 1인 데이타 로우에 락을 걸겠다.
				// 결과값은 empty_clob로 해서 locator만 가져와 진다.
				// lock 걸어준다.
				String sql = &quot;select contents from clob_table where no = ? for update&quot;;
				pst = conn.prepareStatement(sql);// 생성
				pst.setInt(1, 1);// 번호가 1번인 레코드를 락을 거는데 그거로부터 컨텐츠 가져오겠다.
				ResultSet rs = pst.executeQuery();

				String strClob = &quot;String query = \&quot;insert into clob_table values(?,?,?,empty_clob())\&quot;;&quot;;

				if (rs.next()) {
					// oracleresultset 으로 캐스팅을 해줘야 한다.
					// 가져온 resultset은 컨텐츠에 있는 값이니깐 locator값을 가져온다
					// 요에 대한 값을 얻어오기 위해서 rs라는 놈은 캐스팅해줘야 한다. 오라클 리절트 셋으로다.
					// clob 타입을 가져오려면, clob는 오라클사 객체이므로 캐스팅해줘야 한다
					CLOB clob = ((OracleResultSet) rs).getCLOB(&quot;contents&quot;);
					// 데이타출력위한 출력스트림 만들기
					@SuppressWarnings(&quot;deprecation&quot;)
					Writer writer = clob.getCharacterOutputStream();
					// 하나하나 캐릭터 배열로 읽어오겠다.
					Reader reader = new CharArrayReader(strClob.toCharArray());

					// 버퍼하나만든다
					char[] buffer = new char[1024];
					int read = 0;// 해당 크기가 몇바이트인가

					// read는 몇바이트인지 체크해 주는 변수이다.한바이트씩 읽어온다.
					// 버퍼의 크기가 1024이다. 위치가 0에서부터 1024크기까지 해서 읽어오겠다.
					// 그럼 strClob를 읽어온 수만큼 버퍼의 크기를 설정할 수 있다.
					// 읽어온 수만큼 늫겠다.
					// 데이터가 -1이 아니면 1024만큼 한꺼번에 읽어서 버퍼에 집어넣고,...
					// 여기 있는 데이타를 가져와서 clob에 넣어야 겠다.(쓴다 wirte)
					// 읽어온만큼만 적어준다.
					// wirter 아웃풋스트림은 clob 에 적을 수 있는 출력스트림이다.
					while ((read = reader.read(buffer, 0, 1024)) != -1) {
						// 읽어온 바이트 수 만큼(=read)만 clob 에 쓰겠다는 의미다.
						// 해당 컨텐츠 필드의 clob 에다가 쓰겠다. 읽어온 만큼(read수)
						// 적어주겠다.
						writer.write(buffer, 0, read);
					}

					reader.close();
					writer.close();
				} // if
				conn.commit();
				conn.setAutoCommit(true);

				if (rs != null)
					rs.close();
			}
			if (conn != null)
				conn.close();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// 동시성(Concurrency)
		// 웹 서비스에서는 다수의 사용자들이 데이타베이스에 동시에 접근하는 경우가 빈번히
		// 발생한다. 때문에 데이타의일관성에 대한 처리가 필요하다. 이를 동시성문제 라고
		// 한다. 동시성 문제란, 공통된 자원에 동시에 들어온 여러 개의 요청이 모두 읽고
		// 쓰는 작업을 하려고 하는 경우에 발생할 수 있는 문제를 말한다.
		// 동시성 문제는 완전한 해결이 아닌 적절한 해결(제어)에 더 적합하다고 한다.
		// 동시성과 일관성은 하나가 증가하면 다른 하나는 감소하는 트레이드오프의 관계라고
		// 하며 그렇기 때문에 해당되는 로직의 특성에 따라서 적절하게 균형을 설정하는 것이
		// 중요하다고 한다.
		// 비관적 락(Pessimistic Lock)
		// 자원에 대한 동시 요청이 발생하여 일관성에 문제가 생길 것이라고 비관적으로 생각
		// 하고 이를 방지하기 위해 트랜잭션이 시작될 때 락을 먼저 거는 방식이다.
		// 비관적 락은 배타 락 (exclusive lock) 과 공유 락 (shared lock) 이라는
		// 두가지 옵션이 있다고 한다.
		// 공유 락을 걸면 다른 트랜잭션에서는 읽기는 가능하지만 쓰기가 불가능하다. 반면
		// 배타 락을 걸면 다른 트랜잭션에서 읽기와 쓰기가 모두 불가능하다.
		// 배타 락은 쿼리로 보면 SELECT ~ FOR UPDATE 로 나타낼 수 있다.
		// 'SELECT ~ FOR UPDATE'
		// 비관적 락(Pessimistic Lock) 중 배타 락(exclusive lock) 을 적용
		// 하는 쿼리로 'UPDATE 를 하기 위해 SELECT 를 한다.' 즉, '이 데이타는
		// 내가 조회하여 수정 중이기 때문에 다른 사람은 건드릴 수 없다.'는 뜻이라고 하며,
		// 다르게 이야기하면 동시성 제어를 위해 특정 데이타에 대해서 Lock 을 거는 방식
		// 이라고 한다.

	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WINDOWS 내 system32 폴더 내에 cmd.exe 를 실행해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sqlplus 를 실행하여 사용자계정에 로그인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 CLOB_TABLE 테이블에 NO 컬럼이 1 인 레코드셋(ROW, 행)이 있었기에 DELETE FROM CLOB_TABLE; 명령어로 모든 내용을 지운다음에 위의 코드를 실행하였다. 그러나 프로그램이 종료되지 않고 빨간 버튼이 계속 켜져 있는다. 코드가 잘못되었다고 판단을 하여 SELECT ~ FOR UPDATE 문이나 setAutoCommit(boolean autoCommit) 메서드가 서로 맞지 않아서 락이 계속 걸려서 예외가 발생해서 프로그램이 계속 켜져있다고 상상을 하였다. 하지만 찾아보니 SELECT ~ FOR UPDATE 문을 쓸 때는 setAutoCommit(boolean autoCommit) 메서를 쓸 때 boolean autoCommit 값에 false 값을 대입해주고 같이 쓰는 것이다. 그래서 코드 사이마다 콘솔에 출력하는 문을 두었는데 ResultSet rs = pst.executeQuery(); 문 다음부터 진행이 안된다. 그래서 executeQuery() 메서드에서 예외가 발생했다고 봤지만, 실제로 예외와 관련되어 출력되는 오류가 나오지 않는다. executeQuery() 메서드와 SELECT ~ FOR UPDATE 문을 함께 쓰거나 setAutoCommit(boolean autoCommit) 메서드를 함께 쓰면 락이 계속 걸려서 기다려야만 하는 상황이 되었다고 생각이 들어 관련해서 찾는데 시간이 오래 걸렸다. cmd.exe 창에서 sqlplus 를 exit 하고 나온 뒤에 다시 sqlplus 에 사용자계정으로 로그인하여 SELECT * FROM CLOB_TABLE; 을 때리니 CONTENTS 필드(컬럼)에 들어가야할 내용이 출력되어 정상적으로 나온다. 이전에는 나오지 않고 ResultSet rs = pst.executeQuery(); 문에서 멈추고 다음으로 나아가지 않았던 부분이 잘 실행되고 있다. sqlplus 연결을 제대로 끊지 않고 프로그램이 계속 돌아가는 문제라고 본다. 예외 발생 오류 내용이 출력되지 않아서 try 문과 catch 문을 사용한다. 실행해보지만 예외 발생 오류 내용이 여전히 출력이 안된다. cmd.exe 에서 sqlplus 를 exit 했다가 로그인 했다가를 여러번 한다. 그리고 위으 프로그램을 몇 번 실행한다. 그러다가 어쩔 때는 cmd.exe 에서 SELECT 쿼리를 날렸을 때 결과가 나오지만 다시 DELETE 쿼리로 모든 테이블 내용을 지우고서 위의 코드를 다시 실행해서 확인해 보면 안나올 때도 있고 나올 때도 있다. 그러다 보니 cmd.exe 창에 sqlplus 에서 COMMIT; 명령을 안날렸다는 것을 알았다. sqlplus 를 cmd.exe 로 실행할 때 SQL 명령문을 쓸 때마다 DBMS 에 실행을 반영하려면 COMMIT; 명령문을 때려야 한다. 그래서 cmd.exe 에서 DELETE FROM CLOB_TABLE; 과 COMMIT; 명령문을 때린 후에 위의 코드를 실행하고 나서 cmd.exe 에서 SELECT 문으로 테이블 내용을 확인하니 CONTENTS 내용이 출력이 된다. 위의 코드에서는 commit() 메서드를 써서 수정한 내용을 DBMS 에 반영을 하였지만 cmd.exe 에서는 수정 시 마다 매번 반영을 해야만 한다. &lt;span style=&quot;background-color: #ffc1c8; color: #006dd7;&quot;&gt;cmd.exe 에서 sqlplus 를 사용할 때는 COMMIT; 문을 쓴다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.io.CharArrayReader&lt;/p&gt;
&lt;div&gt;CharArrayReader 클래스는 문자-입력 스트림(문자-입력 연속흐름)으로써 사용되어질 수 있는 문자 버퍼(장치)를 구현한다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.io.CharArrayReader.CharArrayReader(char[] buf)&lt;/p&gt;
&lt;div&gt;CharArrayReader(char[] buf) 생성자 메서드는 지정된 문자들의 배열로부터 하나의 CharArrayReader 를 생성한다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char[] buf 파라메터(인수)는 입력 버퍼(장치) 이다. (복사되지 않는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char[] java.lang.String.toCharArray()&lt;/p&gt;
&lt;div&gt;toCharArray() 메서드는 요 문자열을 한개의 새 문자 배열로 변환한다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toCharArray() 메서드는 요 문자열의 길이를 가지고 요 문자열로 나타내어진 문자 배열(연속)을 포함하도록 초기화되어진 내용을 가지는 하나의 새롭게 할당된 문자 배열을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;int java.io.Reader.read(char[] cbuf, int off, int len) throws IOException&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;read(char[] cbuf, int off, int len) 메서드는 문자들을 읽어서 한 배열의 한 부분에 넣는다. 요 메서드는 어떤 입력이 가능할 때가지, 입출력 오류가 발생할 때, 또는 그 스트림(흐름)의 끝에 도달했을 때 막힌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char[] cbuf 파라메터는 목적지 버퍼(장치) 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int off 파라메터는 문자들을 저장하기 시작할 출발점(출발지점) 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int len 파라메터는 최대로 읽을 문자들의 숫자이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;read(char[] cbuf, int off, int len) 메서드는 읽힌 문자들의 수를 반환하거나, 만약에 스트림의 끝에 도달하였다면 -1 을 반환한다.&lt;/p&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/567</guid>
      <comments>https://sapwha.tistory.com/567#entry567comment</comments>
      <pubDate>Mon, 27 Feb 2023 22:57:56 +0900</pubDate>
    </item>
    <item>
      <title>Java CallableStatement</title>
      <link>https://sapwha.tistory.com/566</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 ObjectSerTest.java&lt;/p&gt;
&lt;pre id=&quot;code_1677400716854&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//PS C:\Users\ydbon&amp;gt; sqlplus
//
//SQL*Plus: Release 11.2.0.1.0 Production on 수 3월 9 09:44:19 2022
//
//Copyright (c) 1982, 2010, Oracle.  All rights reserved.
//
//사용자명 입력: scott/a1234
//
//다음에 접속됨:
//Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
//With the Partitioning, OLAP, Data Mining and Real Application Testing options
//
//SQL&amp;gt; #객체들을 주고받기위해서는 직렬화과정이필요한데 객체에는 여러가지변수인스턴스들로이루어져있다.
//SP2-0734: &quot;객체들을 ...&quot;(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL&amp;gt; #그런멤버를스트림에옮기기위해 하나하나씩 변수들을 나열해서 전송해야 한다.
//SP2-0734: &quot;그런멤버를...&quot;(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL&amp;gt; @직렬화된 객체를 데이타베이스에 저장할수있는데 blob필드에 지정할수있다는것이다.
//SP2-0310: 파일 &quot;직렬화된.sql&quot;을 열 수 없습니다.
//SQL&amp;gt; 클래스만들때serializable을...써야한다
//SP2-0734: &quot;클래스만들...&quot;(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL&amp;gt; serializable interface를구현해야
//SP2-0734: &quot;serializab...&quot;(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SP2-0044: 명령어 목록을 보려면 HELP를
//빠져나가려면 EXIT를 입력하시오.
//SQL&amp;gt; 오라클칼럼에서 다시 가져오려면 역직렬화과정도거쳐야한다.
//SP2-0734: &quot;오라클칼럼...&quot;(으)로 시작되는 알 수 없는 명령 - 나머지 줄은 무시되었습니다.
//SQL&amp;gt; create table object_table(
//  2  no number,
//  3  obj_name varchar2(1000),
//  4  obj_value blob default empty_blob()
//  5  );
//
//테이블이 생성되었습니다.
//
//SQL&amp;gt; create sequence object_ser_seq increment by 1 start with 1;
//
//시퀀스가 생성되었습니다.

package javabasic;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

import oracle.sql.BLOB;

public class ObjectSerTest implements java.io.Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static final String driver_class = &quot;oracle.jdbc.driver.OracleDriver&quot;;
	static final String connectionURL = &quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;;
	static final String userId = &quot;scott&quot;;
	static final String userPassword = &quot;a1234&quot;;
	static final String getSequenceSQL = &quot;SELECT object_ser_seq.nextval FROM dual&quot;;
	static final String writeObjSQL = &quot;BEGIN&quot; + &quot; INSERT INTO object_table(no, obj_name, obj_value)&quot;
			+ &quot; VALUES(?,?,empty_blob())&quot; + &quot;RETURNING obj_value INTO ?; &quot; + &quot;END;&quot;;
	// 위의 프로시저에서 empty_blob()는 굳이 안넣어도 된다
	// returning obj_value into ? 에서 ?부분은 파라미터로 설정해서 처리할것
	// returning obj_value는 obj_value값을 받겠다는 것이다.(물음표)
	// obj_value값으로 받아야되는데 이때 받는 변수는 이제 자바에서 처리해야할 타입으로
	// OutParameter를 설정하겠다는 의미이다.물음표에는 java.sql.types.BLOB
	// 타입으로 요 obj_value값인 empty_blob()값을 받아서 처리하기 위해서
	// registerOutParameter로 등록을 해놓는 것이다.프로시저 문을 실행했을때
	// 그럼 프로시저에서 어떤 변숫값으로 returning obj_value INTO ?에서 물음표가
	// 어떤 변숫값으로 처리가 된다.그 변숫값을 이제 자바에서 받아가지고 처리하기 위해서
	// java.sql.Types 패키지에서 BLOB타입으로 등록을 해놓는 것이다.프로시저에서 받는
	// 값을 자바에서 처리하겠다.registerOutParameter의 의미다.

	// 직렬화된 객체를 불러온다(직렬화된 객체를 저장을 하고 그 저장된 객체를 다시 불러온다.)
	static final String readObjSQL = &quot;SELECT obj_value FROM object_table WHERE no = ?&quot;;

	// 직렬화된 객체를 write하는 메서드,저장한객체의넘버값을반환한다
	public static long writeObj(Connection conn, Object obj) throws Exception {
		long rec_key = getNextSeqVal(conn);// 시퀀스얻어와서 설정하기
		String className = obj.getClass().getName();
		CallableStatement stmt = conn.prepareCall(writeObjSQL);

		stmt.setLong(1, rec_key);
		stmt.setString(2, className);
		stmt.registerOutParameter(3, java.sql.Types.BLOB);
		stmt.executeUpdate();

		// BLOB는 오라클사객체이다
		BLOB blob = (BLOB) stmt.getBlob(3);// obj_value의 blob타입을 얻어온다
		// 스트림객체를 생성하기,blob와 연결되어 있는 아웃풋스트림이다.
		// 이런 스트림을 노드스트림이라고 한다.직접 blob와 연결되어있는 아웃풋스트림이기
		// 때문이다.실제 blob에 연결되어 있는 스트림이다.
		@SuppressWarnings(&quot;deprecation&quot;)
		OutputStream out = blob.getBinaryOutputStream();
		// 아웃풋스트림을 직렬화를 한다.직렬화하는 오브젝트아웃풋스트림을생성해줘야한다
		// 직렬화하는 아웃풋스트림
		// 노드를 연결하기 위한 브릿지 역할하는 브릿지 스트림역할이다.
		ObjectOutputStream oop = new ObjectOutputStream(out);// OutputStream과 연결해서 사용한다.
		// 직렬화
		oop.writeObject(obj);
		oop.flush();
		oop.close();
		out.close();
		stmt.close();
		System.out.println(&quot;직렬화 완료!!!&quot; + className);

		return rec_key;
	}

	// 직렬화된 객체가 실지 데이타베이스에 저장되는데 이저장되어있는객체를 역으로
	// 역직렬화를 시키는 방법. 저장되어있는객체를 반대로 객체화 하는 과정이다.
	// 디비에 저장된 객체를 불러오는 read 메소드
	public static Object readObj(Connection conn, long rec_key) throws Exception {
		PreparedStatement stmt = conn.prepareStatement(readObjSQL);
		// 요 해당 rec_key값은 write한후 돌려받은 키값이 된다.이부분은메인에서처리.
		stmt.setLong(1, rec_key);
		// 수행
		ResultSet rs = stmt.executeQuery();
		rs.next();// blob객체이므로 blob 객체 스트림을 통해서 얻어오면 되겠다.

		// InputStream을 통해서 getBlob에있는 내용을 읽어올수가 있는거죠.
		// InputStream 자체가 노드스트림이잖아요.직접 blob로부터연결되있기땜에
		// 이 노드스트림을 다시 역직렬화하기위해서는 오브젝트인풋스트림(역직렬화)이 필요하다
		InputStream is = rs.getBlob(1).getBinaryStream();// obj_value한개 blob객체의스트림
		// 그런데 역직렬화를 통해서 얻어와야 한다.
		// ObjectInputStream은 브릿지역할을해준다.is객체를이용해서 브릿지역할해
		// 줘야해요.그래야 역직렬화를할수있는것을생성한다.
		ObjectInputStream oip = new ObjectInputStream(is);

		Object obj = oip.readObject();

		// 클래스이름을 구해와서 역직렬화가 제대로 되었는지 확인한다
		String className = obj.getClass().getName();
		oip.close();
		is.close();
		if (rs != null)
			rs.close();
		if (stmt != null)
			stmt.close();
		System.out.println(&quot;역직렬화 완료!! &quot; + className);

		return obj;
	}

	// next sequence를 구하는 메소드,sequence의 다음값을 구한다
	private static long getNextSeqVal(Connection conn) throws Exception {

		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery(getSequenceSQL);
		rs.next();// nextValue값에 커서를 위치시키고 그걸 구해온다.
		long rec_key = rs.getLong(1);// 가져온값은nextVal 하나뿐이므로.
		if (rs != null)
			rs.close();
		if (stmt != null)
			stmt.close();
		return rec_key;
	}

	// 메인 메소드
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub

		Connection conn = null;

		System.out.println(&quot;JDBC 드라이버 로딩 -&amp;gt;&quot; + driver_class);
		Class.forName(driver_class);

		// 데이타베이스 연결접속
		System.out.println(&quot;데이타 베이스 접속 -&amp;gt; &quot; + connectionURL);
		conn = DriverManager.getConnection(connectionURL, userId, userPassword);
		System.out.println(&quot;접속 계정 : &quot; + userId);

		conn.setAutoCommit(false);

		// 직렬화가능한 클래스의 인스턴스 생성
		ObjectSerTest obj = new ObjectSerTest();
		// 객체를 직렬화해서 데이타베이스에 쓰는 과정이 필요하다(직렬화가 가능한 오브젝트를 사용해야 한다)

		// 직렬화된 객체를 oracle blob 컬럼(필드)에 저장
		long rec_key = writeObj(conn, obj);
		conn.commit();

		System.out.println(&quot;직렬화된 객체의 번호 -&amp;gt;&quot; + rec_key + &quot;\n&quot;);

		System.out.println(&quot;객체의 값 -&amp;gt;&quot; + readObj(conn, rec_key));

		if (conn != null)
			conn.close();
	}// main

}
//SQL&amp;gt; select * from object_table;
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
// 1
//jdbc_prg.ObjectSerTest
//ACED0005737200166A6462635F7072672E4F626A65637453657254657374375076BCD97D00750200
//007870
//
//22
//javabasic.ObjectSerTest
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
//ACED0005737200176A61766162617369632E4F626A6563745365725465737471DC7119B914F01E02
//00007870
//
//24
//javabasic.ObjectSerTest
//ACED0005737200176A61766162617369632E4F626A65637453657254657374000000000000000102
//00007870
//
//NO
//----------
//OBJ_NAME
//--------------------------------------------------------------------------------
//OBJ_VALUE
//--------------------------------------------------------------------------------
//SQL&amp;gt; #16진수binary형태로 blob타입으로 저장이 된것&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1677400733277&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JDBC 드라이버 로딩 -&amp;gt;oracle.jdbc.driver.OracleDriver
데이타 베이스 접속 -&amp;gt; jdbc:oracle:thin:@localhost:1521:orcl
접속 계정 : scott
직렬화 완료!!!javabasic.ObjectSerTest
직렬화된 객체의 번호 -&amp;gt;24

역직렬화 완료!! javabasic.ObjectSerTest
객체의 값 -&amp;gt;javabasic.ObjectSerTest@49993335&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.sql.CallableStatement&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CallableStatement 는 인터페이스 (규격) 로써 SQL에서 저장된 절차들을 실행하는데에 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC API 는 한개의 저장된 절차에 SQL escape(벗어나는 수단, 탈출) 구문을 제공하는데 그러한 탈출 구문은 모든 RDBMS들에서 저장된 절차들이 표준적인 방법으로 호출되어지는 것을 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요 탈출 구문은 한개의 결과 파라메터를 포함하는 형식과 포함하지 않는 형식을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 사용된다면, 고 결과 파라메터는 반드시 OUT 파라메터(인수)로 등록되어져야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 파라메터들(인수들)은 입력, 출력, 또는 입출력 둘다로 사용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IN 파라메터 값들은 PreparedStatement 로부터 이어받은 set 메서드를 이용하면서 설정된다. 모든 OUT 파라메터들의 유형(모양)은 반드시 저장된 절차를 실행하기 전에 등록되어져야만 한다; OUT 파라메터들(인수들)의 값들은 여기서 제공된 get 메서드들을 통해 실행 후에 정보가 끌어내어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/566</guid>
      <comments>https://sapwha.tistory.com/566#entry566comment</comments>
      <pubDate>Sun, 26 Feb 2023 17:41:58 +0900</pubDate>
    </item>
    <item>
      <title>Java executeBatch()</title>
      <link>https://sapwha.tistory.com/565</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내 src 내 javabasic 패키지 내 NonBatch.java&lt;/p&gt;
&lt;pre id=&quot;code_1677390501505&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package javabasic;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class NonBatch {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Connection conn = null;
		PreparedStatement pst = null;

		try {
			Class.forName(&quot;oracle.jdbc.driver.OracleDriver&quot;);
			conn = DriverManager.getConnection(&quot;jdbc:oracle:thin:@localhost:1521:orcl&quot;, &quot;scott&quot;, &quot;a1234&quot;);

			String query = &quot;insert into nonbatch values(?,?,?,?,?)&quot;;
			pst = conn.prepareStatement(query);

			long startTime = System.currentTimeMillis();
			for (int i = 0; i &amp;lt; 10000; i++) {
				pst.setString(1, &quot;col1&quot;);
				pst.setString(2, &quot;col2&quot;);
				pst.setString(3, &quot;col3&quot;);
				pst.setString(4, &quot;col4&quot;);
				pst.setString(5, &quot;col5&quot;);
//				pst.addBatch();
				pst.executeUpdate();
			}
//			pst.executeBatch();
			long endTime = System.currentTimeMillis();

			System.out.println(&quot;데이터 입력 소요시간: &quot; + (endTime - startTime) + &quot;ms&quot;);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (pst != null)
				try {
					pst.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과&lt;/p&gt;
&lt;pre id=&quot;code_1677390514905&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;데이터 입력 소요시간: 4052ms&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int java.sql.PreparedStatement.executeUpdate() throws SQLException&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;executeUpdate() 메서드는 INSERT, UPDATE 또는 DELETE 같이 SQL 데이타 조작 언어이어야만 하는 SQL 문을 요 PreparedStatement 객체에서 실행한다; 또는 DDL 데이타 정의어 문구 같이 아무것도 반환하지 않는 SQL 문을 요 PreparedStatement 객체에서 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;int[] java.sql.Statement.executeBatch() throws SQLException&lt;/div&gt;
&lt;div&gt;executeBatch() 메서드는&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행을 위해서 데이타베이스에 명령어들을 일괄로(일회분으로) 처리하여 보내는데 만약에 모든 명령어들이 성공적으로 실행된다면, 새롭게 한(업데이트 한) 횟수들의 배열을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Java</category>
      <author>볼뭉치</author>
      <guid isPermaLink="true">https://sapwha.tistory.com/565</guid>
      <comments>https://sapwha.tistory.com/565#entry565comment</comments>
      <pubDate>Sun, 26 Feb 2023 15:37:27 +0900</pubDate>
    </item>
  </channel>
</rss>