[JSP] 20. MyBatis-3.5.5, HikariCP 3.4.2 연동 - Maven(Servlet) Spring 제거버전 (Oracle 19g) - Java 방식
JSP/Servlet 순수한 방식에서 HikariCP를 연동할 수 있는 방법에 대해서 고민을 하게 된 이유는 Spring Framework의 의존성을 줄일 수 있겠냐는 생각을 가지고 접근하게 되었다.
JSP/Servlet이 현재에도 의외로 많이 사용되고 있다. Spring-Framework 사용 안 한 형태도 동작하는 프로젝트가 많기 때문에 조금 생각해보면 효과적으로 기존 프로젝트도 개선할 수 있을 거 같아서 작성하게 되었다.
기존 프로젝트에도 MyBatis 프레임워크와 HikariCP를 적용할 수 있으니 가능성을 가지고 순수한 JSP에 대해서도 관심을 가져봤으면 하는 바람이다.
커넥션 풀은 현재의 웹 개발에서는 반드시 필요한 존재라고 본다.
(중요성에 대해서는 별도로 시간이 나면, 조금 더 심화적인 방법으로 연재하도록 하겠다.)
* XML로 설정한 MyBatis에서는 가능한가요?
= 불가능하다. (미지원)
- IDE: Spring-Tool-Suite 4-4.7.2 Releases (2020-06 최신)
- DB: Oracle Databases 19g (2020-09 최신)
- Maven 3.6.3/1.16.0.20200610-1735 (2020-09 최신)
- JAR: javax.servlet-api.4.0.1.jar (2020-09 최신)
ojdbc8-19.7.0.0.jar (2020-09 최신)
MyBatis 3.5.5 (2020-09 최신)
HikariCP 3.4.2 (2020-09 최신)
* 정말로 Spring-Framework는 사용하지 않았나요?
= 그렇다.
관련 글)
1. [JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식, https://yyman.tistory.com/1434, 2020-10-01
-> 이 글의 소스 코드 이어서 계속(해당 게시글에서는 변형됨.)
1. 결과
이전의 게시글에서 동작 반응이 다소 변경되었다. (HikariConnection Pool 반응 상태를 추가하였음.
그림 1. HikariPool - 2 반응 추가
사소해보이지만, 무척 중요하다. 동시 접속했을 때, 서버가 죽느냐 사느냐를 결정할 수도 있다.
커넥션 풀은 데이터베이스 접속을 원할하게 해주는 중요한 것이라고 비유해주고 싶다.
그림 2. 프로젝트 구성 모습
* 이전의 프로젝트와 차이점: exmple 탈자를 정정하였음. (example로)
- 패키지명을 잘 조정해서 사용하면 크게 무리없이 동작할 것이다.
1. 폴더 추가
/src/main/resources 폴더가 생성되었다.
- db.properties가 추가되었다.
2. POM.xml - 설정하기
POM.xml의 변화는 HikariCP 3.4.2가 추가되었다.
바뀐 것은 없다. 그래서 잘 따라해야 하는 것이다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.exmplebatis</groupId>
<artifactId>web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>web Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.7.0.0</version>
</dependency>
</dependencies>
<build>
<finalName>web</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
파일명: pom.xml
[첨부(Attachments)]
3. /resources/db.properties 설정하기
db.properties에 관한 것이다.
그림 3. db.properties 설정 내용
jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl
dataSourceClassName=oracle.jdbc.driver.OracleDriver
dataSource.user=UserName
dataSource.password=Password
cachePrepStmts=true
prepStmtCacheSize=250
prepStmtCacheSqlLimit=2048
파일명: db.properties
[첨부(Attachments)]
4. SqlMapSessionFactory.java - com.example.web.db
DB 세션 영역이다.
일부 인터넷 게시글을 찾아보면, SqlSessionFactoryBeans ssfb = new SqlSessionFactoryBeans(); 객체 생성 후에 setDatasource()로 연결시키면 된다고 소개된 글들이 있다.
이 부분은 공식 메뉴얼을 찾아본 바로는 MyBatis에서 Spring을 지원하기 위해서 만든 부분이다.
JSP/Servlet 기반의 프로젝트에서는 지원하지 않는 부분이다. (Beans 처리를 미지원함.)
충분히 시간을 가지고 태스트가 완료된 코드이다.
그림 4. SqlMapSessionFactory.java - 작업 모습
package com.example.web.db;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import com.example.web.mapper.CompUsersMapper;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import oracle.jdbc.pool.OracleDataSource;
public class SqlMapSessionFactory {
private static SqlMapSessionFactory factory = new SqlMapSessionFactory();
public static SqlMapSessionFactory getInstance() {
return factory;
}
public static SqlSessionFactory ssf;
private static String CLASSNAME;
private static String JDBC_URL;
private static String USERNAME;
private static String PASSWORD;
private static String CACHE_PREP_STMTS;
private HikariDataSource ds;
private HikariConfig config;
private SqlMapSessionFactory() {
/* HikariCP 로드 */
InputStream inputStream;
config = new HikariConfig();
String resource = "db.properties";
Properties properties = new Properties();
try {
inputStream = getClass().getClassLoader().getResourceAsStream(resource);
properties.load(inputStream);
System.out.println("jdbcurl:" + properties.getProperty("jdbcUrl"));
System.out.println("className" + properties.getProperty("dataSourceClassName"));
CLASSNAME = properties.getProperty("dataSourceClassName");
JDBC_URL = properties.getProperty("jdbcUrl");
USERNAME = properties.getProperty("dataSource.user");
PASSWORD = properties.getProperty("dataSource.password");
CACHE_PREP_STMTS = properties.getProperty("cachePrepStmts");
config.setDriverClassName(CLASSNAME);
config.setJdbcUrl( JDBC_URL );
config.setUsername( USERNAME );
config.setPassword( PASSWORD );
config.addDataSourceProperty( "cachePrepStmts" , CACHE_PREP_STMTS );
config.addDataSourceProperty( "prepStmtCacheSize" , "250" );
config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );
ds = new HikariDataSource( config );
System.out.println("성공:" + ds);
} catch (IOException e) {
System.out.println("오류:" + e.getMessage());
e.printStackTrace();
}
}
// iBatis(MyBatis 반환)
public SqlSessionFactory getSqlSessionFactory() {
DataSource hDs = ds;
// DataSource dataSource = getOracleDataSource();
System.out.println(hDs);
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, hDs);
Configuration configuration = new Configuration(environment);
configuration.addMapper(CompUsersMapper.class); // Mapper 클래스
// System.out.println("성공2");
return new SqlSessionFactoryBuilder().build(configuration);
}
public void close(Connection conn, PreparedStatement ps, ResultSet rs) {
if ( rs != null ) {
try {
rs.close();
}
catch(Exception ex) {
System.out.println("오류 발생: " + ex);
}
close(conn, ps); // Recursive 구조 응용(재귀 함수)
} // end of if
}
public void close(Connection conn, PreparedStatement ps) {
if (ps != null ) {
try {
ps.close();
}
catch(Exception ex) {
System.out.println("오류 발생: " + ex);
}
} // end of if
if (conn != null ) {
try {
conn.close();
}
catch(Exception ex) {
System.out.println("오류 발생: " + ex);
}
} // end of if
}
}
파일명: SqlMapSessionFactory.java
[첨부(Attachments)]
SqlMapSessionFactory-update.zip
5. FrontController.java - com.example.web.controller
FrontController에 대한 변화이다.
그림 5. FrontController.java - 작업 모습
package com.example.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.example.web.db.SqlMapSessionFactory;
import com.example.web.mapper.CompUsersMapper;
import com.example.web.model.CompUsers;
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
SqlSessionFactory factory = null;
SqlMapSessionFactory sqlMapFactory = null;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doAction(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
sqlMapFactory = SqlMapSessionFactory.getInstance();
try {
factory = sqlMapFactory.getSqlSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
try (SqlSession session = factory.openSession()) {
CompUsersMapper mapper = session.getMapper(CompUsersMapper.class);
CompUsers user = mapper.findByUsername("user");
System.out.println("계정명:" + user.getUsername());
}
}
}
파일명: FrontController.java
[첨부(Attachments)]
6. CompUsers.java - com.example.web.model (Model)
이전 게시글과는 변화는 없지만, 다시 재언급한다.
package com.example.web.model;
public class CompUsers {
private String username;
private String password;
private int enabled;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
}
파일명: CompUsers.java
[첨부(Attachments)]
CREATE TABLE comp_users (
username VARCHAR(50) NOT NULL,
password VARCHAR(300) NOT NULL,
enabled INT NOT NULL,
PRIMARY KEY (username)
);
-- 계정
INSERT INTO comp_users (username, password, enabled) VALUES ('user', '$2a$10$x04djNV2e9rpcPPRyXoLk.rMm6iZe2/vYdzpqHQcLeNSYdt7kc30O', 1);
INSERT INTO comp_users (username, password, enabled) VALUES ('admin', '$2a$10$QUddY3O/6ZgkYCR6MFlv9.nqA501Fm0cc/ZxQHX5pwb1o0CYCTiIS', 1);
파일명: CompUsers.sql
[첨부(Attachments)]
7. CompUsersMapper.java - com.example.web.mapper (Mapper - DAO)
이전 게시글과 비교했을 때 변화는 없었다.
package com.example.web.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.example.web.model.CompUsers;
@Mapper
public interface CompUsersMapper {
@Select("SELECT * FROM comp_users WHERE username = #{username}")
public CompUsers findByUsername(String username);
}
파일명: CompUsersMapper.sql
[첨부(Attachments)]
* 맺음글(Conclusion)
HikariCP 구성과 MyBatis-3.5.5 셋팅에 대해서 JSP/Servlet 방식으로 다뤄보았다.
'소프트웨어(SW) > JSP' 카테고리의 다른 글
[JSP] 22. JSP/Servlet MVC2 - jQuery기반의 Ajax POST 전송 및 MVC패턴 Action 식별자 (118) | 2020.10.02 |
---|---|
[JSP] 21. Jsp/Servlet(MVC) Maven 기반의 다중 업로드, 다운로드, 삭제 구현(1) (2) | 2020.10.01 |
[JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식 (2) | 2020.10.01 |
[JSP] 18. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (2) (2) | 2020.09.30 |
[JSP] 17. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (1) (2) | 2020.09.30 |