복붙노트

[SPRING] Spring의 JdbcTemplate과 동일한 연결을 재사용하는 방법?

SPRING

Spring의 JdbcTemplate과 동일한 연결을 재사용하는 방법?

다음 코드가 있습니다.


    @Test
    public void springTest() throws SQLException{
        //Connect to the DB.
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:/data/h2/testa");
        dataSource.setUsername("");
        dataSource.setPassword("");
        JdbcTemplate jt=new JdbcTemplate(dataSource);
        jt.execute("SELECT 1");
        jt.execute("SELECT 1");
    }

나는 두 개의 execute () 라인이 같은 연결을 재사용 할 것으로 기대한다. 그러나 로그 출력은 다음과 같습니다.

2011-02-10 12:24:17 DriverManagerDataSource [INFO] Loaded JDBC driver: org.h2.Driver
2011-02-10 12:24:17 JdbcTemplate [DEBUG] Executing SQL statement [SELECT 1]
2011-02-10 12:24:17 DataSourceUtils [DEBUG] Fetching JDBC Connection from DataSource
2011-02-10 12:24:17 DriverManagerDataSource [DEBUG] Creating new JDBC DriverManager Connection to [jdbc:h2:/data/h2/testa]
2011-02-10 12:24:17 DataSourceUtils [DEBUG] Returning JDBC Connection to DataSource
2011-02-10 12:24:17 JdbcTemplate [DEBUG] Executing SQL statement [SELECT 1]
2011-02-10 12:24:17 DataSourceUtils [DEBUG] Fetching JDBC Connection from DataSource
2011-02-10 12:24:17 DriverManagerDataSource [DEBUG] Creating new JDBC DriverManager Connection to [jdbc:h2:/data/h2/testa]
2011-02-10 12:24:17 DataSourceUtils [DEBUG] Returning JDBC Connection to DataSource

위의 예제는 매우 빠르게 실행되지만 기본적으로 동일한 작업을 수행하고 새로운 JDBC DriverManager Connection 만들기에 오랜 시간 동안 매달려있는 더 큰 코드 조각이 있습니다. 오류가 발생하지는 않지만 코드가 매우 느리게 실행됩니다. 어떻게 든 동일한 연결을 사용하기 위해 위의 코드를 리팩토링 할 수 있습니까?

감사

해결법

  1. ==============================

    1.다음은 Apache DBCP를 사용하는 예입니다.

    다음은 Apache DBCP를 사용하는 예입니다.

    BasicDataSource dbcp = new BasicDataSource();
    dbcp.setDriverClassName("com.mysql.jdbc.Driver");
    dbcp.setUrl("jdbc:mysql://localhost/test");
    dbcp.setUsername("");
    dbcp.setPassword("");
    
    JdbcTemplate jt = new JdbcTemplate(dbcp);
    jt.execute("SELECT 1");
    jt.execute("SELECT 1");
    

    log4j 출력은 다음과 같습니다.

    [DEBUG] [JdbcTemplate] [execute:416] - Executing SQL statement [SELECT 1]
    [DEBUG] [DataSourceUtils] [doGetConnection:110] - Fetching JDBC Connection from DataSource
    [DEBUG] [DataSourceUtils] [doReleaseConnection:332] - Returning JDBC Connection to DataSource
    [DEBUG] [JdbcTemplate] [execute:416] - Executing SQL statement [SELECT 1]
    [DEBUG] [DataSourceUtils] [doGetConnection:110] - Fetching JDBC Connection from DataSource
    [DEBUG] [DataSourceUtils] [doReleaseConnection:332] - Returning JDBC Connection to DataSource
    
  2. ==============================

    2.Spring은 이것을 수행 할 수있는 특별한 DataSource를 제공한다 : SingleConnectionDataSource

    Spring은 이것을 수행 할 수있는 특별한 DataSource를 제공한다 : SingleConnectionDataSource

    이 코드를 변경하면 트릭을 수행해야합니다.

    SingleConnectionDataSource dataSource = new SingleConnectionDataSource();
    ....
    // The rest stays as is
    

    멀티 스레드 응용 프로그램에서 사용하려면 풀에서 새 연결을 빌려 코드를 데이터베이스 집약적 인 섹션으로 래핑하여 코드 재진입을 만들 수 있습니다.

    // ... this code may be invoked in multiple threads simultaneously ...
    
    try(Connection conn = dao.getDataSource().getConnection()) {
        JdbcTemplate db = new JdbcTemplate(new SingleConnectionDataSource(conn, true));
    
        // ... database-intensive code goes here ... 
        // ... this code also is safe to run simultaneously in multiple threads ...
        // ... provided you are not creating new threads inside here
    }
    
  3. ==============================

    3.단일 트랜잭션으로 래핑되도록 호출이 필요합니다. 일반적으로 애플리케이션에서 Spring의 AOP + @Transactional 어노테이션을 사용하면된다. 또한 프로그래밍 방식으로 PlatformTranactionManager, TransactionTemplate을 사용하고 TransactionCallback에서 실행할 코드를 래핑 할 수 있습니다. 트랜잭션 문서를 참조하십시오.

    단일 트랜잭션으로 래핑되도록 호출이 필요합니다. 일반적으로 애플리케이션에서 Spring의 AOP + @Transactional 어노테이션을 사용하면된다. 또한 프로그래밍 방식으로 PlatformTranactionManager, TransactionTemplate을 사용하고 TransactionCallback에서 실행할 코드를 래핑 할 수 있습니다. 트랜잭션 문서를 참조하십시오.

  4. ==============================

    4.Spring의 코드를 보면 이것은 높은 수준의 나의 이해이다.

    Spring의 코드를 보면 이것은 높은 수준의 나의 이해이다.

    DriverManagerDataSource를 작성 중입니다. 이것은 내부적으로 DataSourceUtils를 사용하여 연결을 설정합니다. 진행중인 활성 트랜잭션이있는 경우에만 연결을 다시 사용합니다. 따라서 두 트랜잭션을 하나의 트랜잭션으로 실행하면 동일한 연결이 사용됩니다. 또는 하나의 연결로 풀링을 사용하여 단일 연결이 만들어지고 재사용 될 수도 있습니다.

  5. ==============================

    5.한 단어로, Spring JDBCTemplate DriverManagerDataSource는 연결 풀을 지원하지 않는다. 연결 풀을 사용하려면 DBCP와 C3P0 모두 좋은 선택입니다.

    한 단어로, Spring JDBCTemplate DriverManagerDataSource는 연결 풀을 지원하지 않는다. 연결 풀을 사용하려면 DBCP와 C3P0 모두 좋은 선택입니다.

    이유를보기 위해 JDBCTemplate 소스 코드를 살펴 보겠습니다 ...

    호출 업데이트, queryForObject 및 다른 메소드와 상관없이 마침내 execute 메소드를 호출합니다.

        @Override
        public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
            Assert.notNull(action, "Callback object must not be null");
    
            Connection con = DataSourceUtils.getConnection(getDataSource());
            try {
                Connection conToUse = con;
                if (this.nativeJdbcExtractor != null) {
                    // Extract native JDBC Connection, castable to OracleConnection or the like.
                    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
                }
                else {
                    // Create close-suppressing Connection proxy, also preparing returned Statements.
                    conToUse = createConnectionProxy(con);
                }
                return action.doInConnection(conToUse);
            }
            catch (SQLException ex) {
                // Release Connection early, to avoid potential connection pool deadlock
                // in the case when the exception translator hasn't been initialized yet.
                DataSourceUtils.releaseConnection(con, getDataSource());
                con = null;
                throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
            }
            finally {
                DataSourceUtils.releaseConnection(con, getDataSource());
            }
        }
    

    DataSourceUtils.getConnection 메서드를 호출하여 연결을 가져오고 DataSourceUtils.releaseConnection을 호출하여 연결을 해제합니다.

    DataSourceUtils 소스 코드에서 Connection con = dataSource.getConnection (); 및 con.close ();

    get 연결 동작은 DataSource 인터페이스를 구현하여 정의되고, close 연결 동작은 Connection 인터페이스를 구현하여 정의됩니다. 이를 통해 다른 DataSource / Connection 구현물을 Spring JDBCTemplate에 쉽게 삽입 할 수 있습니다.

    Spring JDBCTemplate의 DataSource 구현은 DriverManagerDataSource입니다. 에서:

    protected Connection getConnectionFromDriverManager(String url, Properties props) throws SQLException {
        return DriverManager.getConnection(url, props);
    }
    

    public static void doCloseConnection(Connection con, DataSource dataSource) throws SQLException {
        if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
            con.close();
        }
    }
    

    우리는 새로운 연결을 반환 할 때마다이를보고 현재 연결을 닫습니다. 그것이 연결 풀을 지원하지 않는 이유입니다.

    DBCP에서 DataSource 구현은 PoolingDataSource이고 getConnection ()은 연결 풀에서 가져온 것으로 나타납니다. Connection 구현은 PoolableConnection입니다. close () 메서드는 연결을 닫지 않고 대신 연결 풀에 대한 연결을 반환합니다.

    그것은 마술입니다!

  6. ==============================

    6.상황에 따라 (사용할 기능 집합에 따라) 상황이 다르지만 JdbcTemplate.batchUpdate 메서드를 사용하면됩니다.

    상황에 따라 (사용할 기능 집합에 따라) 상황이 다르지만 JdbcTemplate.batchUpdate 메서드를 사용하면됩니다.

  7. from https://stackoverflow.com/questions/4961173/how-to-reuse-the-same-connection-with-a-springs-jdbctemplate by cc-by-sa and MIT license