Spring+MyBatis 구성 동적 데이터 소스를 통해 여러 데이터베이스에 액세스하는 방법을 설명하기 전에 "Spring+MyBatis+MySQL"블로그 "분산 데이터베이스 액세스 프레임 워크를 구축하기 위해"블로그를 작성했습니다. 그러나 이전 솔루션에는 몇 가지 제한 사항이 있습니다 (원래 블로그에 설명). 데이터베이스 수가 작고 고정 된 상황에만 적용됩니다. 데이터베이스 동적이 증가하는 상황에 대해서는 할 일이 없습니다.
아래에 언급 된 체계는 동적 데이터베이스 추가 및 삭제를 지원할 수 있으며 숫자는 무제한입니다.
데이터베이스 환경 준비
예를 들어 MySQL은 다음과 같습니다. 먼저 테스트를 위해 3 개의 데이터베이스를 로컬로 빌드합니다. 이 솔루션은 데이터베이스 수를 제한하지 않으며 다른 서버에서 다른 데이터베이스의 배포를 지원합니다. 그림과 같이 DB_PROJECT_001, DB_PROJECT_002, DB_PROJECT_003.
Java 백엔드 마이크로 서비스 프로젝트를 구축하십시오
Spring Boot Maven 프로젝트 만들기 :
구성 : 데이터 소스 구성 관리 클래스.
DataSource : 자체적으로 구현 된 데이터 소스 관리 로직.
DBMGR : 프로젝트 인코딩과 데이터베이스 IP와 이름 간의 매핑 관계를 관리합니다 (실제 프로젝트의 데이터 의이 부분은 Redis 캐시에 저장되어 동적으로 추가 및 삭제할 수 있음).
맵퍼 : 데이터베이스 액세스 인터페이스.
모델 : 맵핑 모델.
REST : 마이크로 서비스가 외부로 출시 한 RESTFUL 인터페이스는 테스트에 사용되었습니다.
application.yml : 데이터베이스의 JDBC 매개 변수를 구성합니다.
자세한 코드 구현
1. 데이터 소스 구성 추가
package com.elon.dds.config; import javax.sql.datasource; import org.apache.ibatis.session.sqlsessionfactory; import org.mybatis.spring.sqlsessionfactorybean; import org.mybatis.spring.annotation.mappercan; import org.springframework.bean.bean.bean.annotation.qualifier; import org.springframework.boot.autoconfigure.jdbc.datasourcebuilder; import org.springframework.boot.context.properties.configurationProperties; import org.springframework.context.annotation.bean; org.springframework.context.annotation.configuration; com.elon.dds.datasource.dynamicdatasource;/*** 데이터 소스 구성 관리. * * @author Elon * @version 2018 년 2 월 26 일 * / @configuration @mapperscan (basepackages = "com.elon.dds.mapper", value = "sqlsessionfactory") public class dataSourceConfig { /** * 구성 매개 변수를 기반으로 데이터 소스 생성. 파생 된 서브 클래스를 사용하십시오. * * @return data source */ @bean (name = "dataSource") @configurationProperties (prefix = "spring.datasource") public dataSource getDatasource () {dataSourceBuilder builder = dataSourceBuilder.create (); Builder.type (DynamicDatasource.class); return builder.build (); } /*** 세션 공장을 만듭니다. ** @param dataSource 데이터 소스* @return 세션 공장*/ @bean (name = "sqlsessionfactory") public sqlsessionfactory getSqlsessionFactory (@Qualifier ( "DataSource") DataSource DataSource) {sqlsessionCeptoryBean Bean = new sqlsessionFactoryBean (); Bean.SetDatasource (DataSource); {return bean.getObject (); } catch (예외 e) {e.printstacktrace (); 널 리턴; }}} 2. 동적 데이터 소스를 정의합니다
1) 먼저 다른 데이터베이스 액세스를 구별하기 위해 데이터베이스 아이덴티티 클래스를 추가하십시오.
다른 프로젝트에 대한 별도의 데이터베이스를 만들었으므로 프로젝트 인코딩을 데이터베이스의 색인으로 사용했습니다. 마이크로 서비스는 다중 스레드 동시성을 지원하고 스레드 변수를 사용합니다.
Com.elon.dds.datasource;/*** 데이터베이스 ID 관리 클래스. 데이터 소스에 연결된 다른 데이터베이스를 구별하는 데 사용됩니다. * * @Author Elon * @version 2018-02-25 */public class dbidentifier {/** * 데이터베이스를 구별하기 위해 다른 프로젝트 인코딩을 사용 */private static strandlocal <string> projectCode = new ThreadLocal <string> (); public static string getProjectCode () {return projectCode.get (); } public static void setProjectCode (문자열 코드) {projectCode.Set (코드); }}2) DynamicDatasource는 데이터베이스 연결의 동적 전환이 구현되는 DataSource에서 파생됩니다.
import java.lang.reflect.field; import java.sql.connection; import java.sql.sqlexception; import org.apache.logging.log4j.logmanager; import org.apache.logging.log4j.logger; import org.apache.tomcat.jdbc.pool.datasouce; org.apache.tomcat.jdbc.pool.poolproperties; import com.elon.dds.dbmgr.projectdbmgr;/*** 동적 데이터 소스 파생 클래스 정의. 기본 데이터 소스에서 파생되어 자체적으로 동적으로 구현됩니다. * * @Author Elon * @version 2018-02-25 */public class dynamicDatasource 확장 DataSource {private static logger log = logmanager.getLogger (DynamicDatasource.class); /***이 방법은 다른 프로젝트에서 데이터를 요청할 때 다른 데이터베이스에 연결하는 것입니다. */ @override public connection getConnection () {문자열 projectCode = dbidentifier.getProjectCode (); // 1. 데이터 소스 데이터 소스 DDS = DDSHOLDER.Instance (). getDds (ProjectCode)를 가져옵니다. // 2. if (dds == null) {try {dataSource newdds = initdds (projectCode); ddsholder.instance (). adddds (projectCode, newDDS); } catch (불법 행정 exception | 불법 행위 exception e) {log.error ( "Init Data Source 실패. projectCode :" + projectCode); 널 리턴; }} dds = ddsholder.instance (). getDds (projectCode); try {return dds.getConnection (); } catch (sqlexception e) {e.printstacktrace (); 널 리턴; }} /*** 현재 데이터 객체와 함께 사본을 템플릿으로 복사합니다. * * @return dds * @Throws 불법 행위 exception * @Throws 불법 행위 exception */ private dataSource initdds (String ProjectCode)는 불법 행위 exception, 불법 DDS = new DataSource (); // 2. PoolConfiguration PoolProperties 속성의 속성을 복사합니다. 필드 [] pfields = poolProperties.class.getDeclaredFields (); for (field f : pfields) {f.setAccessible (true); 개체 값 = f.get (this.getPoolProperties ()); try {f.set (속성, 값); } catch (예외 e) {log.info ( "set value fail. att name :" + f.getname ()); 계속하다; }} dds.setPoolProperties (속성); // 3. 데이터베이스 이름과 IP를 설정합니다 (일반적으로 포트, 사용자 이름 및 비밀번호는 균일하게 고정되어 있습니다) 문자열 urlformat = this.getUrl (); String url = string.format (urlformat, projectDbmgr.instance (). getDbip (projectCode), projectDbmgr.instance (). getDbname (projectCode)); dds.seturl (url); 반환 DDS; }}3) DDSTIMER를 통해 데이터 연결 릴리스 제어 (지정된 시간을 초과 한 미사용 데이터 소스 릴리스)
패키지 com.elon.dds.datasource; import org.apache.tomcat.jdbc.pool.datasource;/*** 동적 데이터 소스 타이머 관리. 오랫동안 액세스 할 수없는 데이터베이스 연결이 닫힙니다. * * @author Elon * @version 2018 년 2 월 25 일 * /public class ddstimer { /** * 유휴 기간. 이 시간보다 더 이상 액세스되지 않은 데이터베이스 연결이 해제됩니다. 기본값은 10 분입니다. */ Private STATIC LONG IDLEPERIODTIME = 10 * 60 * 1000; / *** 동적 데이터 소스*/ 개인 데이터 소스 DDS; / *** 마지막 액세스 시간*/ Private Long Lastusetime; public ddstimer (dataSource dds) {this.dds = dds; this.lastusetime = System.CurrentTimeMillis (); } / *** 최신 액세스 시간을 업데이트했습니다* / public void refreshtime () {lastusetime = System.CurrentTimeMillis (); } /*** 타임 아웃으로 인해 데이터 연결이 닫혀 있는지 여부를 감지합니다. * * * @return true- 시간 내에; false -timed out*/ public boolean checkandclose () {if (system.currenttimeMillis () - lastuseTime> idleperiodtime) {dds.close (); 진실을 반환하십시오. } false를 반환합니다. } public dataSource getDds () {return dds; }}4) 다른 데이터 소스를 관리하고 데이터 소스 추가 및 쿼리 기능을 제공하기 위해 DDSHOLDER 추가
package com.elon.dds.datasource; import java.util.hashmap; import java.util.iterator; import java.util.map; import java.util.map.entry; import java.util.timer; import org.apache.tomcat.jdbc.pool.datasource;/* ** ** ** ** ** ** ** ** ** ** ** ** 동시에. * * @Author Elon * @version 2018 년 2 월 25 일 * /public class ddsholder { /** * 동적 데이터 소스 목록 관리. <프로젝트 인코딩, 데이터 소스> */ private map <string, ddstimer> ddsmap = new Hashmap <String, ddstimer> (); / *** 시간이 지정된 작업을 통해 주기적으로 사용되지 않은 데이터 소스*/ 개인 정적 타이머 clearIdletask = new Timer (); static {clearIdletask.schedule (new stareidletimertask (), 5000, 60 * 1000); }; private ddsholder () {} /** 싱글 톤 객체를 얻습니다* / public static ddsholder instance () {return ddsholderBuilder.instance; } /*** 동적 데이터 소스를 추가합니다. * * @param projectCode 프로젝트 인코딩 * @param dds dds */ public synchronized void adddds (String ProjectCode, DataSource DDS) {ddstimer ddst = new ddstimer (dds); ddsmap.put (projectCode, DDST); } / *** 쿼리 동적 데이터 소스** @param projectCode 프로젝트 인코딩* @return dds* / public synchronized dataSource getDds (String ProjectCode) {if (ddsmap.containskey (projectCode)) {ddstimer ddst = ddsmap.get (projectCode); ddst.refreshtime (); return ddst.getdds (); } return null; } /*** 누구 없이도 시간을 초과 한 데이터 소스를 지우십시오. */ public synchronized void clearIdledds () {iterator <eptry <string, ddstimer >> iter = ddsmap.entryset (). iterator (); for (; iter.hasnext ();) {Entry <string, ddstimer> entry = iter.next (); if (Entry.GetValue (). CheckandClose ()) {iter.remove (); }}} / *** Singleton Artifact 클래스* @Author Elon* @version 2018 년 2 월 26 일* / 개인 정적 클래스 ddsholderBuilder {private static ddsholder instance = new ddsholder (); }}5) 타이머 작업 ClearIdleTimertask는 정기적으로 유휴 데이터 소스를 지우는 데 사용됩니다.
Com.elon.dds.datasource; import java.util.timertask;/*** 유휴 연결 작업을 명확하게합니다. * * @Author Elon * @version 2018 년 2 월 26 일 */public class clearIdletimertask는 Timertask {@override public void run () {ddsholder.instance (). clearidledds (); }}3. 프로젝트 인코딩 데이터베이스 IP 및 이름과의 매핑 관계 관리
패키지 com.elon.dds.dbmgr; import java.util.hashmap; import java.util.map;/*** 프로젝트 데이터베이스 관리. 프로젝트 인코딩을 기반으로 쿼리 데이터베이스 이름과 IP에 대한 인터페이스를 제공합니다. * @Author Elon* @version 2018 년 2 월 25 일* /Public Class ProjectDBMGR { /*** 프로젝트 인코딩과 데이터 이름 간의 매핑 관계 저장. 하드 코드는 다음과 같습니다. 실제 개발 에서이 관계형 데이터는 Redis 캐시에 저장 될 수 있습니다. * 새 프로젝트 추가 또는 프로젝트 삭제하려면 캐시를 업데이트하면됩니다. 당시이 클래스의 인터페이스는 캐시에서 데이터를 가져 오기 위해서만 수정하면됩니다. */ private map <string, String> dbnamemap = new Hashmap <String, String> (); /*** 프로젝트 인코딩과 데이터베이스 IP 간의 매핑 관계를 저장합니다. */ private map <string, String> dbipMap = new Hashmap <String, String> (); private projectdbmgr () {dbnamemap.put ( "project_001", "db_project_001"); dbnamemap.put ( "project_002", "db_project_002"); dbnamemap.put ( "project_003", "db_project_003"); dbipmap.put ( "project_001", "127.0.0.1"); dbipmap.put ( "project_002", "127.0.0.1"); dbipmap.put ( "project_003", "127.0.0.1"); } public static projectDbmgr instance () {return projectDbmgrBuilder.instance; } // 실제 개발에서 공개 문자열을 얻기 위해 변경되었습니다. getDbname (String ProjectCode) {if (dbnamemap.containskey (projectCode)) {return dbnamemap.get (projectCode); } 반품 ""; } // 실제 개발에서 공개 문자열을 가져 오기 위해 변경됩니다. getDbip (String ProjectCode) {if (dbipmap.containskey (projectCode)) {return dbipmap.get (projectCode); } 반품 ""; } private static class projectdbmgrBuilder {private static projectdbmgr instance = new ProjectDbmgr (); }} 4. 데이터베이스 액세스를 위해 맵퍼를 정의하십시오
패키지 com.elon.dds.mapper; import java.util.list; import org.apache.ibatis.annotations.mapper; import org.apache.annotations.result; import org.apache.ibatis.annotations.results; import org.apache.abatis.annottations.select; import com. dd.dd.dd. mybatis 매핑 인터페이스 정의. ** @Author Elon* @version 2018 년 2 월 26 일*/ @mapperPublic Interface usermapper {/*** 모든 사용자 데이터 쿼리* @return 사용자 데이터 목록*/@Results (value = {@result (property = "userId", column = "id"), @result (property = "name", column = "name"), @geeng (age age = "")) @Select ( "선택 ID, 이름, TBL_USER에서 나이") 목록 <user> getUsers ();} 5. 쿼리 객체 모델을 정의합니다
package com.elon.dds.model; public class user {private int userId = -1; 개인 문자열 이름 = ""; 개인 int 연령 = -1; @override public String tostring () {return "name :" + name + "| age :" + age; } public int getUserId () {return userId; } public void setUserId (int userId) {this.userid = userId; } public String getName () {return name; } public void setName (문자열 이름) {this.name = 이름; } public int getage () {반환 연령; } public void 설정 (int Age) {this.age = age; }} 6. 사용자 데이터를 쿼리하기 위해 RESTFUL 인터페이스를 정의하십시오
package com.elon.dds.rest; import java.util.list; import org.springframework.bean.bean.bind.annotation.autowired; import org.springframework.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestmethod; org.springframework.web.bind.annotation.requestparam; import org.springframework.web.bind.annotation.restcontroller; import com.elon.dds.datasource.dbidentifier; import com.elon.dds.mapper.usermapper; import com.lon.dds.model.mel.ser. * * @Author Elon * @version 2018 년 2 월 26 일 */ @restController @restontroller (value = "/user") public class wsuser {@autowired private usermapper usermapper; /*** 프로젝트의 모든 사용자 정보 쿼리** @param projectCode 프로젝트 인코딩* @return 사용자 목록*/@requestmapping (value = "/v1/users", method = requestmethod.get) public list <user> queryuser (@requestparam (value = "projectCode", requireCode ") usermapper.getUsers ()를 반환합니다. }}ProjectCode 매개 변수는 각 쿼리에 포함되어야합니다.
7. Spring Boot 앱의 시작 코드를 작성하십시오
패키지 com.elon.dds; import org.springframework.boot.springApplication; import org.springframework.boot.autoconfigure.springbootApplication;/*** Hello World! * */@springbootApplicationPublic Class App {public static void main (String [] args) {System.out.println ( "Hello World!"); SpringApplication.run (App.Class, Args); }} 8. Application.yml에서 데이터 소스를 구성합니다
데이터베이스 IP 및 데이터베이스 이름은 %s와 함께 사용됩니다. 사용자 데이터 쿼리에서 동적으로 전환합니다.
Spring : DataSource : url : jdbc : mysql : //%s : 3306/%s? useUnicode = true & characterencoding = utf-8 사용자 이름 : 루트 암호 : driver class-name : com.mysql.jdbc.driverlogging : config : log4j2.xml
시험 계획
1. Project_001의 데이터를 쿼리하고 정상적으로 반환하십시오
2. Project_002의 데이터를 쿼리하고 정상적으로 반환하십시오
요약
위는 Spring Boot 구성 동적 데이터 소스를 통해 여러 데이터베이스에 액세스하기위한 구현 코드입니다. 모든 사람에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 모든 사람에게 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!