문제

직장에서는 여러 MS Access MDB 파일을 처리해야하므로 SUN JVM과 함께 제공되는 기본 JDBCODBCBridge 드라이버를 사용하며 대부분의 경우 훌륭하게 작동합니다.

문제는 더 큰 파일을 처리해야 할 때 "더 이상 테이블을 열 수 없다"는 메시지를 여러 번 예외에 직면한다는 것입니다. 우리는 그것을 어떻게 피할 수 있습니까?

우리는 이미 준비된 상태와 레코드 세트의 모든 인스턴스를 닫고 변수를 NULL로 설정했지만이 예외가 계속 발생합니다. 우리는 무엇을해야합니까? 이러한 불쾌한 예외를 어떻게 피할 수 있습니까? 여기 누군가가 어떻게 알고 있습니까?

이 문제를 피하기 위해 변경할 수있는 Windows의 ODBC 드라이버에 대한 추가 구성이 있습니까?

도움이 되었습니까?

해결책

"더 이상 테이블을 열 수 없음"은 "더 이상 데이터베이스를 열 수 없다"보다 더 나은 오류 메시지입니다. 사실, 후자의 메시지는 거의 항상 전자를 가리는 것입니다.

Jet 4 데이터베이스 엔진의 한계는 2048 테이블입니다. 손잡이. 이것이 연결의 수명 내에서 이것이 동시 또는 누적인지 여부는 완전히 명확하지 않습니다. 한 번에 한 번에 적은 레코드 세트를 열면 문제를 피할 수있는 것으로 보이기 때문에 항상 누적이 누적되었다고 생각합니다.

문제는 "테이블 핸들"은 단지 테이블 핸들을 참조하는 것이 아니라 훨씬 더 많은 것을 의미한다는 것입니다.

이 SQL로 저장된 querydef를 고려하십시오.

  SELECT tblInventory.* From tblInventory;

해당 QueryDef를 실행하면 두 개의 테이블 핸들이 사용됩니다.

뭐?, 물어볼 수 있을까요? 하나의 테이블 만 사용합니다! 그러나 Jet는 테이블의 테이블 핸들과 저장된 QueryDef의 테이블 핸들을 사용합니다.

따라서 다음과 같은 쿼리 디프가있는 경우.

  SELECT qryInventory.InventoryID, qryAuthor.AuthorName
  FROM qryInventory JOIN qryAuthor ON qryInventory.AuthorID = qryAuthor.AuthorID

... 각 소스 쿼리에 두 개의 테이블이 있으면이 테이블 핸들을 사용하고 있습니다.

  Table 1 in qryInventory
  Table 2 in qryInventory
  qryInventory
  Table 1 in qryAuthor
  Table 2 in qryAuthor
  qryAuthor
  the top-level QueryDef

따라서 4 개의 테이블 만 포함되어 있다고 생각할 수도 있지만 (기본 테이블이 4 개 밖에 없기 때문에) 실제로 7 테이블을 사용할 것입니다. 손잡이 이 4 개의 기본 테이블을 사용하기 위해.

레코드 세트에서 7 개의 테이블 핸들을 사용하는 저장된 QueryDef를 사용하면 총 8 개를 위해 또 다른 테이블 핸들을 사용했습니다.

제트 3.5 일로 돌아가서, 원래 테이블 핸들 제한은 1024 였고, 작업 앱을 설계 한 후 데이터 파일을 복제 할 때 마감일에 부딪쳤다. 문제는 일부 복제 테이블 중 일부가 항상 열려 있고 (아마도 각 레코드 세트에 대해?) 앱을 맨 위에 올려 놓을 수있는 더 많은 테이블 핸들 만 사용했다는 것입니다.

그 앱의 원래 디자인에서, 나는 많은 하위 형태와 콤보 상자와 목록 상자가있는 많은 헤비급 형태를 열었고, 그 당시에는 많은 장소에서 사용하는 프레임 어셈블 표준 레코드를 위해 많은 저장된 querydef를 사용했습니다. 모든 서버 데이터베이스에서보기와 마찬가지로). 문제가 해결 된 것은 다음과 같습니다.

  1. 서브 형태는 표시된 경우에만로드합니다.

  2. 화면에있을 때만 콤보 상자와 목록 상자의 로우 소스를로드합니다.

  3. 저장된 모든 querydef를 제거하고 가능한 한 원시 테이블에 결합 한 SQL 문을 사용합니다.

이를 통해 런던 사무실에 해당 앱을 배포 할 수있었습니다. Jet SP2가 나왔을 때, 그것은 우리가 여전히 Jet 4에서 가지고있는 테이블 핸들의 수를 두 배로 늘 렸습니다 (그리고 나는 ACE를 추정합니다).

ODBC를 통해 Java의 제트를 사용하는 측면에서 핵심 요점은 다음과 같습니다.

  1. 필요에 따라 열고 닫지 않고 앱 전체에서 단일 연결을 사용하십시오 (닫지 못할 위험이 없습니다).

  2. 필요할 때만 레코드 세트를 열고 완료되면 자원을 정리하고 해제하십시오.

이제 JDBC => ODBC => 제트 체인의 어딘가에 메모리 누출이있을 수 있습니다. 생각한다 당신은 자원을 공개하고 있으며 전혀 풀리지 않습니다. JDBC와 관련된 조언이 없습니다 (사용하지 않으므로 - 결국 액세스 프로그래머입니다). 그러나 VBA에서는 객체를 명시 적으로 닫고 메모리 구조를 공개하는 데주의를 기울여야합니다. VBA는 기준 계수를 사용하며 때로는 객체에 대한 참조가 릴리스되었음을 알지 못하므로 범위를 벗어날 때 해당 객체의 메모리를 해제하지 않습니다.

따라서 VBA 코드에서는 언제든지 다음과 같습니다.

  Dim db As DAO.Database
  Dim rs As DAO.Recordset

  Set db = DBEngine(0).OpenDatabase("[database path/name]")
  Set rs = db.OpenRecordset("[SQL String]")

...해야 할 일을 한 후에는 다음을 끝내야합니다.

  rs.Close         ' closes the recordset
  Set rs = Nothing ' clears the pointer to the memory formerly used by it
  db.Close
  Set db = Nothing

... 그리고 그것은 당신의 선언 된 변수가 해당 코드 직후에 범위를 벗어나지 않더라도 (이것은 그들에 의해 사용 된 모든 메모리를 해제해야하지만 100% 안정적으로하지 않아야한다).

자, 나는 이것이 당신이 Java에서하는 일이라고 말하는 것은 아니지만, 나는 당신이 문제가 있고 모든 자원을 공개한다고 생각한다면, 아마도 당신이 의존하고 있는지 판단해야한다고 제안합니다. 쓰레기 수거를하고 대신 그렇게해야합니다.

내가 Java 및 JDBC와 관련하여 어리석은 말을한다면 용서하십시오. 저는 접근 개발자가 제트 (ODBC가 아닌 DAO를 통해)와 상호 작용하는 데있어서의 문제를보고하는 것과 동일한 오류 메시지를보고하는 것과 동일한 오류 메시지를보고합니다. 우리의 경험과 실습이 특정 프로그래밍 환경에 대한 솔루션을 제안 할 수 있기를 바랍니다.

다른 팁

최근에 나는 MS Access를위한 순수한 Java JDBC 드라이버 인 Ucanaccess를 시도했습니다. 체크 아웃 : http://sourceforge.net/projects/ucanaccess/ - Linux에서도 작동합니다 ;-) 필요한 라이브러리를로드하려면 시간이 필요합니다. 아직 읽기 전용 목적 이상으로 테스트하지 않았습니다.

어쨌든, 나는 위에서 설명한대로 sun.jdbc.odbc.jdbcodbcdriver와 관련하여 문제를 경험했습니다. system.gc () 문의 명세서 개체를 작성한 후 Close () 명령문을 추가 한 후에는 오류 메시지가 중지 된 오류 메시지가 중지되었습니다 ;-)

무료 네트워크 연결이 부족할 가능성이 있습니다. 우리는 직장에서 바쁜 시스템 에서이 문제를 겪었습니다.

주목할만한 점은 네트워크 연결이 닫히지 만 쓰레기 수집 시간까지 소켓을 해제하지 않을 수 있다는 것입니다. 당신은 이것을 확인할 수 있습니다 NETSTAT /A /N /P TCP. 당신이 많은 연결이 있다면 TIME_WAIT 상태, 연결시, 정기적 인 간격에 대한 쓰레기 수집을 강제 할 수 있습니다.

연결 객체도 닫아야합니다.

JDBC ODBC 드라이버에 대한 대안을 살펴 보는 것도 좋은 생각입니다. 대안에 대한 경험이 없지만 시작하기에 좋은 곳이 될 것입니다.

sun.jdbc.odbc.jdbcodbcdriver를 사용하는 대안이 있습니까?

나는 같은 문제가 있었지만 위의 어느 것도 작동하지 않았습니다. 나는 문제를 최종화했다. 나는 이것을 사용하여 조회 목록 레코드 소스로 되돌려 놓을 양식의 값을 읽었습니다.

LocationCode = [Forms]![Support].[LocationCode].Column(2)
ContactCode = Forms("Support")("TakenFrom")

아래로 변경하면 작동합니다.

LocationCode = Forms("Support")("LocationCode")
ContactCode = Forms("Support")("TakenFrom")

나는 그것을 더 잘 작성해야한다는 것을 알고 있지만 이것이 같은 상황에서 다른 사람이 도움이되기를 바랍니다.

감사합니다 Greg

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top