>  기사  >  Java  >  alibaba druid를 사용하여 여러 데이터 소스를 연결할 때 발생하는 문제

alibaba druid를 사용하여 여러 데이터 소스를 연결할 때 발생하는 문제

零下一度
零下一度원래의
2017-07-21 17:27:327376검색

alibaba druid를 사용하여 여러 데이터 소스를 연결할 때 발생하는 문제

태그(공백으로 구분): druid springboot start autoconfig


  • Background

  • 검색 및 분석 프로세스

  • 요약

배경

최근 , Alibaba druid를 사용하여 여러 데이터 소스를 연결할 때 실수로 작은 버그를 발견했습니다. github 문제를 제출했는데 공식적으로 수정되었습니다. 문제 주소:

발견 및 분석 프로세스

우리가 사용하는 Java 개발 프레임워크가 캡슐화되어 있습니다. 데이터 소스에 대한 프레임워크의 지원은 마스터 및 슬레이브 아키텍처를 기반으로 합니다. 즉, 여러 슬레이브 데이터 소스의 집합일 수 있으며 마스터-슬레이브 쓰기 및 쿼리 전환이 내부적으로 자동으로 수행됩니다.

현재 .net을 Java로 변환하는 중입니다. 특수한 시나리오에서는 새로운 Java 시스템이 두 개의 데이터 소스에 연결되어야 하지만 때로는 sqlserver 데이터를 쿼리해야 합니다. 일부 호환성 데이터를 얻으려면 소스를 사용하세요.
그래서 두 번째 데이터 소스를 구성할 때 시스템 로드에서 오류가 보고되었습니다.

우리는 springboot 프레임워크를 사용하며, springboot 속성을 기반으로 데이터 소스 구성을 구성합니다. 그런 다음 구성을 사용하여 자동 druid daasource Bean을 생성하십시오. 이것은 문제가 되지 않는 것 같습니다.

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {
       return new DruidDataSource();
    }

springboot가 아닌 경우 일반적으로 모든 속성을 직접 초기화합니다. 구성 파일에서 구성을 로드하고 DruidDataSource 빈을 수동으로 설정합니다.

저는 별 생각 안하고 그냥 이렇게 사용했어요. 그러나 시작 시 Bean을 초기화할 때 오류가 보고되었습니다. maxevictableidletimemillis의 예외는 java.lang.ilegalargumentexception입니다. .

첫 번째 반응은 구성이 잘못되었다는 것입니다. 구성을 확인하세요.

##一个连接在池中最小生存的时间(ms)
ecommon.order.druid.minEvictableIdleTimeMillis=300000
##一个连接在池中最大生存的时间(ms)
ecommon.order.druid.maxEvictableIdleTimeMillis=600000
맞는 것 같은데, 디버그 시에도 같은 문제가 발생합니다. minEvictableIdleTimeMillis 속성과 maxEvictableIdleTimeMillis 속성의 순서는 괜찮은 것 같습니다. 시도해본 후 두 속성의 순서를 바꿨으나 여전히 문제가 발생했습니다.

눈이 먼 상태~_~.

이 문제는 좀 이상하다고 생각합니다. 시간이 중요하기 때문에 오류가 보고된 곳을 직접 찾아 소스 코드를 추적합니다.

github 검색 alibaba druid 홈페이지로 이동하여 직접 git clone하여 오류 프롬프트 위치를 찾습니다.

글로벌 검색 중에 이 예외가 발생하는 곳은 두 곳입니다.

One: init method

public void init() throws SQLException {
            if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
                throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
            }

읽기의 편의를 위해 문제 분석에 쓸모가 없는 init 코드를 삭제했습니다.

두 가지: setMaxEvictableIdleTimeMillis 방법

    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        if (maxEvictableIdleTimeMillis < 1000 * 30) {
            LOG.error("maxEvictableIdleTimeMillis should be greater than 30000");
        }
        
        if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
            throw new IllegalArgumentException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
        }
        
        this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
    }

이 두 가지 방법의 논리는 비교적 간단합니다. 이 두 가지 Bean 속성의 값은 init 초기화 중에 확인됩니다. setMaxEvictableIdleTimeMillis, 최대 생존 시간 설정 시 확인이 있습니다. 최대 생존 시간이 최소 생존 시간보다 적으면 오류가 직접 보고됩니다.

그러므로 이 두 곳에 중단점을 두고 디버그하면 기본적으로 문제가 어디에 있는지 알 수 있습니다.

디버깅을 통해 new DruidDataSource()로 직접 데이터 소스를 사용하면 init 메소드로 이동하지 않는다는 것을 발견했습니다. 오류가 발생한 장소에는 입력되지 않습니다. 내 코드 경로가 이 검사를 생성해서는 안 되는 것 같습니다. 계속 실행하여 setMaxEvictableIdleTimeMillis 메소드에서 어떤 일이 발생하는지 확인하세요.

setMaxEvictableIdleTimeMillis 메서드를 수행할 때 minEvictableIdleTimeMillis 속성 값이 1800000인 문제를 발견했습니다.

이 값이 어디서 나오는지 살펴보겠습니다.

protected volatile long  minEvictableIdleTimeMillis  = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
public static final long  DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 
1000L * 60L * 30L;

minEvictableIdleTimeMillis 속성에는 기본값이 있습니다. 단위는 ms(밀리초)이므로 여기서 기본값은 30m(분)분입니다.

600000ms로 구성했으므로 1800000보다 작습니다. 그러나 이것은 이상합니다. 우리는 minEvictableIdleTimeMillis 매개변수를 명확하게 설정했습니다. 왜 작동하지 않았나요? 저는 즉시 시퀀스 문제라고 생각했습니다.

그런 다음 디버깅을 계속하세요. 먼저 이 검사를 우회하여 setMinEvictableIdleTimeMillis 메서드가 setMaxEvictableIdleTimeMillis 메서드 다음에 실행되어 이 검사가 구성 순서와 충돌하는지 확인하세요.

디버깅하고 보니 이게 정말 문제네요. 그러다가 지금 우리가 사용하고 있는 프레임워크가 druid를 캡슐화하는 데 어떻게 도움이 되는지 더 궁금했습니다. 프레임워크의 소스 코드를 살펴보면 이 문제를 해결하는 해시코드 정렬이 있다는 것을 알 수 있습니다. (물론 베테랑 드라이버이자 마스터) 여기서는 자세히 설명하지 않겠습니다.

그래서 이 문제를 해결하면 실제로 문제를 해결할 위치를 아는 것은 매우 간단합니다.

One: 먼저 구성된 minEvictableIdleTimeMillis 및 maxEvictableIdleTimeMillis를 가져옵니다.

@Data
@EqualsAndHashCode
@ConfigurationProperties(prefix = "ecommon.order.druid")
public class SqlServerDruidConfig {
    private Long minEvictableIdleTimeMillis;
    private Long maxEvictableIdleTimeMillis;
}

Two: 그런 다음 이 두 속성을 먼저 직접 설정하면 springboot autoconfig

 @Autowired
    private SqlServerDruidConfig druidConfig;

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {

        DruidDataSource dataSource = new DruidDataSource();

        /**setMinEvictableIdleTimeMillis需要先设置*/
        dataSource.setMinEvictableIdleTimeMillis(druidConfig.getMinEvictableIdleTimeMillis());
        dataSource.setMaxEvictableIdleTimeMillis(druidConfig.getMaxEvictableIdleTimeMillis());

        return dataSource;
    }

    @Bean
    public SqlServerDruidConfig getDruidConfig() {
        return new SqlServerDruidConfig();
    }

문제 분석이 여기서 끝나도 오류가 발생하지 않습니다. 이 작은 버그는 alibaba druid에 의해 수정되었습니다.

수정 방법에 관심이 있으시면 druid에서 autoconfiger 수정에 대한 코드를 참조하세요:

요약

갑자기 오픈소스의 이점을 실제로 활용했다는 사실을 깨닫게 되실 겁니다. 함께 사용하고, 문제를 발견하고, 버그를 수정하는 데 함께 참여할 수 있습니다. 이것이 리눅스, git 등 훌륭한 예술 작품을 뒷받침하는 핵심적인 기술적 가치일 수도 있습니다.

위 내용은 alibaba druid를 사용하여 여러 데이터 소스를 연결할 때 발생하는 문제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.