JDBC(Java Data Base Connectivity)
Java & Data Base 연결에 필요한 프로그래밍
- JAVA 와 DB 연결 프로그래밍
- DB 쿼리 실행 프로그래밍
- DB 쿼리 반환 값 추출 프로그래밍
# but 라이브러리를 활용하면 간단하게 가능
- 아래 파일을 다운받은 후 WEB-INF.lib에 copy
mariadb-java-client-2.7.2.jar
0.60MB
직접 연결 방법
- STS 사용 시 더이상 MVC 패턴을 사용하지 않아, Model 대신 Service로 사용하나 비슷한 역할
- Service : Controller에서 받은 작업 중 DB와 연결해야하는 작업을 DAO로 넘김
- Package : Controller / DAO / Service
DAO & DTO
DAO | DB 연결 및 쿼리문 실행 |
DTO | DAO에서 주고 받는 데이터를 저장하기 위한 데이터 타입(Bean 역할) |
- DBcontroller
package kr.co.web.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.service.DBservice;
@WebServlet("/")
public class DBcontroller extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//model 대신 service 객체화
DBservice service = new DBservice();
//db와 연결하기 위해 dbConnection 메서드 실행
String msg = service.dbConnection();
req.setAttribute("msg", msg);
RequestDispatcher dis = req.getRequestDispatcher("result.jsp");
dis.forward(req, resp);
}
}
- DBservice
package kr.co.web.service;
import kr.co.web.dao.HomeDAO;
public class DBservice {
public String dbConnection() {
System.out.println("DB 접속요청");
HomeDAO dao = new HomeDAO();
return dao.dbConnection();
}
}
- HomeDAO
- 연결순서
- DB 접속 정보를 준비
- 추가한 라이브러리 드라이버를 불러옴
- 드라이버 매니저를 불러 접속 정보 넣어줌
- 드라이버 매니저가 가져온 커넥션을 받음
- Connection을 이용하여 데이터를 처리하고 닫기
- 연결순서
package kr.co.web.dao;
import java.sql.Connection;
import java.sql.DriverManager;
public class HomeDAO {
//DB 접속을 시도해 성공/실패 여부를 반환
public String dbConnection() {
System.out.println("DB 접속시도");
//1. 사용하는 드라이버 라이브러리(mariadb)
String driver = "org.mariadb.jdbc.Driver";
//2. 접속정보 받기
//mariadb 시작할 때 설정했던 host & localhost
String host = "jdbc:mariadb://localhost:3306";
//mariadb에 생성했던 username
String username = "web_user";
//user의 password
String password = "pass";
//아래에서 연결에 실패했을 경우 다음 msg 반환
String msg = "DB접속에 실패하였습니다.";
try {
//3. 드라이버 매니저 부르기(위의 정보를 제공해야함)
Class.forName(driver);
//매개변수로 위의 정보를 넣어주고 DriverManager의 Connection을 가져옴
Connection conn = DriverManager.getConnection(host, username, password);
//DB와 연결되었으면 값을 반환하고, 연결되지 않으면 null을 반환
System.out.println(conn);
if(conn != null) {
msg = "DB접속에 성공했습니다.";
}
//자원을 반납하지 않으면 점점 느려짐
//4. 자원 반납
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
}
Connection Pool을 활용하여 연결
- DB연결이 필요할 때 마다 만들었다 버리는 것은 비효율적이고 자원 낭비임
- Connection Pool을 활용하면 Resource를 재사용 할 수 있음
- Servers/Tomcat/context.xml에 사용할 Resource 저장 후 불러오는 방식
# common-dbcp 라이브러리 추가
commons-dbcp2-2.1.1.jar
0.17MB
# 프로젝트 생성 후 가장 먼저 context.xml에 사용할 Resource 추가
- context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Resource
name="jdbc/MariaDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://localhost:3306/mydb"
username="web_user"
password="pass"
/>
</Context>
- PoolController
package kr.co.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.service.PoolService;
@WebServlet("/")
public class PoolController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PoolService service = new PoolService();
String msg = service.dbConnection();
System.out.println(msg);
}
}
- PoolService
package kr.co.web.service;
import kr.co.web.dao.PoolDAO;
public class PoolService {
public String dbConnection() {
PoolDAO dao = new PoolDAO();
return dao.dbConnection();
}
}
- PoolDAO
package kr.co.web.dao;
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class PoolDAO {
public String dbConnection() {
String msg = "DB 접속에 실패하였습니다.";
//conext.xml에서 데이터 꺼내오는 방법
//1. context.xml을 자바객체화 시킴
//Context는 interface이기 때문에 InitialContext로 객체화
try {
Context ctx = new InitialContext();
//2. Resource 찾아옴(name을 사용)
//3. 찾아온 내용을 DataSource객체로 변환
//java 컴파일 환경에서 이름이 'jdbc/MariaDB'인 리소스 찾아오기
//리소스는 Object 객체이기 때문에 DataSource 타입으로 형변환
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MariaDB");
//4. Connection 받아오기
//ds에서 Connection 받아와 conn에 담기
Connection conn = ds.getConnection();
//conn에 값이 담기면 db와 연결성공/null이면 연결실패
if(conn != null) {
msg = "DB 접속에 성공하였습니다.";
//5. 자원반납
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
}
DB에 쿼리문 넣기
Query문 실행
- Statement 쿼리문으로 실행
- 한번 실행 후 다시 실행되지 않으면(예: 최초 table 생성) Statement가 효율적임
- Prepared Statement 쿼리문으로 실행(VALUES()에 값이 아닌 ?를 넣어 다양한 값 대응)
- Prepared Statement는 문장을 컴파일 한 후 재사용
- 문장이 여러번 반복될 때 유리 / 성능&속도 우수
Query문 반환
- executeQurey()
- 반환되는 데이터가 있을 경우 사용 ex) SELECT
- 결과값을 ResultSet 객체로 반환
- ResultSet 객체에 대한 MetaData를 뽑아 낼 수 있음
close() | ResultSet 객체를 반환 |
getTYPE(int ColumnIndex) | 레코드 값을 지정한 타입으로 가져옴(컬럼 인덱스 지정) |
getTYPE(String ColumnIndex) | 레코드 값을 지정한 타입으로 가져옴(컬럼명 지정) |
next() | 다음행으로 커서 이동(데이터 존재 여부를 boolean 값으로 반환) |
- executeUpdate()
- DB에 변화를 줄 경우 사용 ex) UPDATE, DELETE, INSERT
- 사용 시 반환되는 int는 적용에 성공한 데이터 행(row)의 개수
- HomeController
- 들어오는 요청 관리
package kr.co.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.service.HomeService;
@WebServlet(urlPatterns = {"/","/stmt","/pstmt","/resultSet"})
public class HomeController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String uri = req.getRequestURI();
String ctx = req.getContextPath();
String addr = uri.substring(ctx.length());
HomeService service = new HomeService(req,resp);
switch (addr) {
case "/":
service.home();
break;
case "/stmt":
service.stmt();
break;
case "/pstmt":
service.pstmt();
break;
case "/resultSet":
service.resultSet();
break;
}
}
}
- HomeService
package kr.co.web.service;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.web.dao.HomeDAO;
public class HomeService {
HttpServletRequest req;
HttpServletResponse resp;
RequestDispatcher dis;
//DB 처리가 필요할 경우 사용하기 위해 DAO 객체화
HomeDAO dao = new HomeDAO();
public HomeService(HttpServletRequest req, HttpServletResponse resp) {
this.req = req;
this.resp = resp;
}
public void home() throws ServletException, IOException {
dis = req.getRequestDispatcher("main.jsp");
dis.forward(req, resp);
}
public void stmt() throws ServletException, IOException {
try {
int row = dao.stmt();
} catch (Exception e) {
e.printStackTrace();
}finally {
req.setAttribute("msg", "테이블 생성 완료");
dis = req.getRequestDispatcher("result.jsp");
dis.forward(req, resp);
}
}
public void pstmt() throws ServletException, IOException {
String msg = "데이터 수정에 실패했습니다.";
try {
int row = dao.pstmt();
//row가 1일 경우 1개의 데이터를 update 했다는 것으로 원하는 작업 성공
//0 : 데이터 update 작업이 수행되지 않음
//row>1 : 여러개의 데이터가 수정된 것으로 의도와 다른 데이터들도 수정됨
if(row == 1) {
msg = "데이터가 1개 삽입되었습니다.";
}
}catch(Exception e) {
e.printStackTrace();
}finally {
req.setAttribute("msg", msg);
dis = req.getRequestDispatcher("result.jsp");
dis.forward(req, resp);
}
}
public void resultSet() throws ServletException, IOException {
String msg = "데이터를 가져오는데 실패했습니다.";
try {
if(dao.resultSet()) {
msg = "데이터를 성공적으로 가져왔습니다.";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
req.setAttribute("msg", msg);
dis = req.getRequestDispatcher("result.jsp");
dis.forward(req, resp);
}
}
}
- HomeDAO
package kr.co.web.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class HomeDAO {
Connection conn = null;
public HomeDAO() { //생성자 - 객체화 되자마자 DB에 접속할 수 있도록
try { //1. context.xml 객체화
Context ctx = new InitialContext();
//2. Resource를 name으로 찾고 DataSource로 변환
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MariaDB");
//3. Connection 얻어옴
conn = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
public int stmt() throws Exception {
int row = -1;
//1. 쿼리문 준비(테이블 생성 쿼리문)
String sql = "create table member(" +
"id varchar(50) primary key" +
",pw varchar(100)" +
",name varchar(50)" +
",age int(3)" +
",gender varchar(4)" +
",email varchar(100)" +
")";
//2. Statement(한번 사용할 경우) or PreparedStatement(여러번 사용할 경우 ex)insert,delete..)
//쿼리문 사용 빈도에 따라 선택(spring 사용 시 자동 선택해줌)
//쿼리문 담아주기
Statement stmt = conn.createStatement();
//3. 쿼리문 실행(executeQuery(select문) or executeUpdate(insert,delete..))
//executeQuery : select문으로 가져온 데이터 반환
//executeUpdate : update 된 데이터 수 반환
//4. 결과값 반환(row에 담기)
row = stmt.executeUpdate(sql);
//5. 자원 반납
stmt.close();
conn.close();
return row;
}
public int pstmt() throws SQLException {
// 1.쿼리문 준비
// 여러값이 들어올 경우 ?로 작성
String sql = "INSERT INTO member(id,pw,name,age,gender,email)VALUES(?,?,?,?,?,?)";
//2.Statement or PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(sql);
//2-2. ? 대응
//pstmt에 ? 순서대로 값을 넣어줌
pstmt.setString(1, "admin");
pstmt.setString(2, "pass");
pstmt.setString(3, "홍길동");
pstmt.setInt(4, 22);
pstmt.setString(5, "남자");
pstmt.setString(6, "admin@naver.com");
// 3.쿼리문 실행(executeQuery or executeUpdate)
// 4.결과값 반환
// update 된 데이터 수 반환
int row = pstmt.executeUpdate();
// 5.자원반납
pstmt.close();
conn.close();
return row;
}
public boolean resultSet() {
boolean success = true;
//1.쿼리문 준비
String sql = "SELECT * FROM member"; // * 사용 지양(보안성 떨어지고 가져오는 데이터 확인 어려움)
//2. Statement or PreparedStatement
try {
PreparedStatement ps = conn.prepareStatement(sql);
//3. 쿼리문 실행(excuteQuery or executeUpdate)
// select문으로 가져온 데이터 반환
// data를 Set형태로 담아오기 때문에 ResultSet에 담아줌
ResultSet rs = ps.executeQuery();
//4. 결과값 반환
//next() : 테이블의 각 행들을 선택해 원하는 값이 있으면 가져와서 반환
//Array에서 값을 꺼내오는 것과는 조금 다름
while(rs.next()) {
//rs.get[데이터 타입](컬럼명 or 순서);
System.out.println("id : "+rs.getString("id"));
System.out.println("pw : "+rs.getString(2)); //비추(어떤 데이터가 나올지 모름)
System.out.println("name : "+rs.getString("name"));
System.out.println("age : "+rs.getInt("age"));
System.out.println("gender : "+rs.getString("gender"));
System.out.println("email : "+rs.getString("email"));
}
// 5. 자원반납
rs.close();
} catch (SQLException e) {
success = false;
e.printStackTrace();
}
return success;
}
}
- main
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style>
table, th, td{
border: 1px solid black;
border-collapse: collapse;
padding: 5px 10px;
}
</style>
</head>
<body>
<h3>다음의 속성을 갖는 member 테이블을 생성하는 쿼리를 작성하시오</h3>
<table>
<tr>
<th>FIELD</th>
<th>TYPE</th>
<th>SIZE</th>
</tr>
<tr>
<td><ins>id</ins></td>
<td>VARCHAR</td>
<td>50</td>
</tr>
<tr>
<td>pw</td>
<td>VARCHAR</td>
<td>100</td>
</tr>
<tr>
<td>name</td>
<td>VARCHAR</td>
<td>50</td>
</tr>
<tr>
<td>age</td>
<td>INT</td>
<td>3</td>
</tr>
<tr>
<td>gender</td>
<td>VARCHAR</td>
<td>4</td>
</tr>
<tr>
<td>email</td>
<td>VARCHAR</td>
<td>100</td>
</tr>
</table>
<p><a href="stmt">테이블 생성(Statement)</a></p>
<p><a href="pstmt">테이블 삽입(PreparedStatement)</a></p>
<p><a href="resultSet">테이블 요청(PreparedStatement)</a></p>
</body>
<script></script>
</html>
- result
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style></style>
</head>
<body>
${msg}
<p>
<a href="./">메인으로 돌아가기</a>
</p>
</body>
<script></script>
</html>
'코딩도전기 > DB(mariaDB)' 카테고리의 다른 글
JNDI / DBCP (1) | 2023.12.20 |
---|---|
CODO Day38_DB_JDBC(Board&Join) (0) | 2023.03.28 |
CODO Day36_DB_ERD(논리설계/물리설계) (0) | 2023.03.24 |
CODO Day35_DB(정규화&역정규화) (0) | 2023.03.24 |
CODO Day35_DB(Auto_increment/Limit&offset/Function) (0) | 2023.03.24 |