[Database] Oracle cloud ATP DB - JDBC - Java 연결
zl존석동
·2022. 1. 14. 18:05
로컬 데이터베이스와 연결방법이 조금 달랐던 오라클 클라우드 데이터베이스..
를 순수 자바 프로젝트에 수동으로 연결하다 삽질하고 해결한 과정을 기록해보자
환경
윈도우 10
자바 8
오라클 클라우드 자율운영 데이터베이스 19c
연동을 위해 필요한 것?
알맞는 데이터베이스의 JDBC 구현물(라이브러리)
자바에서 JDBC를 활용해 원하는 데이터베이스를 연동하고자 할 때
해당 데이터베이스의 JDBC 구현물(라이브러리)이 필요하다.
이 외부 라이브러리를 자바 프로젝트에 등록해줘야 JDBC를 사용할 수 있다.
지금은 오라클이니 ojdbc 가 필요하다!
https://www.oracle.com/database/technologies/appdev/jdbc-ucp-19c-downloads.html


연결할 DB 정보
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:xe";
String userid = "SCOTT";
String passwd = "TIGER";
드라이버, 데이터베이스 url, 사용자, 비밀번호 라는 정보가 필요하다.
명시된 드라이버를 로드한 다음 데이터베이스 접속위치와 사용자 정보를 이용해 커넥션을 맺게 된다.
위의 url과 사용자는 내 컴퓨터에 있는 오라클 데이터베이스의 정보이다.
이대로 적절하게 커넥션 연결, 쿼리 사용 코드만 잘 작성하면 자바에서 데이터베이스를 사용할 수 있게 된다!
연결 삽질하기
당연히 저 위의 두 정보만으로 클라우드 데이터베이스에도 접근할 수 있을 줄 알았다.
이전에 스프링부트에서 오라클 클라우드 데이터베이스를 사용할 때도
gradle 에 ojdbc 의존성을 추가하고 프로퍼티에 db연결 정보만 잘 작성했는데도 연결이 잘 되었기 때문이다.
전자지갑?
기본적으로 오라클 클라우드 데이터베이스는 전자지갑(Wallet) 을 활용해
데이터베이스 접근 권한을 인증받아 연동하여 사용할 수 있게 된다.
컴퓨터 적절한 곳에 위치시켜준 다음 자바에서 해당 지갑의 정보를 이용하여 연결하게 될 것이다.


지갑을 까보면 다음과 같이 구성되어있는데 tnsnames.ora 에 있는 tns 이름을 활용해 자바에서 연결할 것이다.
각 이름들은 위치,연결, 세션, 서버타입 등 여러 설정들을 가지고 있다.
자바에서 연결정보로 활용한다면 다음과 같이 할 수 있다.
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@[TNSNAMES.ORA에 있던 TNS 이름]?TNS_ADMIN=[지갑경로]";
String userid = "SCOTT";
String passwd = "qlalfdldi";
연결이 잘 되나 다음과 같은 코드로 간단히 테스트를 해보면
public class Main {
public static void main(String[] args) {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "secret";
String userid = "SCOTT";
String passwd = "secret";
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url, userid, passwd);
String sql = "select * from tb_student";
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
안된다.. 커넥션 자체가 성립이 안된다고 한다..

예외를 좀 더 살펴보면 솔직히 뭐가뭔지 잘 몰랐지만 대충 보면 키 저장소를 뭐 초기화하지 못한다느니 하는걸 보고
연결 정보를 온전하게 받아들이지 못했다고 추측해볼 수 있었다.
Caused by: oracle.net.ns.NetException: Unable to initialize the key store.
at oracle.net.nt.CustomSSLSocketFactory.getKeyManagerArray(CustomSSLSocketFactory.java:619)
at oracle.net.nt.CustomSSLSocketFactory.createSSLContext(CustomSSLSocketFactory.java:324)
... 17 more
Caused by: java.security.KeyStoreException: SSO not found
at java.security.KeyStore.getInstance(KeyStore.java:851)
at oracle.net.nt.CustomSSLSocketFactory.getKeyStoreInstance(CustomSSLSocketFactory.java:767)
at oracle.net.nt.CustomSSLSocketFactory.loadKeyStore(CustomSSLSocketFactory.java:901)
at oracle.net.nt.CustomSSLSocketFactory.getKeyManagerArray(CustomSSLSocketFactory.java:610)
... 18 more
Caused by: java.security.NoSuchAlgorithmException: SSO KeyStore not available
at sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
at java.security.Security.getImpl(Security.java:695)
at java.security.KeyStore.getInstance(KeyStore.java:848)
... 21 more
일부러 url 경로를 살짝 틀리게 해보았다.
잘못된 연결 식별자라는 다른 예외를 보여주는 것을 통해
DB연결을 위해 어떤 무언가가 더 필요하다는 것을 확신하게 되었다.

2분만에 해결하기
스프링부트에 분명히 똑같은 의존성을 넣고도 잘 동작했던 기억이 있는데..
여기선 안되고 저기선 된다??
그래서 해당 프로젝트의 오라클 관련 의존성을 모두 뒤져보았다.

ojdbc 의존성을 추가했는데 oraclepki, osdt_cert, osdt_core 라는 친구들이 같이 있는 것을 확인할 수 있었다.
오라클 홈페이지를 뒤져보니
자율운영 데이터베이스에서 빌드도구 없이 JDBC를 사용하는 방법까지도 친절하게 나와 있었다.. ㅠㅠㅠㅠ

https://www.oracle.com/database/technologies/getting-started-using-jdbc.html#Nobuildtools-tab

ojdbc 라이브러리 뿐만아니라 위에서 보았던 oraclepki, osdt_cert, osdt_core 라이브러리들도 필수 였던 것이다.
자바에서 전자지갑에 접근할 수 있도록 도와주는 친구들이라고 한다.
모두 다운받고 프로젝트에 라이브러리 추가를 해주면 해결된다!

오라클 클라우드 데이터베이스 콘솔에서도 다음과 같은 쿼리로 한번 더 확인해보자!
SELECT SQL_ID , MODULE, SQL_FULLTEXT, PARSING_SCHEMA_NAME
FROM V$SQL
WHERE PARSING_SCHEMA_NAME IN ('SCOTT')
ORDER BY LAST_LOAD_TIME DESC;

교훈: 공식문서를 잘 보자!