우리는 공통 메소드를 사용하여 데이터베이스 연결을 한 번 가져오고 사용할 관련 클래스를 통해 전달하는 시스템을 가지고 있습니다. 데이터베이스 연결을 매개 변수로 다른 클래스에 전달하면 문제가 발생할 것이라는 의심이 있습니다. 실제로 이것이 가능한지 여부를 확인하고 더 나은 패턴이 있습니까?
지속성을 수행하는 ORM 도구가 있다는 것을 알고 있지만 아직 그럴 수는 없습니다.
모든 의견을 환영합니다.
우리는 공통 메소드를 사용하여 데이터베이스 연결을 한 번 가져오고 사용할 관련 클래스를 통해 전달하는 시스템을 가지고 있습니다. 데이터베이스 연결을 매개 변수로 다른 클래스에 전달하면 문제가 발생할 것이라는 의심이 있습니다. 실제로 이것이 가능한지 여부를 확인하고 더 나은 패턴이 있습니까?
지속성을 수행하는 ORM 도구가 있다는 것을 알고 있지만 아직 그럴 수는 없습니다.
모든 의견을 환영합니다.
답변:
예, 연결을 통과하는 것이 안전합니다. 외부 제어 블록에서 연결을 처리합니다. 안전하지 않은 것은 없습니다.
안전하지 않은 것은 연결이 적시에 올바르게 처리되도록 보장하지 않는 코드를 작성하는 것입니다. 리소스 정리를 잊어 버리는 것은 리소스를 전달하는 것과 관련이 없습니다. 어디서나 전달하지 않고 연결을 끊는 코드를 쉽게 작성할 수 있습니다.
C ++에서는 스택에 할당하거나 스마트 포인터를 사용하면 RAII로 보호됩니다. C #에서는 모든 일회용 개체 (예 : 연결)가 "using"블록에 선언된다는 엄격한 규칙을 따릅니다. Java에서는 try-finally 로직으로 정리하십시오. 이를 보장하기 위해 모든 데이터 계층 코드에 대한 코드 검토를 수행하십시오.
가장 일반적인 사용 사례는 여러 순열로 결합 할 수있는 여러 작업이있는 경우입니다. 그리고 이러한 순열 각각은 원자 트랜잭션이어야합니다 (모두 성공 또는 롤백). 그런 다음 모든 메소드에 트랜잭션 (및 해당 연결)을 전달해야합니다.
원자 트랜잭션으로 다양한 방법으로 결합 할 수있는 많은 foobar () 액션이 있다고 가정합니다.
//example in C#
//outer controlling block handles clean up via scoping with "using" blocks.
using (IDbConnection conn = getConn())
{
conn.Open();
using (IDbTransaction tran = conn.BeginTransaction())
{
try
{//inner foobar actions just do their thing. They don't need to clean up.
foobar1(tran);
foobar2(tran);
foobar3(tran);
tran.Commit();
}
catch (Exception ex)
{ tran.Rollback(); }
}
}//connection is returned to the pool automatically
BTW 연결을 가능한 한 늦게 열고 가능한 빨리 폐기하십시오. 연결을 객체 구성원으로 취급하고 연결을 불필요한 상태로 도입하고 연결을 필요 이상으로 길게 열면 팀원이 옳을 수 있습니다. 그러나 연결 또는 트랜잭션을 매개 변수로 전달하는 행위는 본질적으로 잘못되지 않습니다.
BTW. 퍼스트 클래스 함수에 대한 언어의 지원에 따라 foobar () 액션 목록에서 취할 수 있습니다. 따라서 하나의 함수가 동작의 모든 순열을 처리 할 수 있습니다. 각 순열에 대한 외부 제어 블록의 중복 제거.
Dependency Injection 후에있는 것처럼 들립니다 . 즉, 풀링 된 연결이 한 번 생성되어 필요할 때마다 주입됩니다. 메소드 매개 변수를 통해 연결을 전달하는 것은 의존성 주입 방법 중 하나이지만 Guice, PicoContainer 또는 Spring과 같은 IoC 컨테이너는 다른 방법으로 수행 할 수 있습니다.
DI를 사용하면 핵심 비즈니스 로직과는 별도로 연결 생성, 열기, 사용 및 닫기에 대한 로직을 깔끔하게 마무리 할 수 있습니다.
Spring JDBC et al은 이러한 종류의 동작을 수행하는 예제입니다.
데이터가 아닌 데이터베이스를 전달하면 문제가 발생할 수 있습니다. 그 정도까지는 실제 데이터베이스 위생을 보장 할 수 없다면 데이터베이스를 전달하지 마십시오.
데이터베이스를 전달할 때의 문제점은 조잡 할 수 있다는 것입니다. 누군가 데이터베이스 연결을 통과하는 코드에서 둘 이상의 버그를 보았습니다. 누군가가 결과 집합을 가져 와서 로컬 개체 (결과 집합은 여전히 데이터베이스에 연결되어 있음)에 고정시킨 다음 커서를 연결합니다. 상당한 시간 동안 데이터베이스. 다른 인스턴스가 다른 사람에게 결과 세트를 전달한 다음 (결과가 스태킹 된) 결과 세트를 전달한 메소드가 결과를 닫고 (및 명령문) 다른 메소드가 더 이상 그렇지 않은 결과 세트로 작업을 시도하면 오류가 발생합니다.
이 모든 것은 데이터베이스, 연결, 명령문, 결과 세트 및 라이프 사이클을 존중하지 않기 때문입니다.
이를 피하기 위해 데이터베이스와 더 잘 작동하는 기존 패턴과 구조가 있으며, 제한된 클래스에서 데이터베이스를 가져와야 할 필요가 없습니다. 데이터가 들어오고, 데이터가 나가고, 데이터베이스가 그대로 유지됩니다.
Root
Dao에서 얻을 수있는 방법이 있다고 가정 해 봅시다 . 그러나 당신은 당신 이 그것으로 Node
전체 Root
물건을 꺼내지 않고 얻을 수있는 방법을 원한다는 것을 알고 있습니다 . Root
Dao가 Node
Dao 코드 (예 : 재사용)를 호출 하도록하려면 어떻게해야합니까? 그러나 Dao가 직접 호출 Node
될 때 Dao 만 연결을 닫고 Dao가 호출 Node
될 때 연결을 유지해야 Root
합니까?
Connection
대부분의 상황에서 DAO 구현 만 관련이 있지만 인스턴스를 전달 하는 것은 일반적으로 문제가되지 않습니다. 이제 사용 후 연결이 닫히지 않는 문제에 대한 문제로 인해 실제로 수정하기가 쉽습니다. Connection
개체가 열려있는 것과 같은 수준, 즉 동일한 방법으로 개체를 닫아야합니다. 개인적으로 다음 코드 패턴을 사용합니다.
final Connection cnx = dataSource.getConnection();
try {
// Operations using the instance
} finally {
cnx.close();
}
그렇게하면 블록 내에서 예외가 발생하더라도 모든 연결이 항상 닫힙니다. 나는 실제로 동일한 패턴 Statement
과 ResultSet
인스턴스 를 사용하는 한 계속 가고 있으며 , 지금까지 모든 것이 순조롭게 진행되었습니다.
2018-03-29 편집 : 아래 주석에서 user1156544에 표시된 것처럼 Java 7부터 try-with-resources 구문을 사용하는 것이 좋습니다. 이를 사용하여 초기 답변에서 제공 한 코드 패턴을 다음과 같이 단순화 할 수 있습니다.
try (final Connection cnx = dataSource.getConnection()) {
// Operations using the instance
}
dataSource
것이 아니라 그 객체의 이름을 지정해야합니다 DataSource
. 해당 객체의 정확한 유형은입니다 javax.sql.DataSource
. 이전 코드에서는 단일 응용 프로그램 내에서 사용 가능한 모든 데이터 소스를 싱글 톤으로 관리했습니다. DataSource
인스턴스가 의존성 주입을 통해 제공되므로 DAO는이를 통해 알 필요가 없습니다 .
필요에 따라 얻을 수있는 싱글 톤을 사용하는 대신 이러한 방식으로 작업을 수행하는 것이 절충됩니다. 나는 과거에 두 가지 일을 해왔다.
일반적으로 데이터베이스 연결 관리의 결과에 대해 생각해야하며 이는 데이터베이스 쿼리 사용과 직교하거나 아닐 수 있습니다. 예를 들어, 주어진 애플리케이션 인스턴스에 대해 하나의 db 연결이 있고 사용하지 않을 때 닫히면 직교하는 것입니다. 경영진을 싱글턴 클래스에 배치하고 통과시키지 마십시오. 이를 통해 필요에 따라 DB 연결을 관리 할 수 있습니다. 예를 들어, 모든 커밋에서 연결을 닫고 다음 호출에서 다시 열려면이를위한 API를 중앙 집중화 할 수 있기 때문에 싱글 톤에서 수행하는 것이 더 쉽습니다.
반면에, 주어진 통화가 임의의 연결을 사용해야하는 연결 풀을 관리해야한다고 가정하십시오. 예를 들어 여러 서버에서 분산 트랜잭션을 수행 할 때 이런 일이 발생할 수 있습니다. 이 경우 일반적으로 싱글 톤을 사용하는 것보다 db 연결 객체를 전달하는 것이 훨씬 좋습니다. 나는 이것이 가장 드문 경우라고 생각하지만 필요할 때 그것을하는 데 아무런 문제가 없습니다.