日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java多个数据库数据进行访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码...

發(fā)布時(shí)間:2024/9/15 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java多个数据库数据进行访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前寫過一篇博客《Spring+Mybatis+Mysql搭建分布式數(shù)據(jù)庫訪問框架》描述如何通過Spring+Mybatis配置動態(tài)數(shù)據(jù)源訪問多個(gè)數(shù)據(jù)庫。但是之前的方案有一些限制(原博客中也描述了):只適用于數(shù)據(jù)庫數(shù)量不多且固定的情況。針對數(shù)據(jù)庫動態(tài)增加的情況無能為力。

下面講的方案能支持?jǐn)?shù)據(jù)庫動態(tài)增刪,數(shù)量不限。

數(shù)據(jù)庫環(huán)境準(zhǔn)備

下面一Mysql為例,先在本地建3個(gè)數(shù)據(jù)庫用于測試。需要說明的是本方案不限數(shù)據(jù)庫數(shù)量,支持不同的數(shù)據(jù)庫部署在不同的服務(wù)器上。如圖所示db_project_001、db_project_002、db_project_003。

搭建Java后臺微服務(wù)項(xiàng)目

創(chuàng)建一個(gè)Spring Boot的maven項(xiàng)目:

config:數(shù)據(jù)源配置管理類。

datasource:自己實(shí)現(xiàn)的數(shù)據(jù)源管理邏輯。

dbmgr:管理了項(xiàng)目編碼與數(shù)據(jù)庫IP、名稱的映射關(guān)系(實(shí)際項(xiàng)目中這部分?jǐn)?shù)據(jù)保存在redis緩存中,可動態(tài)增刪)。

mapper:數(shù)據(jù)庫訪問接口。

model:映射模型。

rest:微服務(wù)對外發(fā)布的restful接口,這里用來測試。

application.yml:配置了數(shù)據(jù)庫的JDBC參數(shù)。

詳細(xì)的代碼實(shí)現(xiàn)

1. 添加數(shù)據(jù)源配置

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;

/**

* 數(shù)據(jù)源配置管理。

*

* @author elon

* @version 2018年2月26日

*/

@Configuration

@MapperScan(basePackages="com.elon.dds.mapper", value="sqlSessionFactory")

public class DataSourceConfig {

/**

* 根據(jù)配置參數(shù)創(chuàng)建數(shù)據(jù)源。使用派生的子類。

*

* @return 數(shù)據(jù)源

*/

@Bean(name="dataSource")

@ConfigurationProperties(prefix="spring.datasource")

public DataSource getDataSource() {

DataSourceBuilder builder = DataSourceBuilder.create();

builder.type(DynamicDataSource.class);

return builder.build();

}

/**

* 創(chuàng)建會話工廠。

*

* @param dataSource 數(shù)據(jù)源

* @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.定義動態(tài)數(shù)據(jù)源

1)? 首先增加一個(gè)數(shù)據(jù)庫標(biāo)識類,用于區(qū)分不同的數(shù)據(jù)庫訪問。

由于我們?yōu)椴煌膒roject創(chuàng)建了單獨(dú)的數(shù)據(jù)庫,所以使用項(xiàng)目編碼作為數(shù)據(jù)庫的索引。而微服務(wù)支持多線程并發(fā)的,采用線程變量。

package com.elon.dds.datasource;

/**

* 數(shù)據(jù)庫標(biāo)識管理類。用于區(qū)分?jǐn)?shù)據(jù)源連接的不同數(shù)據(jù)庫。

*

* @author elon

* @version 2018-02-25

*/

public class DBIdentifier {

/**

* 用不同的工程編碼來區(qū)分?jǐn)?shù)據(jù)庫

*/

private static ThreadLocal projectCode = new ThreadLocal();

public static String getProjectCode() {

return projectCode.get();

}

public static void setProjectCode(String code) {

projectCode.set(code);

}

}

2)? 從DataSource派生了一個(gè)DynamicDataSource,在其中實(shí)現(xiàn)數(shù)據(jù)庫連接的動態(tài)切換

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;

/**

* 定義動態(tài)數(shù)據(jù)源派生類。從基礎(chǔ)的DataSource派生,動態(tài)性自己實(shí)現(xiàn)。

*

* @author elon

* @version 2018-02-25

*/

public class DynamicDataSource extends DataSource {

private static Logger log = LogManager.getLogger(DynamicDataSource.class);

/**

* 改寫本方法是為了在請求不同工程的數(shù)據(jù)時(shí)去連接不同的數(shù)據(jù)庫。

*/

@Override

public Connection getConnection(){

String projectCode = DBIdentifier.getProjectCode();

//1、獲取數(shù)據(jù)源

DataSource dds = DDSHolder.instance().getDDS(projectCode);

//2、如果數(shù)據(jù)源不存在則創(chuàng)建

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;

}

}

/**

* 以當(dāng)前數(shù)據(jù)對象作為模板復(fù)制一份。

*

* @return dds

* @throws IllegalAccessException

* @throws IllegalArgumentException

*/

private DataSource initDDS(String projectCode) throws IllegalArgumentException, IllegalAccessException {

DataSource dds = new DataSource();

// 2、復(fù)制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、設(shè)置數(shù)據(jù)庫名稱和IP(一般來說,端口和用戶名、密碼都是統(tǒng)一固定的)

String urlFormat = this.getUrl();

String url = String.format(urlFormat, ProjectDBMgr.instance().getDBIP(projectCode),

ProjectDBMgr.instance().getDBName(projectCode));

dds.setUrl(url);

return dds;

}

}

3)? 通過DDSTimer控制數(shù)據(jù)連接釋放(超過指定時(shí)間未使用的數(shù)據(jù)源釋放)

package com.elon.dds.datasource;

import org.apache.tomcat.jdbc.pool.DataSource;

/**

* 動態(tài)數(shù)據(jù)源定時(shí)器管理。長時(shí)間無訪問的數(shù)據(jù)庫連接關(guān)閉。

*

* @author elon

* @version 2018年2月25日

*/

public class DDSTimer {

/**

* 空閑時(shí)間周期。超過這個(gè)時(shí)長沒有訪問的數(shù)據(jù)庫連接將被釋放。默認(rèn)為10分鐘。

*/

private static long idlePeriodTime = 10 * 60 * 1000;

/**

* 動態(tài)數(shù)據(jù)源

*/

private DataSource dds;

/**

* 上一次訪問的時(shí)間

*/

private long lastUseTime;

public DDSTimer(DataSource dds) {

this.dds = dds;

this.lastUseTime = System.currentTimeMillis();

}

/**

* 更新最近訪問時(shí)間

*/

public void refreshTime() {

lastUseTime = System.currentTimeMillis();

}

/**

* 檢測數(shù)據(jù)連接是否超時(shí)關(guān)閉。

*

* @return true-已超時(shí)關(guān)閉; false-未超時(shí)

*/

public boolean checkAndClose() {

if (System.currentTimeMillis() - lastUseTime > idlePeriodTime)

{

dds.close();

return true;

}

return false;

}

public DataSource getDds() {

return dds;

}

}

4)????? 增加DDSHolder來管理不同的數(shù)據(jù)源,提供數(shù)據(jù)源的添加、查詢功能

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;

/**

* 動態(tài)數(shù)據(jù)源管理器。

*

* @author elon

* @version 2018年2月25日

*/

public class DDSHolder {

/**

* 管理動態(tài)數(shù)據(jù)源列表。

*/

private Map ddsMap = new HashMap();

/**

* 通過定時(shí)任務(wù)周期性清除不使用的數(shù)據(jù)源

*/

private static Timer clearIdleTask = new Timer();

static {

clearIdleTask.schedule(new ClearIdleTimerTask(), 5000, 60 * 1000);

};

private DDSHolder() {

}

/*

* 獲取單例對象

*/

public static DDSHolder instance() {

return DDSHolderBuilder.instance;

}

/**

* 添加動態(tài)數(shù)據(jù)源。

*

* @param projectCode 項(xiàng)目編碼

* @param dds dds

*/

public synchronized void addDDS(String projectCode, DataSource dds) {

DDSTimer ddst = new DDSTimer(dds);

ddsMap.put(projectCode, ddst);

}

/**

* 查詢動態(tài)數(shù)據(jù)源

*

* @param projectCode 項(xiàng)目編碼

* @return dds

*/

public synchronized DataSource getDDS(String projectCode) {

if (ddsMap.containsKey(projectCode)) {

DDSTimer ddst = ddsMap.get(projectCode);

ddst.refreshTime();

return ddst.getDds();

}

return null;

}

/**

* 清除超時(shí)無人使用的數(shù)據(jù)源。

*/

public synchronized void clearIdleDDS() {

Iterator> iter = ddsMap.entrySet().iterator();

for (; iter.hasNext(); ) {

Entry entry = iter.next();

if (entry.getValue().checkAndClose())

{

iter.remove();

}

}

}

/**

* 單例構(gòu)件類

* @author elon

* @version 2018年2月26日

*/

private static class DDSHolderBuilder {

private static DDSHolder instance = new DDSHolder();

}

}

5)????? 定時(shí)器任務(wù)ClearIdleTimerTask用于定時(shí)清除空閑的數(shù)據(jù)源

package com.elon.dds.datasource;

import java.util.TimerTask;

/**

* 清除空閑連接任務(wù)。

*

* @author elon

* @version 2018年2月26日

*/

public class ClearIdleTimerTask extends TimerTask {

@Override

public void run() {

DDSHolder.instance().clearIdleDDS();

}

}

3.?????? 管理項(xiàng)目編碼與數(shù)據(jù)庫IP和名稱的映射關(guān)系

package com.elon.dds.dbmgr;

import java.util.HashMap;

import java.util.Map;

/**

* 項(xiàng)目數(shù)據(jù)庫管理。提供根據(jù)項(xiàng)目編碼查詢數(shù)據(jù)庫名稱和IP的接口。

* @author elon

* @version 2018年2月25日

*/

public class ProjectDBMgr {

/**

* 保存項(xiàng)目編碼與數(shù)據(jù)名稱的映射關(guān)系。這里是硬編碼,實(shí)際開發(fā)中這個(gè)關(guān)系數(shù)據(jù)可以保存到redis緩存中;

* 新增一個(gè)項(xiàng)目或者刪除一個(gè)項(xiàng)目只需要更新緩存。到時(shí)這個(gè)類的接口只需要修改為從緩存拿數(shù)據(jù)。

*/

private Map dbNameMap = new HashMap();

/**

* 保存項(xiàng)目編碼與數(shù)據(jù)庫IP的映射關(guān)系。

*/

private Map dbIPMap = new HashMap();

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;

}

// 實(shí)際開發(fā)中改為從緩存獲取

public String getDBName(String projectCode) {

if (dbNameMap.containsKey(projectCode)) {

return dbNameMap.get(projectCode);

}

return "";

}

//實(shí)際開發(fā)中改為從緩存中獲取

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.?????? 定義數(shù)據(jù)庫訪問的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

{

/**

* 查詢所有用戶數(shù)據(jù)

* @return 用戶數(shù)據(jù)列表

*/

@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 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.?????? 定義查詢用戶數(shù)據(jù)的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;

/**

* 用戶數(shù)據(jù)訪問接口。

*

* @author elon

* @version 2018年2月26日

*/

@RestController

@RequestMapping(value="/user")

public class WSUser {

@Autowired

private UserMapper userMapper;

/**

* 查詢項(xiàng)目中所有用戶信息

*

* @param projectCode 項(xiàng)目編碼

* @return 用戶列表

*/

@RequestMapping(value="/v1/users", method=RequestMethod.GET)

public List queryUser(@RequestParam(value="projectCode", required=true) String projectCode)

{

DBIdentifier.setProjectCode(projectCode);

return userMapper.getUsers();

}

}

要求每次查詢都要帶上projectCode參數(shù)。

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中配置數(shù)據(jù)源

其中的數(shù)據(jù)庫IP和數(shù)據(jù)庫名稱使用%s。在查詢用戶數(shù)據(jù)中動態(tài)切換。

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.?????? 查詢project_001的數(shù)據(jù),正常返回

2.?????? 查詢project_002的數(shù)據(jù),正常返回

總結(jié)

以上所述是小編給大家介紹的通過Spring Boot配置動態(tài)數(shù)據(jù)源訪問多個(gè)數(shù)據(jù)庫的實(shí)現(xiàn)代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

總結(jié)

以上是生活随笔為你收集整理的java多个数据库数据进行访问_通过Spring Boot配置动态数据源访问多个数据库的实现代码...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 午夜在线播放 | 日韩一区网站 | 伊人网色 | 国产成人亚洲综合a∨婷婷 台湾a级片 | 色婷婷婷婷色 | 亚洲永久免费 | av先锋在线 | 狠狠ri | 国产电影一区二区三区爱妃记 | www.久久久久久久久 | 尤物在线观看 | 91秦先生在线播放 | 在线视频91| 久久久视频6r | 噜噜在线视频 | 亚洲高清视频在线播放 | 大又大又粗又硬又爽少妇毛片 | 欧美性生交xxxxx | 小毛片在线观看 | 亚洲一区二区精品视频 | 福利91 | av在线网站观看 | 999www| 久久小视频 | 国产综合无码一区二区色蜜蜜 | 亚洲国产av一区 | 老汉色av| 欧美高清不卡 | 亚洲综合网站 | 无码人妻精品一区二区三应用大全 | 午夜色网站 | 国产在线中文 | 国产欧美精品区一区二区三区 | 免费污视频在线观看 | 成人国产精品免费 | 欧美一级乱黄 | 亚洲午夜精品在线 | 五月婷婷免费视频 | 少妇av一区二区三区无码 | 91视频免费视频 | ass亚洲熟妇毛耸耸pics | 九九热国产视频 | 人妻视频一区二区三区 | 日韩视频在线一区二区 | 97人人澡人人爽人人模亚洲 | 亚洲最大看欧美片网站 | 99精品黄色 | 亚洲人人夜夜澡人人爽 | 欧美在线你懂的 | 日本一本视频 | 99色综合 | 超碰在线播放97 | 女人扒开腿让男人桶爽 | 稀缺呦国内精品呦 | av在线www | 久久黄色免费网站 | 日日网| 精品区在线观看 | 欧美日韩中文字幕在线视频 | 播播激情网 | 色婷婷久久一区二区三区麻豆 | 香蕉a | 亚洲综合伊人 | 色综合av综合无码综合网站 | 黄色大片91| 欧美一区三区三区高中清蜜桃 | www.插插 | 亚洲最大视频网 | 日本wwwxxx| 校园春色欧美 | 日韩网站免费观看高清 | 黄色的网站免费观看 | 欧美成人免费高清视频 | 日本黄色小片 | 黄色天堂网站 | 好吊操免费视频 | 黄色小说网站在线观看 | 九七在线视频 | 亚洲欧美日韩天堂 | 在线日韩免费 | 超碰av男人的天堂 | www.欧美色| 国产一区毛片 | 蜜臀av性久久久久蜜臀av麻豆 | 久久久久亚洲av无码专区 | 亚洲一区二区精品视频 | 亚洲天堂一 | 污污视频在线免费观看 | 精品无码久久久久久久久久 | 亚洲视频在线一区 | 日韩三级久久 | 黄色第一网站 | 亚洲国产一二三 | 奇米在线777| 97se在线| 久久亚洲精 | 日韩二区在线 | 日韩欧美在线视频观看 | 人妻丝袜一区 |