diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aee73cfa8..1f29ee133 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Project versions -nativeBuildTools = "0.9.16" +nativeBuildTools = "0.9.18" # External dependencies junitPlatform = "1.8.1" diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/index.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/index.json new file mode 100644 index 000000000..9512e972d --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/index.json @@ -0,0 +1,7 @@ +[ + "jni-config.json", + "proxy-config.json", + "reflect-config.json", + "resource-config.json", + "serialization-config.json" +] diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/jni-config.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/jni-config.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/jni-config.json @@ -0,0 +1 @@ +[] diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/proxy-config.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/proxy-config.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/proxy-config.json @@ -0,0 +1 @@ +[] diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/reflect-config.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/reflect-config.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/reflect-config.json @@ -0,0 +1 @@ +[] diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/resource-config.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/resource-config.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/resource-config.json @@ -0,0 +1 @@ +{} diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/serialization-config.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/serialization-config.json new file mode 100644 index 000000000..5b382b874 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/serialization-config.json @@ -0,0 +1,4 @@ +{ + "lambdaCapturingTypes": [], + "types": [] +} diff --git a/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/index.json b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/index.json new file mode 100644 index 000000000..bc15bda68 --- /dev/null +++ b/metadata/com.baomidou/dynamic-datasource-spring-boot-starter/index.json @@ -0,0 +1,10 @@ +[ + { + "latest": true, + "metadata-version": "3.6.1", + "module": "com.baomidou:dynamic-datasource-spring-boot-starter", + "tested-versions": [ + "3.6.1" + ] + } +] diff --git a/metadata/index.json b/metadata/index.json index 742cfa29f..333d87b7e 100644 --- a/metadata/index.json +++ b/metadata/index.json @@ -201,5 +201,9 @@ { "directory": "org.eclipse.jetty/jetty-client", "module": "org.eclipse.jetty:jetty-client" + }, + { + "directory": "com.baomidou/dynamic-datasource-spring-boot-starter", + "module": "com.baomidou:dynamic-datasource-spring-boot-starter" } ] diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/.gitignore b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/.gitignore new file mode 100644 index 000000000..c98c7875b --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/.gitignore @@ -0,0 +1,4 @@ +gradlew.bat +gradlew +gradle/ +build/ diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/build.gradle b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/build.gradle new file mode 100644 index 000000000..2607d6ef7 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/build.gradle @@ -0,0 +1,40 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ + +plugins { + id "org.graalvm.internal.tck" + id 'org.springframework.boot' version '3.0.0' +} + +String libraryVersion = tck.testedLibraryVersion.get() + +dependencies { + testImplementation "com.baomidou:dynamic-datasource-spring-boot-starter:$libraryVersion" + testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + testImplementation 'org.springframework.boot:spring-boot-starter-web' + testRuntimeOnly 'com.h2database:h2:2.1.214' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +group 'com_baomidou.dynamic_datasource_spring_boot_starter' + +graalvmNative { + agent { + defaultMode = "conditional" + modes { + conditional { + userCodeFilterPath = "user-code-filter.json" + } + } + metadataCopy { + mergeWithExisting = true + inputTaskNames.add("test") + outputDirectories.add("src/test/resources/META-INF/native-image/com.baomidou/dynamic-datasource-spring-boot-starter") + } + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/gradle.properties b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/gradle.properties new file mode 100644 index 000000000..8403743d9 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/gradle.properties @@ -0,0 +1,2 @@ +library.version = 3.6.1 +metadata.dir = com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/ diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/settings.gradle b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/settings.gradle new file mode 100644 index 000000000..cf6b65fd7 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/settings.gradle @@ -0,0 +1,13 @@ +pluginManagement { + def tckPath = Objects.requireNonNullElse( + System.getenv("GVM_TCK_TCKDIR"), + "../../../../tck-build-logic" + ) + includeBuild(tckPath) +} + +plugins { + id "org.graalvm.internal.tck-settings" version "1.0.0-SNAPSHOT" +} + +rootProject.name = 'com.baomidou.dynamic-datasource-spring-boot-starter_tests' diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/AddRemoveDatasourceTest.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/AddRemoveDatasourceTest.java new file mode 100644 index 000000000..51db7ce15 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/AddRemoveDatasourceTest.java @@ -0,0 +1,51 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.hikari.HikariCpConfig; +import org.junit.jupiter.api.Test; +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 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) +public class AddRemoveDatasourceTest { + @Autowired + DataSource dataSource; + @Autowired + DefaultDataSourceCreator dataSourceCreator; + + @Test + void testAddAndRemoveDataSource() { + HikariCpConfig hikariCpConfig = new HikariCpConfig(); + hikariCpConfig.setConnectionTestQuery("select 1"); + DataSourceProperty dataSourceProperty = new DataSourceProperty() + .setPoolName("slave_1").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test1;MODE=MySQL") + .setUsername("sa").setPassword("").setHikari(hikariCpConfig); + 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); + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/LoadDatasourceFromJDBCTest.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/LoadDatasourceFromJDBCTest.java new file mode 100644 index 000000000..77ec85a9d --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/LoadDatasourceFromJDBCTest.java @@ -0,0 +1,79 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import org.junit.jupiter.api.Test; +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 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) +public class LoadDatasourceFromJDBCTest { + @Autowired + DataSource dataSource; + + @Test + 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() { + return new AbstractJdbcDataSourceProvider("org.h2.Driver", "jdbc:h2:mem:test;MODE=MySQL", "sa", "") { + @Override + protected Map executeStmt(Statement statement) throws SQLException { + statement.execute(""" + CREATE TABLE IF NOT EXISTS `DB` + ( + `name` VARCHAR(30) NULL DEFAULT NULL, + `username` VARCHAR(30) NULL DEFAULT NULL, + `password` VARCHAR(30) NULL DEFAULT NULL, + `url` VARCHAR(30) NULL DEFAULT NULL, + `driver` VARCHAR(30) NULL DEFAULT NULL + )"""); + 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 map = new HashMap<>(); + ResultSet rs = statement.executeQuery("select * from DB"); + while (rs.next()) { + map.put(rs.getString("name"), new DataSourceProperty() + .setUsername(rs.getString("username")).setPassword(rs.getString("password")) + .setUrl(rs.getString("url")).setDriverClassName(rs.getString("driver"))); + } + return map; + } + }; + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/NestDataSourceTest.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/NestDataSourceTest.java new file mode 100644 index 000000000..9091aacbc --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/NestDataSourceTest.java @@ -0,0 +1,70 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import com_baomidou.dynamic_datasource_spring_boot_starter.service.nest.*; +import org.junit.jupiter.api.Test; +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 javax.sql.DataSource; +import java.util.List; + +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) +public class NestDataSourceTest { + @Autowired + DataSource dataSource; + @Autowired + DefaultDataSourceCreator dataSourceCreator; + @Autowired + private TeacherService teacherService; + @Autowired + private StudentService studentService; + @Autowired + private SchoolService schoolService; + + @Test + void testNest() { + DataSourceProperty masterDataSourceProperty = new DataSourceProperty() + .setPoolName("master").setDriverClassName("org.h2.Driver") + .setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'") + .setUsername("sa").setPassword(""); + DataSourceProperty teacherDataSourceProperty = new DataSourceProperty() + .setPoolName("teacher").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + DataSourceProperty studentDataSourceProperty = new DataSourceProperty() + .setPoolName("student").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + 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(List.of(new Teacher(1, "tt", 2))); + assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2))); + assertThat(schoolService.addTeacherAndStudentWithTx()).isEqualTo(2); + 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))); + } +} + +@SpringBootApplication +class NestApplication { + public static void main(String[] args) { + SpringApplication.run(NestApplication.class, args); + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/SPELTest.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/SPELTest.java new file mode 100644 index 000000000..f1812c456 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/SPELTest.java @@ -0,0 +1,102 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; +import com_baomidou.dynamic_datasource_spring_boot_starter.service.spel.User; +import com_baomidou.dynamic_datasource_spring_boot_starter.service.spel.UserService; +import jakarta.servlet.ServletException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +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.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.junit.jupiter.api.Assertions.assertThrows; +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) +public class SPELTest { + MockMvc mockMvc; + @Autowired + DataSource dataSource; + @Autowired + DefaultDataSourceCreator dataSourceCreator; + + @Autowired + UserService userService; + + @BeforeEach + void setup(WebApplicationContext webApplicationContext) { + this.mockMvc = webAppContextSetup(webApplicationContext).defaultResponseCharacterEncoding(StandardCharsets.UTF_8).build(); + } + + @Test + void testSPEL() { + DataSourceProperty masterDataSourceProperty = new DataSourceProperty() + .setPoolName("master").setDriverClassName("org.h2.Driver") + .setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'") + .setUsername("sa").setPassword(""); + DataSourceProperty tenant1_1DataSourceProperty = new DataSourceProperty() + .setPoolName("tenant1_1").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + DataSourceProperty tenant1_2DataSourceProperty = new DataSourceProperty() + .setPoolName("tenant1_2").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + DataSourceProperty tenant2_1DataSourceProperty = new DataSourceProperty() + .setPoolName("tenant2_1").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + DataSourceProperty tenant2_2DataSourceProperty = new DataSourceProperty() + .setPoolName("tenant2_2").setDriverClassName("org.h2.Driver").setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE") + .setUsername("sa").setPassword(""); + 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"); + assertThrows(ServletException.class, () -> { + mockMvc.perform(MockMvcRequestBuilders.get("/users/session").characterEncoding(StandardCharsets.UTF_8)) + .andDo(print()).andExpectAll( + status().isOk(), + content().encoding(StandardCharsets.UTF_8) + ).andReturn().getResponse().getContentAsString(); + mockMvc.perform(MockMvcRequestBuilders.get("/users/header").contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("tenantName", "tenant1") + .characterEncoding(StandardCharsets.UTF_8) + ).andDo(print()).andExpectAll( + status().isOk(), + content().encoding(StandardCharsets.UTF_8) + ).andReturn().getResponse().getContentAsString(); + }); + assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1"); + assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2"); + } +} + +@SpringBootApplication +class SPELApplication { + public static void main(String[] args) { + SpringApplication.run(SPELApplication.class, args); + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/controller/UserController.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/controller/UserController.java new file mode 100644 index 000000000..e275047db --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/controller/UserController.java @@ -0,0 +1,37 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.controller; + +import com_baomidou.dynamic_datasource_spring_boot_starter.service.spel.User; +import com_baomidou.dynamic_datasource_spring_boot_starter.service.spel.UserService; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RequestMapping("/users") +@RestController +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping("/session") + public List session(HttpServletRequest request) { + request.getSession().setAttribute("tenantName", "tenant1"); + return userService.selectSpelBySession(); + } + + @GetMapping("/header") + public String header() { + userService.selectSpelByHeader(); + return "success"; + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/SchoolService.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/SchoolService.java new file mode 100644 index 000000000..c398d0c54 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/SchoolService.java @@ -0,0 +1,28 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.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; + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Student.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Student.java new file mode 100644 index 000000000..ed4cfbfed --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Student.java @@ -0,0 +1,10 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.service.nest; + +public record Student(Integer id, String name, Integer age) { +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/StudentService.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/StudentService.java new file mode 100644 index 000000000..2b7d10b37 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/StudentService.java @@ -0,0 +1,62 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.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.*; +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 selectStudents() { + List 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); + } + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Teacher.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Teacher.java new file mode 100644 index 000000000..65075e300 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/Teacher.java @@ -0,0 +1,10 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.service.nest; + +public record Teacher(Integer id, String name, Integer age) { +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/TeacherService.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/TeacherService.java new file mode 100644 index 000000000..dc4f2e92f --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/nest/TeacherService.java @@ -0,0 +1,65 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.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.*; +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 selectTeachers() { + List 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); + } + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/User.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/User.java new file mode 100644 index 000000000..e2392e450 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/User.java @@ -0,0 +1,13 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.service.spel; + +public record User(Integer id, String name, Integer age, String tenantName) { + public User(String tenantName) { + this(null, null, null, tenantName); + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/UserService.java b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/UserService.java new file mode 100644 index 000000000..a509c18a2 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/src/test/java/com_baomidou/dynamic_datasource_spring_boot_starter/service/spel/UserService.java @@ -0,0 +1,71 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package com_baomidou.dynamic_datasource_spring_boot_starter.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 selectSpelBySession() { + List 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 selectSpelByHeader() { + List 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(); + } +} diff --git a/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/user-code-filter.json b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/user-code-filter.json new file mode 100644 index 000000000..9d9a98678 --- /dev/null +++ b/tests/src/com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1/user-code-filter.json @@ -0,0 +1,6 @@ +{ + "rules": [ + {"excludeClasses": "**"}, + {"includeClasses": "com.baomidou.dynamic.datasource.**"} + ] +} diff --git a/tests/src/index.json b/tests/src/index.json index d4d2495d1..9da21c02f 100644 --- a/tests/src/index.json +++ b/tests/src/index.json @@ -548,5 +548,16 @@ ] } ] + }, + { + "test-project-path": "com.baomidou/dynamic-datasource-spring-boot-starter/3.6.1", + "libraries": [ + { + "name": "com.baomidou:dynamic-datasource-spring-boot-starter", + "versions": [ + "3.6.1" + ] + } + ] } ]