Java는 JDBC 또는 MyBatis 프레임워크를 사용하여 Oracle에 XMLType 데이터 삽입
XMLType은 Oracle이 9i부터 특유의 데이터 유형으로 Blob의 강력한 존재를 계승하여 xml을 저장하고 상당히 많은 조작 함수를 제공할 수 있다.이론적으로 2G 크기의 데이터를 저장할 수 있다.
그러면 어떻게 자바를 통해 XMLType 형식의 데이터를 삽입합니까?프로젝트에서 사용하는 것은 Mybatis입니다. 항상 알 수 없는 이상이 생겨서 도대체 Mybatis의 문제인지 jdbc 자체의 문제인지 알 수 없기 때문에 한 걸음 한 걸음 jdbc를 해결하고 Mybatis를 해결하려고 합니다.
JDBC
한참 동안 고생한 후에 jdbc 조작은 주로 세 가지 방법이 있다는 것을 발견했다.
1. Java에서 XMLType을 문자열 String으로 사용하고 XMLType을 만드는 작업은 데이터베이스에 완전히 전달됩니다.
String sql = "insert into xmltable (XML) values(sys.xmlType.createXML(?))";
String xmldata = "<label>This is an XML fragment</label>";
ps.setString(1, xmldata);
ps.executeUpdate();
이 방법은 데이터베이스의 압력을 크게 할 수 있다. 왜냐하면 이 방법은 간단하고 별도의 의존이 필요하지 않기 때문에 처음에 이 방법을 사용했지만 실제 사용 과정에서 내용의 길이가 4000 정도를 넘을 때 ORA-01461: can bind a LONG value only for insert into a LONG column 이상을 던진다.처음에는 mybatis를 사용하는 이유가 jdbc 테스트를 사용하는 것도 그렇고 여러 가지 방법을 사용해서 풀지 못했습니다.프로젝트에서 이 큰 필드를 사용하면 길이가 4000 이내인 데이터만 저장할 수 없기 때문에varchar2를 사용하면 충분하기 때문에 이 방법은 도태됩니다.둘째, CLOB 유형을 사용합니다.XMLType은 CLOB의 존재를 계승하기 때문에 CLOB를 통해 조작할 수 있습니다.방법은 클라이언트가 CLOB 데이터를 만든 후 데이터베이스에 전송하여 Oracle의 XMLTYPE() 함수를 통해 XMLType 값을 구성합니다.
String sql = "insert into xmltable (XML) values(XMLType(?))";
String xmldata = "<label>This is an XML fragment</label>";
// conn CLOB
CLOB tempClob = CLOB.createTemporary(connection, false, CLOB.DURATION_SESSION);
// CLOB
tempClob.open(CLOB.MODE_READWRITE);
// writer
Writer clobWriter = tempClob.setCharacterStream(100);
//
clobWriter.write(xmldata);
//
clobWriter.flush();
// writer
clobWriter.close();
// CLOB
tempClob.close();
pst.setObject(1, tempClob);
이 방법은 클라이언트와 데이터베이스가 XMLType을 만드는 임무를 동시에 맡고 있기 때문에 압력이 평균적이며 길이를 초과하는 문제도 없다.그러나 실제 사용 과정에서 xml의 내용 헤더에는 다음과 같은 정보가 포함될 수 없다는 것을 발견했다.
<?xml version="1.0" encoding="UTF-8"?>
그렇지 않으면 이상이 발생합니다.
PI names starting with XML are reserved
이것은 나중에 xml 내용이 중국어를 포함할 때 계란이 아픈 디코딩 문제를 겪지 않을까요? 보기만 해도 기분 나쁘고 저장을 요구합니다. 어쩔 수 없습니다. 이 방법은 또 통하지 않습니다.3. Oracle에서 제공하는 oracle을 사용합니다.xdb.XMLType 클래스, 클라이언트가 XMLType을 만든 후 데이터베이스에 직접 객체 전송:
Connection conn = ... ;// Connection
PreparedStatement ps = ...;// PreparedSatement
String sql = "insert into xmltable (XML) values(?)";
String xmldata = "<label>This is an XML fragment</label>";
// XMLType
XMLType xmltype = XMLType.createXML(conn, xmldata);
ps.setObject(1, xmltype);
ps.executeUpdate();
이 방법은 XMLType을 만드는 작업을 클라이언트에게 완전히 맡기기 때문에 클라이언트의 압력이 크고 데이터베이스의 압력이 적다.실측 과정에서 jar 패키지 두 개를 추가해야 합니다. 그렇지 않으면 클래스를 찾을 수 없는 오류가 발생합니다.
xdb.jar
xmlparserv2.jar
이jar가방은 버전 표시가 없어서 틀리기 쉬우니 주의해야 합니다. 처음에 xdb를 다운로드했습니다.jar, 어떻게 해도 알림이 맞지 않아서 어떤 종류를 찾을 수 없습니다. 보고 보니oracle의 초기 버전에 속하고 xdb를 다시 다운로드했습니다.jar 후 정상입니다.위의 세 가지 방법은 20만 개의 데이터 테스트를 삽입하여 비교한 것이다.
첫 번째 방법: 소모 시간이 가장 짧고 서버 cpu 소모가 가장 크다.
두 번째 방법: 소모 시간이 가장 길고 서버 cpu 소모가 중간이다.
세 번째 방법: 시간 소모가 중간이고 서버 cpu 소모가 가장 적다.
이로써 jdbc가 XMLType 유형 데이터를 조작하는 것은 마침내 작은 해결이라고 할 수 있다. 세 번째 방안을 채택한 것은 말할 것도 없지만 프로젝트에서 기본적으로 jdbc로 조작하지 않는다. 현재 프로젝트에서 Mybatis를 사용했다. 위에서 언급한 바와 같이 Mybatis를 사용하면 항상 이상이 발생한다. Mybatis를 봐도 XMLType에 대한 실현이 없다. 보아하니 아직도 고생이 있는 것 같다. 그러나 jdbc는 이미 해결되었고 사고방식은 명확하지 않니?
Mybatis
ybatis를 사용하여 XMLType을 조작하면 우리는 Java단에서 String 유형으로 비추고 직접 조작하여 아무런 처리도 하지 않을 때 jdbc와 대체적으로 같이 전송된 내용의 길이가 4000보다 작을 때 모든 것이 정상적이고 전송된 내용의 길이가 4000 정도를 초과할 때 똑같이 이상을 던진다.
ORA-01461: can bind a LONG value only for insert into a LONG column
이를 통해 알 수 있듯이 Mybatis의 조작은 사실 jdbc와 같다. 단지 jdbc의 바깥쪽에 한 층을 봉인하여 우리는 프로필 등 매핑 방식으로 데이터베이스에 더욱 편리하게 접근할 수 있다. 우리가 해야 할 일은 기존의 Mybatis의 편리성을 바탕으로 XMLType 형식의 데이터에 대한 삽입을 실현하는 것이다. 이런 상황에서 XMLType 형식의 사용자 정의 TypeHandler 프로세서를 실현하는 것이 가장 좋은 선택이다.여기, 우리는 여전히 앞에서 언급한 방안을 채택한다.jar,xmlparserv2.jar도 가입해야 돼요.
XmltypeTypeHandler를 추가하여 TypeHandler 인터페이스를 구현합니다. 데이터 삽입은 주로 setParameter 방법에 사용되기 때문에 이 방법만 열거하고 다른 방법 코드는 약간입니다.
/**
* oracle SYS.XMLTYPE
*/
public class XmltypeTypeHandler implements TypeHandler<String> {
@Override
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
}
...
}
이 setParameter 방법은 바로 Mybatis가 데이터를 데이터베이스에 삽입할 때 파라미터를 설정하는 것입니다. 이 방법의 파라미터는 당신이 코드를 보는 것도 이미 알고 있다고 믿습니다. 우리는 앞의 jdbc의 실현 방식에 따라 여기에 다음과 같은 코드를 삽입합니다.
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
XMLType xmltype = XMLType.createXML(ps.getConnection(), parameter);
ps.setObject(i,xmltype);
}
그리고 매퍼-config.xml에 변환기를 등록합니다. 왜냐하면 Mybatis가 정의한 매거 org입니다.apache.ibatis.type.JdbcType에는 필요한 XMLType 유형이 없습니다. 여기서 UNDEFINED로 정의합니다.
<configuration>
<typeHandlers>
<typeHandler javaType="string" jdbcType="UNDEFINED" handler="com.tyyd.dw.context.XmltypeTypeHandler"/>
</typeHandlers>
</configuration>
프로필 매개 변수에서 정의된 변환기를 사용하면 Mybatis를 찾을 수 있습니다.
#{xmlFile,jdbcType=UNDEFINED},
물론 너도 좀 더 규범화하고 그 유형과 사용하는 변환기를 완전하게 쓸 수 있다.#{xmlFile,javaType=string,jdbcType=UNDEFINED,typeHandler=com.tyyd.dw.context.XmltypeTypeHandler},
위의 절차를 완성하고 이치대로 말하면 모든 것이 대성공했으니 우리 운행합시다.
결과는 이상을 던졌다.
java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Oracle의 연결 대상인 Oracle Connection으로 바꿀 수 없습니다. 확인해 보니 저희 데이터 원본은 아파치의dbcp를 사용하고 있습니다. 호환되지 않는 것 같습니다.인터넷에서 찾아보니 어떤 인형이 완벽한 해결 문안을 주었다고 했어요. 바로 set Parameter 방법에서 Oracle 드라이브 클래스를 단독으로 불러와서 연결을 만드는 거예요. 다음과 같습니다.
Class.forName("oracle.jdbc.OracleDriver");
Connection connection = DriverManager.getConnection(url, username, password);
이것은 확실히 연결 대상이 전환할 수 없는 문제를 100% 해결할 수 있지만, 실현 방식에 있어서는 허허, 논평을 하지 않겠다.그리고 인터넷에서 들려오는 것은 Poolable Connection 대상으로 전환할 수 있다고 합니다. 그리고 get Delegate 방법을 사용하면 원시 프록시 링크를 얻을 수 있습니다. 이것은 가능할 것 같습니다. 한번 해 보겠습니다.
PoolableConnection connection = (PoolableConnection )ps.getConnection();
XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
ps.setObject(i,xmltype);
결과는 또 이상을 던졌다.org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection
, 변환할 수 없습니다.어쩔 수 없어요. 인터넷에 떠도는 글은 그다지 믿을 수 없는 것 같아요. 지름길이 없으니 원본 코드를 직접 보세요.
소스 코드를 보면 PoolableConnection이 DelegatingConnection 클래스를 계승하고 DelegatingConnection 클래스가 Connection 인터페이스를 실현하는 것을 발견했습니다. 이를 DelegatingConnection으로 변환해 보겠습니다.
DelegatingConnection connection = (DelegatingConnection )ps.getConnection();
XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
ps.setObject(i,xmltype);
결과는 또 이상을 던졌다. 설명자를 구성할 수 없음: Invalid arguments;nested exception is java.sql.SQLException: 설명자를 구성할 수 없습니다: Invalid arguments, 단점 디버깅을 통해connection 대상이 null인 것을 발견했습니다. 어떻게 null일 수 있습니까? 인터넷에서 사람들이 잘 사용하고 있습니다. 저에게 오면 안 돼요. 정말 알이 아파요. 이게 이해가 안 되는 건 아니겠죠? 위의 인형이 말한 것처럼 드라이버를 혼자 불러와야 하나요?어쩔 수 없어, 다시 연구해 보자.마지막으로 getMetaData 방법을 통해 원시 에이전트 연결을 얻을 수 있다는 것을 발견했습니다. 버드나무 암화명입니다. 빨리 테스트를 적으세요. 드디어 정상입니다. 쉽지 않습니다. 최종 코드는 다음과 같습니다.
@Override
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
DelegatingConnection connection = (DelegatingConnection) ps.getConnection().getMetaData()
.getConnection();
XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
ps.setObject(i, xmltype);
}
이로써 Mybatis를 사용하여 XMLType 유형을 조작하는 것은 드디어 끝났습니다. 과정은 우여곡절이 많습니다.데이터가 삽입되면 당연히 조회가 있어야 한다. 다음은 XMLType 유형의 조회 조작을 실현해야 한다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.