Spring Boot 를 통 해 동적 데이터 원본 을 설정 하여 여러 데이터베이스 에 접근 하 는 실현 코드
아래 에 설명 한 방안 은 데이터 베 이 스 를 동적 으로 삭제 할 수 있 고 수량 에 제한 이 없다.
데이터베이스 환경 준비
다음 Mysql 의 경우 로 컬 에 3 개의 데이터 베 이 스 를 만들어 테스트 에 사용 합 니 다.설명 이 필요 한 것 은 이 방안 은 데이터 베 이 스 를 제한 하지 않 고 서로 다른 데이터 베 이 스 를 서로 다른 서버 에 배치 하 는 것 을 지원 합 니 다.그림 에서 보 듯 이 dbproject_001、db_project_002、db_project_003。
자바 백 스테이지 마이크로 서비스 프로젝트 구축
Spring Boot 의 maven 프로젝트 만 들 기:
config:데이터 원본 설정 관리 클래스.
datasource:자신 이 실현 한 데이터 소스 관리 논리.
dbmgr:프로젝트 인 코딩 과 데이터베이스 IP,이름 의 맵 관 계 를 관리 합 니 다.
mapper:데이터베이스 액세스 인터페이스.
model:맵 모델.
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.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.elon.dds.datasource.DynamicDataSource;
/**
* 。
*
* @author elon
* @version 2018 2 26
*/
@Configuration
@MapperScan(basePackages="com.elon.dds.mapper", value="sqlSessionFactory")
public class DataSourceConfig {
/**
* 。 。
*
* @return
*/
@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) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
try {
return bean.getObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
2.동적 데이터 원본 정의1) 먼저 데이터베이스 표지 류 를 추가 하여 서로 다른 데이터 베 이 스 를 구분 하 는 데 사용 합 니 다.
우 리 는 서로 다른 프로젝트 를 위해 단독 데이터 베 이 스 를 만 들 었 기 때문에 프로젝트 인 코딩 을 데이터베이스 색인 으로 사용 합 니 다.한편,마이크로 서 비 스 는 다 중 스 레 드 병발 을 지원 하고 스 레 드 변 수 를 사용 합 니 다.
package com.elon.dds.datasource;
/**
* 。 。
*
* @author elon
* @version 2018-02-25
*/
public class DBIdentifier {
/**
*
*/
private static ThreadLocal<String> projectCode = new ThreadLocal<String>();
public static String getProjectCode() {
return projectCode.get();
}
public static void setProjectCode(String code) {
projectCode.set(code);
}
}
2) DataSource 에서 DynamicDataSource 를 파생 하여 데이터베이스 연결 의 동적 전환 을 실현 합 니 다.
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.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import com.elon.dds.dbmgr.ProjectDBMgr;
/**
* 。 DataSource , 。
*
* @author elon
* @version 2018-02-25
*/
public class DynamicDataSource extends DataSource {
private static Logger log = LogManager.getLogger(DynamicDataSource.class);
/**
* 。
*/
@Override
public Connection getConnection(){
String projectCode = DBIdentifier.getProjectCode();
//1、
DataSource dds = DDSHolder.instance().getDDS(projectCode);
//2、
if (dds == null) {
try {
DataSource newDDS = initDDS(projectCode);
DDSHolder.instance().addDDS(projectCode, newDDS);
} catch (IllegalArgumentException | IllegalAccessException e) {
log.error("Init data source fail. projectCode:" + projectCode);
return null;
}
}
dds = DDSHolder.instance().getDDS(projectCode);
try {
return dds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 。
*
* @return dds
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
private DataSource initDDS(String projectCode) throws IllegalArgumentException, IllegalAccessException {
DataSource dds = new DataSource();
// 2、 PoolConfiguration
PoolProperties property = new PoolProperties();
Field[] pfields = PoolProperties.class.getDeclaredFields();
for (Field f : pfields) {
f.setAccessible(true);
Object value = f.get(this.getPoolProperties());
try
{
f.set(property, value);
}
catch (Exception e)
{
log.info("Set value fail. attr name:" + f.getName());
continue;
}
}
dds.setPoolProperties(property);
// 3、 IP( , 、 )
String urlFormat = this.getUrl();
String url = String.format(urlFormat, ProjectDBMgr.instance().getDBIP(projectCode),
ProjectDBMgr.instance().getDBName(projectCode));
dds.setUrl(url);
return dds;
}
}
3) DDSTimer 를 통 해 데이터 연결 방출 제어(지 정 된 시간 을 초과 하여 사용 하지 않 은 데이터 원본 방출)
package 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;
/**
*
*/
private DataSource dds;
/**
*
*/
private long lastUseTime;
public DDSTimer(DataSource dds) {
this.dds = dds;
this.lastUseTime = System.currentTimeMillis();
}
/**
*
*/
public void refreshTime() {
lastUseTime = System.currentTimeMillis();
}
/**
* 。
*
* @return true- ; false-
*/
public boolean checkAndClose() {
if (System.currentTimeMillis() - lastUseTime > idlePeriodTime)
{
dds.close();
return true;
}
return 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>();
/**
*
*/
private static Timer clearIdleTask = new Timer();
static {
clearIdleTask.schedule(new ClearIdleTimerTask(), 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<Entry<String, DDSTimer>> iter = ddsMap.entrySet().iterator();
for (; iter.hasNext(); ) {
Entry<String, DDSTimer> entry = iter.next();
if (entry.getValue().checkAndClose())
{
iter.remove();
}
}
}
/**
*
* @author elon
* @version 2018 2 26
*/
private static class DDSHolderBuilder {
private static DDSHolder instance = new DDSHolder();
}
}
5) 타이머 작업 ClearIdleTimer Task 는 남 은 데이터 원본 을 정시 에 제거 하 는 데 사 용 됩 니 다.
package com.elon.dds.datasource;
import java.util.TimerTask;
/**
* 。
*
* @author elon
* @version 2018 2 26
*/
public class ClearIdleTimerTask extends TimerTask {
@Override
public void run() {
DDSHolder.instance().clearIdleDDS();
}
}
3. 프로젝트 인 코딩 과 데이터베이스 IP 와 이름 의 매 핑 관 계 를 관리 합 니 다.
package 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;
}
//
public String getDBName(String projectCode) {
if (dbNameMap.containsKey(projectCode)) {
return dbNameMap.get(projectCode);
}
return "";
}
//
public String getDBIP(String projectCode) {
if (dbIPMap.containsKey(projectCode)) {
return dbIPMap.get(projectCode);
}
return "";
}
private static class ProjectDBMgrBuilder {
private static ProjectDBMgr instance = new ProjectDBMgr();
}
}
4. 데이터베이스 접근 을 정의 하 는 mapper
package com.elon.dds.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import com.elon.dds.model.User;
/**
* Mybatis 。
*
* @author elon
* @version 2018 2 26
*/
@Mapper
public interface UserMapper
{
/**
*
* @return
*/
@Results(value= {
@Result(property="userId", column="id"),
@Result(property="name", column="name"),
@Result(property="age", column="age")
})
@Select("select id, name, age from tbl_user")
List<User> getUsers();
}
5. 정의 조회 대상 모델
package com.elon.dds.model;
public class User
{
private int userId = -1;
private String name = "";
private int age = -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(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
6. 사용자 데 이 터 를 조회 하 는 restful 인 터 페 이 스 를 정의 합 니 다.
package com.elon.dds.rest;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import 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.elon.dds.model.User;
/**
* 。
*
* @author elon
* @version 2018 2 26
*/
@RestController
@RequestMapping(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", required=true) String projectCode)
{
DBIdentifier.setProjectCode(projectCode);
return userMapper.getUsers();
}
}
매번 조회 할 때마다 procject Code 인 자 를 가 져 오 라 고 요구 합 니 다.7. Spring Boot App 의 시작 코드 를 작성 합 니 다.
package com.elon.dds;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Hello world!
*
*/
@SpringBootApplication
public 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
username: root
password:
driver-class-name: com.mysql.jdbc.Driver
logging:
config: classpath:log4j2.xml
테스트 방안1. 조회 project001 데이터,정상 반환
2. 조회 project002 데이터,정상 반환
총결산
위 에서 말씀 드 린 것 은 스프링 부 트 를 통 해 동적 데이터 원본 을 설정 하여 여러 데이터 베 이 스 를 방문 하 는 실현 코드 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.