diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 135c8323866..4336804c5f4 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -38,6 +38,7 @@ body:
- MySQL
- Neo4j
- NGINX
+ - OceanBase CE
- Oracle Free
- Oracle XE
- OrientDB
diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml
index d77b4ce07a2..d98eba32b71 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.yaml
+++ b/.github/ISSUE_TEMPLATE/enhancement.yaml
@@ -38,6 +38,7 @@ body:
- MySQL
- Neo4j
- NGINX
+ - OceanBase CE
- Oracle Free
- Oracle XE
- OrientDB
diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml
index 65a27e5f99a..a00c8dcd3f3 100644
--- a/.github/ISSUE_TEMPLATE/feature.yaml
+++ b/.github/ISSUE_TEMPLATE/feature.yaml
@@ -38,6 +38,7 @@ body:
- MySQL
- Neo4j
- NGINX
+ - OceanBase CE
- Oracle Free
- Oracle XE
- OrientDB
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 3cb3e0fd222..d962092d345 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -194,6 +194,11 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
+ - package-ecosystem: "gradle"
+ directory: "/modules/oceanbase-ce"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/oracle-free"
schedule:
diff --git a/.github/labeler.yml b/.github/labeler.yml
index eec54b67829..a965c4bebbb 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -119,6 +119,10 @@
- changed-files:
- any-glob-to-any-file:
- modules/nginx/**/*
+"modules/oceanbase-ce":
+ - changed-files:
+ - any-glob-to-any-file:
+ - modules/oceanbase-ce/**/*
"modules/oracle":
- changed-files:
- any-glob-to-any-file:
diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md
index ab4baa75e22..e0535962310 100644
--- a/docs/modules/databases/jdbc.md
+++ b/docs/modules/databases/jdbc.md
@@ -55,6 +55,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database
`jdbc:tc:sqlserver:2017-CU12:///databasename`
+#### Using OceanBase
+
+`jdbc:tc:oceanbase:4.1.0.0:///databasename`
+
#### Using Oracle
`jdbc:tc:oracle:21-slim-faststart:///databasename`
diff --git a/docs/modules/databases/oceanbasece.md b/docs/modules/databases/oceanbasece.md
new file mode 100644
index 00000000000..87e84f9b5f5
--- /dev/null
+++ b/docs/modules/databases/oceanbasece.md
@@ -0,0 +1,25 @@
+# OceanBase-CE Module
+
+See [Database containers](./index.md) for documentation and usage that is common to all relational database container types.
+
+## Adding this module to your project dependencies
+
+Add the following dependency to your `pom.xml`/`build.gradle` file:
+
+=== "Gradle"
+ ```groovy
+ testImplementation "org.testcontainers:oceanbase-ce:{{latest_version}}"
+ ```
+
+=== "Maven"
+ ```xml
+
+ org.testcontainers
+ oceanbase-ce
+ {{latest_version}}
+ test
+
+ ```
+
+!!! hint
+Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency.
diff --git a/mkdocs.yml b/mkdocs.yml
index 43645183075..3067bf405f1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -64,6 +64,7 @@ nav:
- modules/databases/mssqlserver.md
- modules/databases/mysql.md
- modules/databases/neo4j.md
+ - modules/databases/oceanbasece.md
- modules/databases/oraclefree.md
- modules/databases/oraclexe.md
- modules/databases/orientdb.md
diff --git a/modules/oceanbase-ce/build.gradle b/modules/oceanbase-ce/build.gradle
new file mode 100644
index 00000000000..0e4f901fada
--- /dev/null
+++ b/modules/oceanbase-ce/build.gradle
@@ -0,0 +1,8 @@
+description = "Testcontainers :: JDBC :: OceanBase CE"
+
+dependencies {
+ api project(':jdbc')
+
+ testImplementation project(':jdbc-test')
+ testRuntimeOnly 'mysql:mysql-connector-java:8.0.33'
+}
diff --git a/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainer.java b/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainer.java
new file mode 100644
index 00000000000..12687f21c5c
--- /dev/null
+++ b/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainer.java
@@ -0,0 +1,139 @@
+package org.testcontainers.containers;
+
+import org.apache.commons.lang3.StringUtils;
+import org.testcontainers.utility.DockerImageName;
+
+/**
+ * Testcontainers implementation for OceanBase.
+ *
+ * Supported image: {@code oceanbase/oceanbase-ce}
+ *
+ * Exposed ports:
+ *
+ * - SQL: 2881
+ * - RPC: 2882
+ *
+ */
+public class OceanBaseContainer extends JdbcDatabaseContainer {
+
+ static final String NAME = "oceanbase";
+
+ static final String DOCKER_IMAGE_NAME = "oceanbase/oceanbase-ce";
+
+ private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse(DOCKER_IMAGE_NAME);
+
+ private static final Integer SQL_PORT = 2881;
+ private static final Integer RPC_PORT = 2882;
+
+ private static final String SYSTEM_TENANT_NAME = "sys";
+ private static final String DEFAULT_TEST_TENANT_NAME = "test";
+ private static final String DEFAULT_USERNAME = "root";
+ private static final String DEFAULT_PASSWORD = "";
+ private static final String DEFAULT_DATABASE_NAME = "test";
+
+ private boolean enableFastboot;
+ private String mode;
+ private String tenantName = DEFAULT_TEST_TENANT_NAME;
+
+ public OceanBaseContainer(String dockerImageName) {
+ this(DockerImageName.parse(dockerImageName));
+ }
+
+ public OceanBaseContainer(DockerImageName dockerImageName) {
+ super(dockerImageName);
+ dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
+
+ addExposedPorts(SQL_PORT, RPC_PORT);
+ }
+
+ @Override
+ public Integer getMappedPort(int originalPort) {
+ return "host".equals(getNetworkMode()) ? originalPort : super.getMappedPort(originalPort);
+ }
+
+ @Override
+ public String getDriverClassName() {
+ return "com.mysql.cj.jdbc.Driver";
+ }
+
+ @Override
+ public String getJdbcUrl() {
+ return getJdbcUrl(DEFAULT_DATABASE_NAME);
+ }
+
+ public String getJdbcUrl(String databaseName) {
+ String additionalUrlParams = constructUrlParameters("?", "&");
+ return "jdbc:mysql://" + getHost() + ":" + getMappedPort(SQL_PORT) + "/" + databaseName + additionalUrlParams;
+ }
+
+ @Override
+ public String getDatabaseName() {
+ return DEFAULT_DATABASE_NAME;
+ }
+
+ @Override
+ public String getUsername() {
+ return DEFAULT_USERNAME + "@" + tenantName;
+ }
+
+ @Override
+ public String getPassword() {
+ return DEFAULT_PASSWORD;
+ }
+
+ @Override
+ protected String getTestQueryString() {
+ return "SELECT 1";
+ }
+
+ /**
+ * Enable fastboot.
+ *
+ * @return this
+ */
+ public OceanBaseContainer enableFastboot() {
+ this.enableFastboot = true;
+ return self();
+ }
+
+ /**
+ * Set the deployment mode, see Docker Hub for more details.
+ *
+ * @param mode the deployment mode
+ * @return this
+ */
+ public OceanBaseContainer withMode(String mode) {
+ this.mode = mode;
+ return self();
+ }
+
+ /**
+ * Set the non-system tenant to be created for testing.
+ *
+ * @param tenantName the name of tenant to be created
+ * @return this
+ */
+ public OceanBaseContainer withTenant(String tenantName) {
+ if (StringUtils.isEmpty(tenantName)) {
+ throw new IllegalArgumentException("Tenant name cannot be null or empty");
+ }
+ if (SYSTEM_TENANT_NAME.equals(tenantName)) {
+ throw new IllegalArgumentException("Tenant name cannot be " + SYSTEM_TENANT_NAME);
+ }
+ this.tenantName = tenantName;
+ return self();
+ }
+
+ @Override
+ protected void configure() {
+ if (StringUtils.isNotBlank(mode)) {
+ withEnv("MODE", mode);
+ }
+ if (enableFastboot) {
+ withEnv("FASTBOOT", "true");
+ }
+ if (!DEFAULT_TEST_TENANT_NAME.equals(tenantName)) {
+ withEnv("OB_TENANT_NAME", tenantName);
+ }
+ }
+}
diff --git a/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainerProvider.java b/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainerProvider.java
new file mode 100644
index 00000000000..fd84a04d328
--- /dev/null
+++ b/modules/oceanbase-ce/src/main/java/org/testcontainers/containers/OceanBaseContainerProvider.java
@@ -0,0 +1,30 @@
+package org.testcontainers.containers;
+
+import org.testcontainers.utility.DockerImageName;
+
+/**
+ * Factory for OceanBase containers.
+ */
+public class OceanBaseContainerProvider extends JdbcDatabaseContainerProvider {
+
+ private static final String DEFAULT_TAG = "4.2.1_bp3";
+
+ @Override
+ public boolean supports(String databaseType) {
+ return databaseType.equals(OceanBaseContainer.NAME);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance() {
+ return newInstance(DEFAULT_TAG);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance(String tag) {
+ if (tag != null) {
+ return new OceanBaseContainer(DockerImageName.parse(OceanBaseContainer.DOCKER_IMAGE_NAME).withTag(tag));
+ } else {
+ return newInstance();
+ }
+ }
+}
diff --git a/modules/oceanbase-ce/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/oceanbase-ce/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider
new file mode 100644
index 00000000000..977e58989c9
--- /dev/null
+++ b/modules/oceanbase-ce/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider
@@ -0,0 +1 @@
+org.testcontainers.containers.OceanBaseContainerProvider
diff --git a/modules/oceanbase-ce/src/test/java/org/testcontainers/OceanBaseTestImages.java b/modules/oceanbase-ce/src/test/java/org/testcontainers/OceanBaseTestImages.java
new file mode 100644
index 00000000000..b758e8b605f
--- /dev/null
+++ b/modules/oceanbase-ce/src/test/java/org/testcontainers/OceanBaseTestImages.java
@@ -0,0 +1,8 @@
+package org.testcontainers;
+
+import org.testcontainers.utility.DockerImageName;
+
+public class OceanBaseTestImages {
+
+ public static final DockerImageName OCEANBASE_CE_IMAGE = DockerImageName.parse("oceanbase/oceanbase-ce:4.2.1_bp3");
+}
diff --git a/modules/oceanbase-ce/src/test/java/org/testcontainers/jdbc/oceanbase/OceanBaseJdbcDriverTest.java b/modules/oceanbase-ce/src/test/java/org/testcontainers/jdbc/oceanbase/OceanBaseJdbcDriverTest.java
new file mode 100644
index 00000000000..d540c71e7cf
--- /dev/null
+++ b/modules/oceanbase-ce/src/test/java/org/testcontainers/jdbc/oceanbase/OceanBaseJdbcDriverTest.java
@@ -0,0 +1,19 @@
+package org.testcontainers.jdbc.oceanbase;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.testcontainers.jdbc.AbstractJDBCDriverTest;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+
+@RunWith(Parameterized.class)
+public class OceanBaseJdbcDriverTest extends AbstractJDBCDriverTest {
+
+ @Parameterized.Parameters(name = "{index} - {0}")
+ public static Iterable