国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Spring Boot 動(dòng)態(tài)數(shù)據(jù)源示例(多數(shù)據(jù)源自動(dòng)切換)

Spring Boot 動(dòng)態(tài)數(shù)據(jù)源示例(多數(shù)據(jù)源自動(dòng)切換)

2020-08-18 11:34catoop Java教程

本篇文章主要介紹了Spring Boot 動(dòng)態(tài)數(shù)據(jù)源示例(多數(shù)據(jù)源自動(dòng)切換),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

本文實(shí)現(xiàn)案例場(chǎng)景:

某系統(tǒng)除了需要從自己的主要數(shù)據(jù)庫(kù)上讀取和管理數(shù)據(jù)外,還有一部分業(yè)務(wù)涉及到其他多個(gè)數(shù)據(jù)庫(kù),要求可以在任何方法上可以靈活指定具體要操作的數(shù)據(jù)庫(kù)。

為了在開(kāi)發(fā)中以最簡(jiǎn)單的方法使用,本文基于注解和AOP的方法實(shí)現(xiàn),在spring boot框架的項(xiàng)目中,添加本文實(shí)現(xiàn)的代碼類后,只需要配置好數(shù)據(jù)源就可以直接通過(guò)注解使用,簡(jiǎn)單方便。

一配置二使用

1. 啟動(dòng)類注冊(cè)動(dòng)態(tài)數(shù)據(jù)源

2. 配置文件中配置多個(gè)數(shù)據(jù)源

3. 在需要的方法上使用注解指定數(shù)據(jù)源

1、在啟動(dòng)類添加 @Import({DynamicDataSourceRegister.class, MProxyTransactionManagementConfiguration.class})

?
1
2
3
4
5
6
@SpringBootApplication
@Import({DynamicDataSourceRegister.class}) // 注冊(cè)動(dòng)態(tài)多數(shù)據(jù)源
public class SpringBootSampleApplication {
 
  // 省略其他代碼
}

2、配置文件配置內(nèi)容為: (不包括項(xiàng)目中的其他配置,這里只是數(shù)據(jù)源相關(guān)的)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 主數(shù)據(jù)源,默認(rèn)的
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
 
# 更多數(shù)據(jù)源
custom.datasource.names=ds1,ds2
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1
custom.datasource.ds1.username=root
custom.datasource.ds1.password=123456
 
custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test2
custom.datasource.ds2.username=root
custom.datasource.ds2.password=123456

3、使用方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package org.springboot.sample.service;
 
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
 
import org.springboot.sample.datasource.TargetDataSource;
import org.springboot.sample.entity.Student;
import org.springboot.sample.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
 
/**
 * Student Service
 *
 * @author  單紅宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create  2016年1月12日
 */
@Service
public class StudentService {
 
  @Autowired
  private JdbcTemplate jdbcTemplate;
 
  // MyBatis的Mapper方法定義接口
  @Autowired
  private StudentMapper studentMapper;
 
  @TargetDataSource(name="ds2")
  public List<Student> likeName(String name){
    return studentMapper.likeName(name);
  }
 
  public List<Student> likeNameByDefaultDataSource(String name){
    return studentMapper.likeName(name);
  }
 
  /**
   * 不指定數(shù)據(jù)源使用默認(rèn)數(shù)據(jù)源
   *
   * @return
   * @author SHANHY
   * @create 2016年1月24日
   */
  public List<Student> getList(){
    String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
    return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
 
      @Override
      public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
        Student stu = new Student();
        stu.setId(rs.getInt("ID"));
        stu.setAge(rs.getInt("AGE"));
        stu.setName(rs.getString("NAME"));
        stu.setSumScore(rs.getString("SCORE_SUM"));
        stu.setAvgScore(rs.getString("SCORE_AVG"));
        return stu;
      }
 
    });
  }
 
  /**
   * 指定數(shù)據(jù)源
   *
   * @return
   * @author SHANHY
   * @create 2016年1月24日
   */
  @TargetDataSource(name="ds1")
  public List<Student> getListByDs1(){
    String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
    return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
 
      @Override
      public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
        Student stu = new Student();
        stu.setId(rs.getInt("ID"));
        stu.setAge(rs.getInt("AGE"));
        stu.setName(rs.getString("NAME"));
        stu.setSumScore(rs.getString("SCORE_SUM"));
        stu.setAvgScore(rs.getString("SCORE_AVG"));
        return stu;
      }
 
    });
  }
 
  /**
   * 指定數(shù)據(jù)源
   *
   * @return
   * @author SHANHY
   * @create 2016年1月24日
   */
  @TargetDataSource(name="ds2")
  public List<Student> getListByDs2(){
    String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE  FROM STUDENT";
    return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){
 
      @Override
      public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
        Student stu = new Student();
        stu.setId(rs.getInt("ID"));
        stu.setAge(rs.getInt("AGE"));
        stu.setName(rs.getString("NAME"));
        stu.setSumScore(rs.getString("SCORE_SUM"));
        stu.setAvgScore(rs.getString("SCORE_AVG"));
        return stu;
      }
 
    });
  }
}

要注意的是,在使用MyBatis時(shí),注解@TargetDataSource 不能直接在接口類Mapper上使用。

按上面的代碼中StudentMapper為接口,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.springboot.sample.mapper;
 
import java.util.List;
 
import org.springboot.sample.entity.Student;
 
/**
 * StudentMapper,映射SQL語(yǔ)句的接口,無(wú)邏輯實(shí)現(xiàn)
 *
 * @author 單紅宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月20日
 */
public interface StudentMapper {
 
  // 注解 @TargetDataSource 不可以在這里使用
  List<Student> likeName(String name);
 
  Student getById(int id);
 
  String getNameById(int id);
 
}

請(qǐng)將下面幾個(gè)類放到Spring Boot項(xiàng)目中。

DynamicDataSource.Java

DynamicDataSourceAspect.java

DynamicDataSourceContextHolder.java

DynamicDataSourceRegister.java

TargetDataSource.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package org.springboot.sample.datasource;
 
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源
 *
 * @author  單紅宇(365384722)
 * @create  2016年1月22日
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
 
  @Override
  protected Object determineCurrentLookupKey() {
    return DynamicDataSourceContextHolder.getDataSourceType();
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.springboot.sample.datasource;
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
 
/**
 * 切換數(shù)據(jù)源Advice
 *
 * @author 單紅宇(365384722)
 * @create 2016年1月23日
 */
@Aspect
@Order(-1)// 保證該AOP在@Transactional之前執(zhí)行
@Component
public class DynamicDataSourceAspect {
 
  private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
 
  @Before("@annotation(ds)")
  public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {
    String dsId = ds.name();
    if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
      logger.error("數(shù)據(jù)源[{}]不存在,使用默認(rèn)數(shù)據(jù)源 > {}", ds.name(), point.getSignature());
    } else {
      logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());
      DynamicDataSourceContextHolder.setDataSourceType(ds.name());
    }
  }
 
  @After("@annotation(ds)")
  public void restoreDataSource(JoinPoint point, TargetDataSource ds) {
    logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());
    DynamicDataSourceContextHolder.clearDataSourceType();
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package org.springboot.sample.datasource;
 
import java.util.ArrayList;
import java.util.List;
 
public class DynamicDataSourceContextHolder {
 
  private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
  public static List<String> dataSourceIds = new ArrayList<>();
 
  public static void setDataSourceType(String dataSourceType) {
    contextHolder.set(dataSourceType);
  }
 
  public static String getDataSourceType() {
    return contextHolder.get();
  }
 
  public static void clearDataSourceType() {
    contextHolder.remove();
  }
 
  /**
   * 判斷指定DataSrouce當(dāng)前是否存在
   *
   * @param dataSourceId
   * @return
   * @author SHANHY
   * @create 2016年1月24日
   */
  public static boolean containsDataSource(String dataSourceId){
    return dataSourceIds.contains(dataSourceId);
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package org.springboot.sample.datasource;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.sql.DataSource;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源注冊(cè)<br/>
 * 啟動(dòng)動(dòng)態(tài)數(shù)據(jù)源請(qǐng)?jiān)趩?dòng)類中(如SpringBootSampleApplication)
 * 添加 @Import(DynamicDataSourceRegister.class)
 *
 * @author 單紅宇(365384722)
 * @create 2016年1月24日
 */
public class DynamicDataSourceRegister
    implements ImportBeanDefinitionRegistrar, EnvironmentAware {
 
  private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
 
  private ConversionService conversionService = new DefaultConversionService();
  private PropertyValues dataSourcePropertyValues;
 
  // 如配置文件中未指定數(shù)據(jù)源類型,使用該默認(rèn)值
  private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
  // private static final Object DATASOURCE_TYPE_DEFAULT =
  // "com.zaxxer.hikari.HikariDataSource";
 
  // 數(shù)據(jù)源
  private DataSource defaultDataSource;
  private Map<String, DataSource> customDataSources = new HashMap<>();
 
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
    // 將主數(shù)據(jù)源添加到更多數(shù)據(jù)源中
    targetDataSources.put("dataSource", defaultDataSource);
    DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
    // 添加更多數(shù)據(jù)源
    targetDataSources.putAll(customDataSources);
    for (String key : customDataSources.keySet()) {
      DynamicDataSourceContextHolder.dataSourceIds.add(key);
    }
 
    // 創(chuàng)建DynamicDataSource
    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(DynamicDataSource.class);
    beanDefinition.setSynthetic(true);
    MutablePropertyValues mpv = beanDefinition.getPropertyValues();
    mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
    mpv.addPropertyValue("targetDataSources", targetDataSources);
    registry.registerBeanDefinition("dataSource", beanDefinition);
 
    logger.info("Dynamic DataSource Registry");
  }
 
  /**
   * 創(chuàng)建DataSource
   *
   * @param type
   * @param driverClassName
   * @param url
   * @param username
   * @param password
   * @return
   * @author SHANHY
   * @create 2016年1月24日
   */
  @SuppressWarnings("unchecked")
  public DataSource buildDataSource(Map<String, Object> dsMap) {
    try {
      Object type = dsMap.get("type");
      if (type == null)
        type = DATASOURCE_TYPE_DEFAULT;// 默認(rèn)DataSource
 
      Class<? extends DataSource> dataSourceType;
      dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
 
      String driverClassName = dsMap.get("driver-class-name").toString();
      String url = dsMap.get("url").toString();
      String username = dsMap.get("username").toString();
      String password = dsMap.get("password").toString();
 
      DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
          .username(username).password(password).type(dataSourceType);
      return factory.build();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
    return null;
  }
 
  /**
   * 加載多數(shù)據(jù)源配置
   */
  @Override
  public void setEnvironment(Environment env) {
    initDefaultDataSource(env);
    initCustomDataSources(env);
  }
 
  /**
   * 初始化主數(shù)據(jù)源
   *
   * @author SHANHY
   * @create 2016年1月24日
   */
  private void initDefaultDataSource(Environment env) {
    // 讀取主數(shù)據(jù)源
    RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
    Map<String, Object> dsMap = new HashMap<>();
    dsMap.put("type", propertyResolver.getProperty("type"));
    dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
    dsMap.put("url", propertyResolver.getProperty("url"));
    dsMap.put("username", propertyResolver.getProperty("username"));
    dsMap.put("password", propertyResolver.getProperty("password"));
 
    defaultDataSource = buildDataSource(dsMap);
 
    dataBinder(defaultDataSource, env);
  }
 
  /**
   * 為DataSource綁定更多數(shù)據(jù)
   *
   * @param dataSource
   * @param env
   * @author SHANHY
   * @create 2016年1月25日
   */
  private void dataBinder(DataSource dataSource, Environment env){
    RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
    //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
    dataBinder.setConversionService(conversionService);
    dataBinder.setIgnoreNestedProperties(false);//false
    dataBinder.setIgnoreInvalidFields(false);//false
    dataBinder.setIgnoreUnknownFields(true);//true
    if(dataSourcePropertyValues == null){
      Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
      Map<String, Object> values = new HashMap<>(rpr);
      // 排除已經(jīng)設(shè)置的屬性
      values.remove("type");
      values.remove("driver-class-name");
      values.remove("url");
      values.remove("username");
      values.remove("password");
      dataSourcePropertyValues = new MutablePropertyValues(values);
    }
    dataBinder.bind(dataSourcePropertyValues);
  }
 
  /**
   * 初始化更多數(shù)據(jù)源
   *
   * @author SHANHY
   * @create 2016年1月24日
   */
  private void initCustomDataSources(Environment env) {
    // 讀取配置文件獲取更多數(shù)據(jù)源,也可以通過(guò)defaultDataSource讀取數(shù)據(jù)庫(kù)獲取更多數(shù)據(jù)源
    RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");
    String dsPrefixs = propertyResolver.getProperty("names");
    for (String dsPrefix : dsPrefixs.split(",")) {// 多個(gè)數(shù)據(jù)源
      Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
      DataSource ds = buildDataSource(dsMap);
      customDataSources.put(dsPrefix, ds);
      dataBinder(ds, env);
    }
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.springboot.sample.datasource;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * 在方法上使用,用于指定使用哪個(gè)數(shù)據(jù)源
 *
 * @author  單紅宇(365384722)
 * @create  2016年1月23日
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
  String name();
}

本文代碼博主是經(jīng)過(guò)測(cè)試后沒(méi)有問(wèn)題才發(fā)出來(lái)共享給大家的。對(duì)于連接池參數(shù)配置會(huì)應(yīng)用到所有數(shù)據(jù)源上。
比如配置一個(gè):

?
1
spring.datasource.maximum-pool-size=80

那么我們所有的數(shù)據(jù)源都會(huì)自動(dòng)應(yīng)用上。

補(bǔ)充:

如果你使用的是SpringMVC,并集成了Shiro,一般按網(wǎng)上的配置你可能是:

?
1
2
3
4
5
6
7
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
   <property name="proxyTargetClass" value="true" />
 </bean>
 
 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
   <property name="securityManager" ref="securityManager"/>
 </bean>

那么你請(qǐng)不要這樣做,請(qǐng)按下面方法配置:

?
1
2
3
4
5
6
7
8
<!-- AOP式方法級(jí)權(quán)限檢查 -->
 <!-- 不要使用 DefaultAdvisorAutoProxyCreator 會(huì)出現(xiàn)二次代理的問(wèn)題,這里不詳述。 mark by shanhy 2016-05-15 -->
 <aop:config proxy-target-class="true"/>
 <!-- 或者你使用了 <aop:aspectj-autoproxy proxy-target-class="true" /> 也可以。 -->
 
 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
   <property name="securityManager" ref="securityManager"/>
 </bean>

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://blog.csdn.net/catoop/article/details/50575038

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩国产 | 成人久久久久久久久 | 午夜网址| 一区日韩| 日本特黄特色aaa大片免费 | 99精品免费视频 | 中文字幕av第一页 | 视频一区二区三 | 色图综合| 色婷婷精品国产一区二区三区 | 台湾黄色网 | 久久成人国产精品 | 亚洲一区二区三区久久久 | 久久久在线 | 国产一区二区三区视频 | 狼人综干网 | 中文视频在线 | 自拍视频网| 国内精品一区二区 | 一区二区不卡视频 | 日本精品久久 | 中国freesex| 久久久久99| 欧美日韩一区二区三区在线观看 | 精品国产欧美一区二区三区成人 | 中文在线视频 | 中文av一区二区 | 黄色小视频在线免费观看 | 欧美日韩一区二区三区 | 美女在线视频一区二区 | 国产99精品视频 | 91看视频| 美女视频一区二区三区 | 欧美日本韩国一区二区三区 | 久久精品2019中文字幕 | 午夜影院免费 | 在线亚洲不卡 | 亚洲精品久久久久久动漫 | 在线中文 | 日本福利片 | 亚洲a在线播放 |