본문 바로가기

자바 수업 정리

수업정리 17일차.

Thread ( 쓰레드 )

 - 프로그램이 실행되면 OS로부터 메모리를 할당받아 process의 상태 됨.
 - 하나의 process는 하나 이상의 Thread를 가지게 됨.
 - Thread는 실제 작업을 수행하는 단위이다.
 - thread가 실제 CPU가 작업을 처리하는 단위
 - multi-thread : 여러개의 thread가 동시에 수행되는 프로그램 
 - CPU는 시간을 잘게 쪼개서 thread를 번갈아 수행함. ( 시분할 처리. )
 - 사용자들은 동시에 처리되는 듯한 효과를 가지게 됨.
 - thread는 각자 자신만의 작업공간을 가짐 (context)
 - 각 thread는 공유하는 자원이 있을 수 있음. (자바에서 static instance)
 - 여러 thread가 공유하는 자원을 사용하려고 경쟁이 발생함.
 - 경쟁이 발생하는 구역 critical section (임계영역) 
 - 임계영역에서 교착상태(deadlock)가 발생하지 않도록 동기화(순차적 수행) 구현하여 오류를 막음.

 

Thread를 구현하는 2가지 방법  
1. Thread 클래스를 상속하여 만들기
2. Runnable 인터페이스를 구현하여 만들기

자바는 다중상속을 허용하지 않기 때문에, 다른 클래스를 상속 중이라면 2번으로 구현

join() : 동시에 여러개의 스레드가 실행될 때 다른 스레드의 결과를 참조하여 실행되어야 할 경우 join() 메서드를 사용 
try~ catch 필요

Thread.sleep() : 기다렸다가 실행 (millisecond 단위 1초 = 1000)

 

critical section(임계영역)은 두 개 이상의 thread가 동시에 접근할 수 있는 영역 ( 공유 영역 )
- 동시에 여러개의 thread가 접근하여 공유영역을 가지려고 하면 문제가 생길 수 있음.
- 교착상태(deadlock)가 발생 
- 한 순간에는 하나의 thread만 사용가능 : 세마포어(semaphore)
- 세마포어를 얻은 스레드만 접근이 가능 / 나머지는 대기상태가 됨.
동기화(순서화) : synchronized 

 * 동기화가 필요한 메서드 앞에 선언


Netword 

인터넷 주소의 정보를 확인

 

		InetAddress ip = null;
		
		ip = InetAddress.getByName("www.naver.com");
		
		System.out.println("HostAddress > "+ip.getHostAddress());
		System.out.println("HostName > " + ip.getHostName());
		System.out.println(ip.toString());
		
		URL url = new URL("https://n.news.naver.com/article/308/0000035560?cds=news_media_pc&type=editn");
		
		System.out.println(url.getContent());
		System.out.println(url.getAuthority());
		System.out.println(url.getDefaultPort());
		System.out.println(url.getProtocol());
		System.out.println(url.getHost());
		System.out.println(url.getQuery());
		System.out.println(url.getPath());

 

예를들어 이렇게 사이트의 주소를 넣어서 정보를 확인할 수 있음.

 

Singleton 싱글턴 

디자인 패턴 중 하나 

디자인 패턴 : 개발자들이 개발 과정에서 하나의 패턴으로 묶어놓은 코드 조합.

싱글턴 : 단 1개만 존재해야 하는 객체를 생성하여 => 공유하고자 할 때 사용

class Singleton{
	// 단 1개만 존재하기 위해 객체의 인스턴스 생성 (공유) 
	private static Singleton instance;
	
	// 생성자를 통해 객체 생성을 막기위해 생성자를 private 설정
	private Singleton() {
		
	}
	
	//getIntance() 메서드를 사용하여 instance를 리턴 
	//instance가 있으면 기존 instance를 리턴
	//instance가 없으면 새로 생성해서 리턴
	
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}

 

 

	Singleton s = Singleton.getInstance();
	Singleton s1 = Singleton.getInstance();

 

2개의 객체를 생성해도 1개의 객체를 공유.


DB와 자바 연결.

JDBC 필요  - mysql용 내가사용하는 버젼 (8.0.39)

라이브러리 다운로드 : mvnRepository  ( mysql Connection 검색함.)

eclipse에서 라이브러리 추가 

 

상품을 관리하는 프로그램을  자바와 DB에 만들어 연결해서 구현해 보도록 하자.

 

1. DB연결 

연결을 하기 위해서는  DB 생성  → 유저 생성 →  테이블 생성 

 

유저 : javaUser
create user 'javaUser'@'localhost' identifiedby 'mysql';
DB : javadb 
create database javadb; 로 생성해 주고

grant all privileges on javadb.*to 'javaUser'@'localhost' with grant option;
flush privileges; 권한을 준 다음에

 

use javadb; 만든 db를 use

 

테이블 : product
pno ai pk
pname varchar(50) nn
price int default 0
regdate datetime default now()
madeby text 로 구성할 예정

 

create table product(
pno int auto_Increment,
pname varchar(50) not null,
price int default 0,
regdate datetime default now(),
madeby text,
primary key(pno));

 

db 구현은 일단 이걸로 끝.


자바에서 구현은

 

Controller(화면으로 보낼 객체 생성, 화면에서 온 객체 생성)

Service / Serviceinterface ( DB로 보낼 객체 생성, DB에서 가져온 객체 생성)

DAO / DAO interface ( DB연결처리 )

ORM (DB연결객체) 으로 구성

 

일단 컨트롤러를 실행해 줄 메인 

 

public class ProductMain {

	public static void main(String[] args) {
		new ProductController();

	}
}

 

처리는 컨트롤러에서 해줄 거기 때문에 객체만 생성해주면됨.

 

public class Product {
	// DB의 테이블과 일치하는 객체 생성
	
	private int pno; // 자동생성
	private String pname;
	private int price;
	private String regdate; // now()
	private String madeby;
	
	// 생성자 / getter/setter / toString
	
	public Product() {}

	// 상품등록 -> pname, price, madeby
	
	public Product(String pname, int price, String madeby) {
		this.pname = pname;
		this.price = price;
		this.madeby = madeby;
	}
	
	// 상품리스트 -> pno, pname, price
	public Product(int pno, String pname, int price) {
		this.pno = pno;
		this.pname = pname;
		this.price = price;
	}
    
	// 상품상세보기 -> 전부
	public Product(int pno, String pname, int price, String regdate, String madeby) {
		this.pno = pno;
		this.pname = pname;
		this.price = price;
		this.regdate = regdate;
		this.madeby = madeby;
	}

	// 상품수정 -> pname, price, madeby, pno 

	public Product(String pname, int price, String madeby, int pno) {
		this(pname,price,madeby);
		this.pno = pno;
	}

	@Override
	public String toString() {
		return pno + ". 상품명 : " + pname + "(" + price + ") / " + regdate + "["
				+ madeby + "]";
	}

 

( getter / setter ) 는 코드안에서 넣어두면 너무길어져서 있지만 생략 

 

Product 클래스는 만들어둔 DB 테이블과 일치하게 변수를 선언해주어야함.

구현할 메서드에 필요한 형식에 맞게 생성자를 생성해주고, toString 생성.

 

public class ProductController {
	private Scanner scan;
	private Service svc; // 아직없음. interface
	private boolean flag; // 종료변수
	
	public ProductController() {
		scan = new Scanner(System.in);
		svc = new  ProductServiceImpl(); // service interface 구현체
		flag = true;
		printMenu();
	}

	private void printMenu() {
		while(flag) {
			System.out.println("-- 상품관리프로그램 --");
			System.out.println("1. 상품등록 | 2. 상품목록 | 3. 상품검색(상세보기) | 4. 상품수정 | 5. 상품삭제 | 6. 종료");
			System.out.println("menu >> ");
			int menu = scan.nextInt();
			
				
			switch (menu) {
			case 1:
				register();
				break;
			case 2:
				list();
				break;
			case 3:
				search();
				break;
			case 4:
				modify();
				break;
			case 5:
				delete();
				break;
			case 6:
				flag = false;
				System.out.println("종료.");
				break;

			default:
				System.out.println("잘못된 메뉴");
				break;
			}	
		}	
	}

	private void delete() {
		// TODO Auto-generated method stub
		
	}

	private void modify() {
		// TODO Auto-generated method stub
		
	}

	private void search() {
		// TODO Auto-generated method stub
		
	}

	private void list() {
		// 상품 전체 리스트
		// 매개변수는 없고, 리턴 List
		List<Product> list = svc.getList();
		
		//출력
		
		for(Product p : list) {
			p.printProductList();
		}
		
	}

	private void register() {
		// 상품등록
		System.out.println("상품이름:");
		String name = scan.next();
		System.out.println("상품가격:");
		int price = scan.nextInt();
		scan.nextLine(); // 공백처리용
		System.out.println("상품상세내역:");
		String madeby = scan.nextLine(); // 공백포함 
		
		
		Product p = new Product(name, price, madeby);
		// service에게 p 객체 등록 요청 (메서드 작성) 
		// 	1 row(s) affected	0.000 sec
		// isOk = 1 (DB에 성공적으로 들어감) / isOk = 0 (실패)
		
		
		int isOk = svc.insert(p);
		System.out.println("상품등록 > "+ ( (isOk > 0) ? "성공" : "실패" ));
	
	}

}

 

오늘은 상품등록과 상품 전체리스트를 출력해주는 2가지 기능만 구현.

 

컨트롤러에서 각 메서드를 처리 할 것이기 때문에 스캐너를 받아주고, Service에 연결해주기위해 svc를 선언, 종료변수로 flag를 boolean으로 선언해줌.

컨트롤러가 생성됐을때 스캐너를 받을 수 있도록 해주고, svc 에 service interface에 구현체를 생성해줌, 그리고 생성이됐으니 flag를 true로 만들어서 실행할 수 있게 만들어주며, 컨트롤러가 생성이됐을때 메뉴를 출력하고 선택해서 선택한 메뉴의 메서드가 작용할 수 있게해주는 printMenu()를 미리 적어두고 구현.

printMenu()는 종료변수 flag가 true면 계속 돌아가게 반복해주고 미리 계획해둔 메뉴구성에따라 메뉴와 메서드명을 구현해줌.

그리고 각 메서드명에 맞게 메서드를 추가해주고 구현시작.

상품등록 메서드는 자동으로 입력되는 상품번호와 날짜를 제외한 이름, 가격, 상세내용을 받을 수 있게함.

 

그리고 sql에서 정상적으로 insert 되면 1 row(s) affected처럼 들어간 row 수가 표시되니 0보다 크면 제대로 작동성공, 아니면 실패로 출력해주기위해 isOk 변수를 선언하고 svc.insert(p);   서비스에 내가 입력한 p객체가 insert 됐을때 리턴을 줄 수있도록 svc.insert(p); 를 미리 입력 이제 svc.insert를 구현할건데  service interface에 추가해주고

추가해주면 service interface 구현체인 ProductServiceImpl에 오버라이드로 받아 구현 해 줄 예정.

 

출력기능은 DB안에 리스트를 받아오기만 하면 되는 것이니 줄 것은없고 list를 생성해서 svc.getList(); 로 받아와서

반복문으로 출력만 해주면됨. 여기서도 마찬가지로 svc.getList();는 인터페이스에 추가해주고 구현체에서 구현.

 

public interface Service {

	int insert(Product p);

	List<Product> getList();

}

 

그러면 서비스 인터페이스는 이렇게 두 기능을 구현하기위해 추가되어있고

 

public class ProductServiceImpl implements Service {
	
	/* service <-> DAO */
	// 생성자로 DAO 객체와 연결
	
	private DAO dao; // interface  
	
	public ProductServiceImpl() {
		dao = new ProductDAOImpl();
	}
	

	@Override
	public int insert(Product p) {
		// 실제 구현 영역
		System.out.println("상품등록 serviceImpl success!! ");
		// DAO에게 DB 저장을 요청
		// dao 요청시 메서드명은 sql구문과 비슷하게 작성하는 것이 일반적
		return dao.insert(p);
	}


	@Override
	public List<Product> getList() {
		
		System.out.println("list serviceImpl success!! ");
		
		
		return dao.selectList();
	}

}

 

서비스 인터페이스에 구현체인 ProductServiceImpl는 DB연결을 처리하는 DAO와 연결해주기위해 

DAO 인터페이스를 선언해주고  생성이됐을때  DAO인터페이스의 구현체인 ProductDAOImpl이 생성될 수 있도록 생성자구현.

그리고 컨트롤러에서 인터페이스로 추가했던 insert와 getList 메서드를 오버라이드로 받아 구현해주고 연결할 dao.insert(p);  , dao.selectList(); 를 만들어 DAO 인터페이스에 추가 이후, 구현체에서 구현

 

public interface DAO {

	int insert(Product p);

	List<Product> selectList();

}

 

그러면 DAO 인터페이스는 이렇게 두 개 추가되고

 

public class ProductDAOImpl implements DAO {
	// DAO <-> DB
	
	// DB연결객체
	private Connection conn;
	
	// sql구문을 실행시키는 기능을 가진 객체
	private PreparedStatement pst;
	
	// 쿼리문 저장 스트링
	private String query="";
	
}

 

DB연결객체와 연결해주기 위해 연결객체, 쿼리실행 기능을 가진 객체, 쿼리문을 담을 저장 스트링을 선언해줌.

 

그러고 일단 연결객체를 생성해주어야함

public class DatabaseConnection {
	/* DB 접속 객체
	 * DB Driver, url, user, password
	 * com.mysql.cj.jdbc.Driver 
	 * jdbc:mysql://localhost:3306/DB명
	 * */
	private static DatabaseConnection dbc = new DatabaseConnection();
	
	private Connection conn = null;
	
	private String jdbcDriver = "com.mysql.cj.jdbc.Driver";
	private String jdbcUrl = "jdbc:mysql://localhost:3306/javadb";
	
	// 생성자
	private DatabaseConnection() {
		// 드라이버를 로드하기 위한 메서드
		try {
			Class.forName(jdbcDriver);
			// 연결위해서 url, user, password
			conn = DriverManager.getConnection(jdbcUrl, "javaUser", "mysql");
		} catch (ClassNotFoundException e) {
			// 드라이버를 찾을 수 없을 경우.
			System.out.println("드라이버를 찾을 수 없습니다.");
			e.printStackTrace();
		} catch (SQLException e) {
			// conn 연결정보가 잘못되었을 경우
			System.out.println("연결정보가 정확하지 않습니다.");
			e.printStackTrace();
		}
	}
	
	
	public static DatabaseConnection getInstance() {
		return dbc;
	}
	
	
	public Connection getConnection() {
		return conn;
	}

}

 

DB 객체가 여러개이면 안되니 싱글턴으로 1개의 객체로 쓸 수 있게 만들어줌.

DB접속을 위해 드라이버 , url     (2개는 mysql 전용으로 검색하면나옴 다른 종류면 다름.) 을 선언해서 받아주고

생성했을때 연결 객체인 conn에 forName으로 드라이버를 연결해주고 DriverManager.getConnection으로 연결정보를 받아줌

 

public ProductDAOImpl() {
		// DBConnection class 생성 (싱글톤) 연결
		
		DatabaseConnection dbc = DatabaseConnection.getInstance();
		conn = dbc.getConnection();
		
		
	}
	
	//sql 처리
	
	@Override
	public int insert(Product p) {
		// product 객체를 등록하고, isOk를 리턴
		System.out.println("insert DAOImpl success!!");
		
		query = "insert into product(pname,price,madeby) values(?,?,?)";
		
		try {
			pst = conn.prepareStatement(query);
			// ? 반드시 순서대로 처리 1부터시작
			pst.setString(1, p.getPname());
			pst.setInt(2, p.getPrice());
			pst.setString(3, p.getMadeby());
			
			// insert, update, delete =>  처리만.. (1 row(s) affected)
			// 결과의 행 수만 리턴 => executeUpdate(); // int 리턴
			// select => 목록 => executeQuery(); // ResultSet 리턴
			
			return pst.executeUpdate();
			
		} catch (SQLException e) {
			// insert error
			System.out.println("insert error");
			e.printStackTrace();
		}
		
		
		return 0;
	}

	@Override
	public List<Product> selectList() {
		// DB에서 리스트를 가져와서 리턴
		System.out.println("list DAOImpl success!!");
		
		query = "select * from product order by pno desc";
		
		List<Product> list = new ArrayList<>();
		
		try {
			pst = conn.prepareStatement(query);
			
			ResultSet rs = pst.executeQuery();
			
			// ResultSet => List로 변환 
			while(rs.next()) {
				list.add(new Product(rs.getInt("pno"), rs.getString("pname"), rs.getInt("price")));
			}
			
			return list;
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			System.out.println("list error");
			e.printStackTrace();
		}
		
		
		
		return null;
	}

  

그리고 만들어둔 다오 구현체에 각 메서드를  구현해주기위해 쿼리문 작성, 쿼리실행객체 = DB연결객체.prepareStatement(query)로 쿼리문을 실행할 수 있게해주고 
pst.set으로 각 ? 벨류에다 매개변수로 받는 Product p의 각 해당 값을 가져와 설정해줘야함.

 

여기서 상품 전체목록 출력 메서드는 row 수를 int로 리턴하는게 아니라 select는 목록을 ResultSet 으로 리턴하므로 ResultSet은 리스트로 변환해서 실행문에 받아오고 list.add 해서 리스트를 return 하도록 구현.

 

결과의 행 수만 리턴 => executeUpdate(); // int 리턴   => isOk에 받아서 성공여부확인
select => 목록 => executeQuery(); // ResultSet 리턴

 

나머지는 이어서 다음에.

'자바 수업 정리' 카테고리의 다른 글

State(장소) 관련 코드  (0) 2024.10.20
수업정리 18일차.  (1) 2024.10.16
수업정리 16일차.  (3) 2024.10.14
수업정리 15일차.  (1) 2024.10.11
수업정리 14일차.  (0) 2024.10.10