Add unit tests for dynamic-datasource-spring-boot-starter
(#555)
This commit is contained in:
parent
18b5312b68
commit
6ba32b2505
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
|||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- name: Build test with Maven
|
- name: Build test with Maven
|
||||||
run: |
|
run: |
|
||||||
./mvnw -am -pl dynamic-datasource-spring-boot3-starter -T1C -B clean test
|
./mvnw -T1C -B clean test
|
||||||
test-minimum-jdk-ci:
|
test-minimum-jdk-ci:
|
||||||
name: Test CI - JDK ${{ matrix.java-version }} on ${{ matrix.os }}
|
name: Test CI - JDK ${{ matrix.java-version }} on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@ -64,4 +64,4 @@ jobs:
|
|||||||
./mvnw -am -pl dynamic-datasource-creator -T1C -B clean package
|
./mvnw -am -pl dynamic-datasource-creator -T1C -B clean package
|
||||||
./mvnw -am -pl dynamic-datasource-spring -T1C -B clean package
|
./mvnw -am -pl dynamic-datasource-spring -T1C -B clean package
|
||||||
./mvnw -am -pl dynamic-datasource-spring-boot-common -T1C -B clean package
|
./mvnw -am -pl dynamic-datasource-spring-boot-common -T1C -B clean package
|
||||||
./mvnw -am -pl dynamic-datasource-spring-boot-starter -T1C -B clean package
|
./mvnw -am -pl dynamic-datasource-spring-boot-starter -T1C -B clean test
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
<version>1.2.18</version>
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -35,6 +34,15 @@
|
|||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.hikaricp.HikariCpConfig;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = AddRemoveDatasourceApplication.class, webEnvironment = RANDOM_PORT)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class AddRemoveDatasourceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataSource dataSource;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DefaultDataSourceCreator dataSourceCreator;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAndRemoveDataSource() {
|
||||||
|
HikariCpConfig hikariCpConfig = new HikariCpConfig();
|
||||||
|
hikariCpConfig.setConnectionTestQuery("select 1");
|
||||||
|
DataSourceProperty dataSourceProperty = new DataSourceProperty();
|
||||||
|
dataSourceProperty.setHikari(hikariCpConfig);
|
||||||
|
dataSourceProperty.setPoolName("slave_1");
|
||||||
|
dataSourceProperty.setUsername("sa");
|
||||||
|
dataSourceProperty.setPassword("");
|
||||||
|
dataSourceProperty.setType(SimpleDriverDataSource.class);
|
||||||
|
dataSourceProperty.setUrl("jdbc:h2:mem:test1;MODE=MySQL");
|
||||||
|
dataSourceProperty.setDriverClassName("org.h2.Driver");
|
||||||
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
|
ds.addDataSource(dataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(dataSourceProperty));
|
||||||
|
assertThat(ds.getDataSources().keySet()).contains("slave_1");
|
||||||
|
ds.removeDataSource("slave_1");
|
||||||
|
assertThat(ds.getDataSources().keySet()).doesNotContain("slave_1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
class AddRemoveDatasourceApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(AddRemoveDatasourceApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
||||||
|
import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
|
||||||
|
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = LoadDatasourceFromJDBCApplication.class, webEnvironment = RANDOM_PORT)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class LoadDatasourceFromJDBCTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataSource dataSource;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistDataSource() {
|
||||||
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
|
assertThat(ds.getDataSources().keySet()).contains("master", "db1", "db2", "db3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
|
||||||
|
@SpringBootApplication
|
||||||
|
class LoadDatasourceFromJDBCApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(LoadDatasourceFromJDBCApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DynamicDataSourceProvider dynamicDataSourceProvider(DefaultDataSourceCreator dataSourceCreator) {
|
||||||
|
return new AbstractJdbcDataSourceProvider(dataSourceCreator, "org.h2.Driver", "jdbc:h2:mem:test;MODE=MySQL", "sa", "") {
|
||||||
|
@Override
|
||||||
|
protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
|
||||||
|
statement.execute("CREATE TABLE IF NOT EXISTS `DB`\n" +
|
||||||
|
"(\n" +
|
||||||
|
" `name` VARCHAR(30) NULL DEFAULT NULL,\n" +
|
||||||
|
" `username` VARCHAR(30) NULL DEFAULT NULL,\n" +
|
||||||
|
" `password` VARCHAR(30) NULL DEFAULT NULL,\n" +
|
||||||
|
" `url` VARCHAR(30) NULL DEFAULT NULL,\n" +
|
||||||
|
" `driver` VARCHAR(30) NULL DEFAULT NULL\n" +
|
||||||
|
")");
|
||||||
|
statement.executeUpdate("insert into DB values ('master','sa','','jdbc:h2:mem:test;MODE=MySQL','org.h2.Driver')");
|
||||||
|
statement.executeUpdate("insert into DB values ('db1','sa','','jdbc:h2:mem:test2','org.h2.Driver')");
|
||||||
|
statement.executeUpdate("insert into DB values ('db2','sa','','jdbc:h2:mem:test3','org.h2.Driver')");
|
||||||
|
statement.executeUpdate("insert into DB values ('db3','sa','','jdbc:h2:mem:test4','org.h2.Driver')");
|
||||||
|
Map<String, DataSourceProperty> map = new HashMap<>();
|
||||||
|
ResultSet rs = statement.executeQuery("select * from DB");
|
||||||
|
while (rs.next()) {
|
||||||
|
DataSourceProperty dataSourceProperty = new DataSourceProperty();
|
||||||
|
dataSourceProperty.setUsername(rs.getString("username"));
|
||||||
|
dataSourceProperty.setPassword(rs.getString("password"));
|
||||||
|
dataSourceProperty.setUrl(rs.getString("url"));
|
||||||
|
dataSourceProperty.setDriverClassName(rs.getString("driver"));
|
||||||
|
dataSourceProperty.setType(SimpleDriverDataSource.class);
|
||||||
|
map.put(rs.getString("name"), dataSourceProperty);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.SchoolService;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.Student;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.StudentService;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.Teacher;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.TeacherService;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = NestApplication.class, webEnvironment = RANDOM_PORT)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class NestDataSourceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataSource dataSource;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DefaultDataSourceCreator dataSourceCreator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TeacherService teacherService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
StudentService studentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SchoolService schoolService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNest() {
|
||||||
|
DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master");
|
||||||
|
DataSourceProperty teacherDataSourceProperty = createDataSourceProperty("teacher");
|
||||||
|
DataSourceProperty studentDataSourceProperty = createDataSourceProperty("student");
|
||||||
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
|
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
||||||
|
ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty));
|
||||||
|
ds.addDataSource(studentDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(studentDataSourceProperty));
|
||||||
|
assertThat(ds.getDataSources().keySet()).contains("master", "teacher", "student");
|
||||||
|
assertThat(teacherService.addTeacherWithTx("ss", 1)).isEqualTo(1);
|
||||||
|
assertThat(studentService.addStudentWithTx("tt", 2)).isEqualTo(1);
|
||||||
|
assertThat(teacherService.selectTeachers()).isEqualTo(Collections.singletonList(new Teacher(1, "tt", 2)));
|
||||||
|
assertThat(studentService.selectStudents()).isEqualTo(Collections.singletonList(new Student(1, "tt", 2)));
|
||||||
|
assertThat(schoolService.addTeacherAndStudentWithTx()).isEqualTo(2);
|
||||||
|
assertThat(teacherService.selectTeachers()).isEqualTo(Arrays.asList(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4)));
|
||||||
|
assertThat(studentService.selectStudents()).isEqualTo(Arrays.asList(new Student(1, "tt", 2), new Student(2, "bb", 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSourceProperty createDataSourceProperty(String poolName) {
|
||||||
|
DataSourceProperty result = new DataSourceProperty();
|
||||||
|
result.setPoolName(poolName);
|
||||||
|
result.setDriverClassName("org.h2.Driver");
|
||||||
|
result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'");
|
||||||
|
result.setUsername("sa");
|
||||||
|
result.setPassword("");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
class NestApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(NestApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
||||||
|
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.spel.CustomResultHandler;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.spel.User;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.spel.UserService;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = SPELApplication.class, webEnvironment = RANDOM_PORT)
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class SPELTest {
|
||||||
|
|
||||||
|
MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebApplicationContext webApplicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataSource dataSource;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DefaultDataSourceCreator dataSourceCreator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UserService userService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.mockMvc = webAppContextSetup(webApplicationContext)
|
||||||
|
.alwaysDo(new CustomResultHandler())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSPEL() throws Exception {
|
||||||
|
DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master");
|
||||||
|
DataSourceProperty tenant1_1DataSourceProperty = createDataSourceProperty("tenant1_1");
|
||||||
|
DataSourceProperty tenant1_2DataSourceProperty = createDataSourceProperty("tenant1_2");
|
||||||
|
DataSourceProperty tenant2_1DataSourceProperty = createDataSourceProperty("tenant2_1");
|
||||||
|
DataSourceProperty tenant2_2DataSourceProperty = createDataSourceProperty("tenant2_2");
|
||||||
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
|
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
||||||
|
ds.addDataSource(tenant1_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_1DataSourceProperty));
|
||||||
|
ds.addDataSource(tenant1_2DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_2DataSourceProperty));
|
||||||
|
ds.addDataSource(tenant2_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant2_1DataSourceProperty));
|
||||||
|
ds.addDataSource(tenant2_2DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant2_2DataSourceProperty));
|
||||||
|
assertThat(ds.getDataSources().keySet()).contains("master", "tenant1_1", "tenant1_2", "tenant2_1", "tenant2_2");
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders.get("/users/session").characterEncoding(StandardCharsets.UTF_8.name()))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().encoding(StandardCharsets.UTF_8.name()))
|
||||||
|
.andReturn().getResponse().getContentAsString();
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders.get("/users/header").contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
|
.header("tenantName", "tenant1")
|
||||||
|
.characterEncoding(StandardCharsets.UTF_8.name())
|
||||||
|
).andDo(print())
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().encoding(StandardCharsets.UTF_8.name()))
|
||||||
|
.andReturn().getResponse().getContentAsString();
|
||||||
|
assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1");
|
||||||
|
assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2");
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSourceProperty createDataSourceProperty(String poolName) {
|
||||||
|
DataSourceProperty result = new DataSourceProperty();
|
||||||
|
result.setPoolName(poolName);
|
||||||
|
result.setDriverClassName("org.h2.Driver");
|
||||||
|
result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
||||||
|
result.setUsername("sa");
|
||||||
|
result.setPassword("");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
class SPELApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SPELApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.controller;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.spel.User;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.spel.UserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequestMapping("/users")
|
||||||
|
@RestController
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@GetMapping("/session")
|
||||||
|
public List<User> session(HttpServletRequest request) {
|
||||||
|
request.getSession().setAttribute("tenantName", "tenant1");
|
||||||
|
return userService.selectSpelBySession();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/header")
|
||||||
|
public String header() {
|
||||||
|
userService.selectSpelByHeader();
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.nest;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SchoolService {
|
||||||
|
private final TeacherService teacherService;
|
||||||
|
private final StudentService studentService;
|
||||||
|
|
||||||
|
public SchoolService(TeacherService teacherService, StudentService studentService) {
|
||||||
|
this.teacherService = teacherService;
|
||||||
|
this.studentService = studentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public int addTeacherAndStudentWithTx() {
|
||||||
|
int aa = teacherService.addTeacherNoTx("aa", 3);
|
||||||
|
int bb = studentService.addStudentNoTx("bb", 4);
|
||||||
|
return aa + bb;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.nest;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Student {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
private Integer age;
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.nest;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
|
||||||
|
@Service
|
||||||
|
@DS("student")
|
||||||
|
public class StudentService {
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
|
public StudentService(DataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public int addStudentWithTx(String name, Integer age) {
|
||||||
|
try (Connection connection = dataSource.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("insert into student (name,age) values (?,?)")) {
|
||||||
|
preparedStatement.setString(1, name);
|
||||||
|
preparedStatement.setInt(2, age);
|
||||||
|
return preparedStatement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addStudentNoTx(String name, Integer age) {
|
||||||
|
try (Connection connection = dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("insert into student (name,age) values (?,?)")) {
|
||||||
|
preparedStatement.setString(1, name);
|
||||||
|
preparedStatement.setInt(2, age);
|
||||||
|
return preparedStatement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Student> selectStudents() {
|
||||||
|
List<Student> result = new LinkedList<>();
|
||||||
|
try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) {
|
||||||
|
ResultSet resultSet = statement.executeQuery("SELECT * FROM student");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
result.add(new Student(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.nest;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Teacher {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Integer age;
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.nest;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings({"SqlNoDataSourceInspection", "SqlDialectInspection"})
|
||||||
|
@Service
|
||||||
|
@DS("teacher")
|
||||||
|
public class TeacherService {
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
|
public TeacherService(DataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public int addTeacherWithTx(String name, Integer age) {
|
||||||
|
try (Connection connection = dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name,age) values (?,?)")) {
|
||||||
|
preparedStatement.setString(1, name);
|
||||||
|
preparedStatement.setInt(2, age);
|
||||||
|
return preparedStatement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int addTeacherNoTx(String name, Integer age) {
|
||||||
|
try (Connection connection = dataSource.getConnection();
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name,age) values (?,?)")) {
|
||||||
|
preparedStatement.setString(1, name);
|
||||||
|
preparedStatement.setInt(2, age);
|
||||||
|
return preparedStatement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Teacher> selectTeachers() {
|
||||||
|
List<Teacher> result = new LinkedList<>();
|
||||||
|
try (Connection connection = dataSource.getConnection();
|
||||||
|
Statement statement = connection.createStatement()) {
|
||||||
|
ResultSet resultSet = statement.executeQuery("SELECT * FROM student");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
result.add(new Teacher(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baomidou.dynamic.datasource.fixture.service.spel;
|
||||||
|
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import org.springframework.test.web.servlet.ResultHandler;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class CustomResultHandler implements ResultHandler {
|
||||||
|
@Override
|
||||||
|
public void handle(MvcResult result) {
|
||||||
|
result.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.spel;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
private String tenantName;
|
||||||
|
|
||||||
|
public User(String tenantName) {
|
||||||
|
this.id = null;
|
||||||
|
this.name = null;
|
||||||
|
this.age = null;
|
||||||
|
this.tenantName = tenantName;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 organization baomidou
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.baomidou.dynamic.datasource.fixture.service.spel;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||||
|
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection", "UnusedReturnValue", "unused"})
|
||||||
|
@Service
|
||||||
|
@DS("slave")
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
|
public UserService(DataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@DS("#session.tenantName")
|
||||||
|
public List<User> selectSpelBySession() {
|
||||||
|
List<User> result = new LinkedList<>();
|
||||||
|
try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) {
|
||||||
|
ResultSet resultSet = statement.executeQuery("select * from t_user");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
result.add(new User(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getString(4)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DS("#header.tenantName")
|
||||||
|
public List<User> selectSpelByHeader() {
|
||||||
|
List<User> result = new LinkedList<>();
|
||||||
|
try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) {
|
||||||
|
ResultSet resultSet = statement.executeQuery("select * from t_user");
|
||||||
|
while (resultSet.next()) {
|
||||||
|
result.add(new User(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getString(4)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DS("#tenantName")
|
||||||
|
public String selectSpelByKey(String tenantName) {
|
||||||
|
return DynamicDataSourceContextHolder.peek();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@DS("#user.tenantName")
|
||||||
|
public String selecSpelByTenant(User user) {
|
||||||
|
return DynamicDataSourceContextHolder.peek();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS TEACHER
|
||||||
|
(
|
||||||
|
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(30) NULL DEFAULT NULL,
|
||||||
|
age INT(11) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS STUDENT
|
||||||
|
(
|
||||||
|
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(30) NULL DEFAULT NULL,
|
||||||
|
age INT(11) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS t_user
|
||||||
|
(
|
||||||
|
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(30) NULL DEFAULT NULL,
|
||||||
|
age INT(11) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
@ -33,7 +33,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||||
<version>1.2.18</version>
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -44,7 +43,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>${h2.version}</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -18,17 +18,18 @@ package com.baomidou.dynamic.datasource.fixture;
|
|||||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
|
||||||
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
|
||||||
import com.baomidou.dynamic.datasource.fixture.service.nest.*;
|
import com.baomidou.dynamic.datasource.fixture.service.nest.SchoolService;
|
||||||
import org.h2.tools.Server;
|
import com.baomidou.dynamic.datasource.fixture.service.nest.Student;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.StudentService;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.Teacher;
|
||||||
|
import com.baomidou.dynamic.datasource.fixture.service.nest.TeacherService;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -54,24 +55,9 @@ public class NestDataSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNest() {
|
void testNest() {
|
||||||
DataSourceProperty masterDataSourceProperty = new DataSourceProperty();
|
DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master");
|
||||||
masterDataSourceProperty.setPoolName("master");
|
DataSourceProperty teacherDataSourceProperty = createDataSourceProperty("teacher");
|
||||||
masterDataSourceProperty.setDriverClassName("org.h2.Driver");
|
DataSourceProperty studentDataSourceProperty = createDataSourceProperty("student");
|
||||||
masterDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'");
|
|
||||||
masterDataSourceProperty.setUsername("sa");
|
|
||||||
masterDataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty teacherDataSourceProperty = new DataSourceProperty();
|
|
||||||
teacherDataSourceProperty.setPoolName("teacher");
|
|
||||||
teacherDataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
teacherDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'");
|
|
||||||
teacherDataSourceProperty.setUsername("sa");
|
|
||||||
teacherDataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty studentDataSourceProperty = new DataSourceProperty();
|
|
||||||
studentDataSourceProperty.setPoolName("student");
|
|
||||||
studentDataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
studentDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'");
|
|
||||||
studentDataSourceProperty.setUsername("sa");
|
|
||||||
studentDataSourceProperty.setPassword("");
|
|
||||||
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
||||||
ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty));
|
ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty));
|
||||||
@ -85,6 +71,16 @@ public class NestDataSourceTest {
|
|||||||
assertThat(teacherService.selectTeachers()).isEqualTo(List.of(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4)));
|
assertThat(teacherService.selectTeachers()).isEqualTo(List.of(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4)));
|
||||||
assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2), new Student(2, "bb", 4)));
|
assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2), new Student(2, "bb", 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataSourceProperty createDataSourceProperty(String poolName) {
|
||||||
|
DataSourceProperty result = new DataSourceProperty();
|
||||||
|
result.setPoolName(poolName);
|
||||||
|
result.setDriverClassName("org.h2.Driver");
|
||||||
|
result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'");
|
||||||
|
result.setUsername("sa");
|
||||||
|
result.setPassword("");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@ -63,36 +63,11 @@ public class SPELTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSPEL() {
|
void testSPEL() {
|
||||||
DataSourceProperty masterDataSourceProperty = new DataSourceProperty();
|
DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master");
|
||||||
masterDataSourceProperty.setPoolName("master");
|
DataSourceProperty tenant1_1DataSourceProperty = createDataSourceProperty("tenant1_1");
|
||||||
masterDataSourceProperty.setDriverClassName("org.h2.Driver");
|
DataSourceProperty tenant1_2DataSourceProperty = createDataSourceProperty("tenant1_2");
|
||||||
masterDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
DataSourceProperty tenant2_1DataSourceProperty = createDataSourceProperty("tenant2_1");
|
||||||
masterDataSourceProperty.setUsername("sa");
|
DataSourceProperty tenant2_2DataSourceProperty = createDataSourceProperty("tenant2_2");
|
||||||
masterDataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty tenant1_1DataSourceProperty = new DataSourceProperty();
|
|
||||||
tenant1_1DataSourceProperty.setPoolName("tenant1_1");
|
|
||||||
tenant1_1DataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
tenant1_1DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
|
||||||
tenant1_1DataSourceProperty.setUsername("sa");
|
|
||||||
tenant1_1DataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty tenant1_2DataSourceProperty = new DataSourceProperty();
|
|
||||||
tenant1_2DataSourceProperty.setPoolName("tenant1_2");
|
|
||||||
tenant1_2DataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
tenant1_2DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
|
||||||
tenant1_2DataSourceProperty.setUsername("sa");
|
|
||||||
tenant1_2DataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty tenant2_1DataSourceProperty = new DataSourceProperty();
|
|
||||||
tenant2_1DataSourceProperty.setPoolName("tenant2_1");
|
|
||||||
tenant2_1DataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
tenant2_1DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
|
||||||
tenant2_1DataSourceProperty.setUsername("sa");
|
|
||||||
tenant2_1DataSourceProperty.setPassword("");
|
|
||||||
DataSourceProperty tenant2_2DataSourceProperty = new DataSourceProperty();
|
|
||||||
tenant2_2DataSourceProperty.setPoolName("tenant2_2");
|
|
||||||
tenant2_2DataSourceProperty.setDriverClassName("org.h2.Driver");
|
|
||||||
tenant2_2DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE");
|
|
||||||
tenant2_2DataSourceProperty.setUsername("sa");
|
|
||||||
tenant2_2DataSourceProperty.setPassword("");
|
|
||||||
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
|
||||||
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty));
|
||||||
ds.addDataSource(tenant1_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_1DataSourceProperty));
|
ds.addDataSource(tenant1_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_1DataSourceProperty));
|
||||||
@ -117,6 +92,16 @@ public class SPELTest {
|
|||||||
assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1");
|
assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1");
|
||||||
assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2");
|
assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataSourceProperty createDataSourceProperty(String poolName) {
|
||||||
|
DataSourceProperty result = new DataSourceProperty();
|
||||||
|
result.setPoolName(poolName);
|
||||||
|
result.setDriverClassName("org.h2.Driver");
|
||||||
|
result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'");
|
||||||
|
result.setUsername("sa");
|
||||||
|
result.setPassword("");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@ -18,7 +18,6 @@ package com.baomidou.dynamic.datasource.fixture.controller;
|
|||||||
import com.baomidou.dynamic.datasource.fixture.service.spel.User;
|
import com.baomidou.dynamic.datasource.fixture.service.spel.User;
|
||||||
import com.baomidou.dynamic.datasource.fixture.service.spel.UserService;
|
import com.baomidou.dynamic.datasource.fixture.service.spel.UserService;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@ -29,8 +28,11 @@ import java.util.List;
|
|||||||
@RestController
|
@RestController
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
@Autowired
|
private final UserService userService;
|
||||||
private UserService userService;
|
|
||||||
|
public UserController(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/session")
|
@GetMapping("/session")
|
||||||
public List<User> session(HttpServletRequest request) {
|
public List<User> session(HttpServletRequest request) {
|
||||||
|
@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SchoolService {
|
public class SchoolService {
|
||||||
|
|
||||||
private final TeacherService teacherService;
|
private final TeacherService teacherService;
|
||||||
private final StudentService studentService;
|
private final StudentService studentService;
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
@DS("student")
|
@DS("student")
|
||||||
public class StudentService {
|
public class StudentService {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
|
||||||
public StudentService(DataSource dataSource) {
|
public StudentService(DataSource dataSource) {
|
||||||
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
@DS("teacher")
|
@DS("teacher")
|
||||||
public class TeacherService {
|
public class TeacherService {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
|
||||||
public TeacherService(DataSource dataSource) {
|
public TeacherService(DataSource dataSource) {
|
||||||
|
28
pom.xml
28
pom.xml
@ -119,6 +119,16 @@
|
|||||||
<artifactId>druid</artifactId>
|
<artifactId>druid</artifactId>
|
||||||
<version>${druid.version}</version>
|
<version>${druid.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>${druid.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||||
|
<version>${druid.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
|
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
|
||||||
@ -261,6 +271,24 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>jdk11+</id>
|
||||||
|
<activation>
|
||||||
|
<jdk>[11,)</jdk>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<argLine>--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
<id>release</id>
|
<id>release</id>
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user