A few weeks ago the Spring team posted an announcement stating Spring AI 1.0 GA was released. Of the many features provided by the framework you’ll find the option to store vector embeddings in vector databases, such as Oracle Database 23ai. Josh Long and yours truly posted a blog entry showcasing how you can get started with these technologies. In that particular blogpost we demonstrated how easy it is to connect to an Oracle Database 23ai Free instance running on containers.
But what if you want to go beyond that and switch to the cloud, connecting to an Autonomous Database 23ai instance? Well, turns out that there’s little changes that need to be made to the code, more specifically to the build configuration and database settings. It really doesn’t take that much.
First things first. You need to download a wallet, follow this link to find out more how you can do it. If you’re new to Autonomous Database, a wallet is a secure, password-protected container used to store authentication and encryption credentials like private keys, certificates, and other security information for Oracle databases. It enables secure access to databases without embedding passwords directly in application code or configuration files. You only need to download the wallet as a zip file. Word of caution, do not share this archive with untrusted parties nor commit it to source control, specially on a public repository. However, don’t worry if that were to happen by accident, you can still rotate the wallet using the cloud console, which would mean downloading yet another archive. I’d recommend placing the archive file in the same directory structure as your project but mark it as skipped for source control.
Alright, now that we have the wallet in place let’s see what else needs to be updated in original source code that can be found at this repository. The next order of business is configuring additional dependencies required to connect to a cloud database. As it turns out we need more than just the driver and the connection pool JARs that are already configured. The Oracle JDBC team has put forward a guide explaining what these additional JARs are and how you can configure them with both Apache Maven and Gradle.
Right, according to the guide it’s enough to configure a dependency element for ojdbc17-production. Now, one thing to remember is that Spring Boot manages versions for many of its dependencies, including 3rd party dependencies such as Oracle drivers. These versions may be updated to a different value by overriding the setting for a given user property. If you’re unfamiliar with Apache Maven you can run the mvn help:effective-pom command and see the full resolved model that the build tool uses to execute a build. In that model you may find the names of all the user properties that may be override, in our case it happens to be oracle-database.version, thus that’s the first change we’ll make to pom.xml
<properties>
<java.version>21</java.version>
<spring-ai.version>1.0.0-M8</spring-ai.version>
<oracle-database.version>23.8.0.25.04</oracle-database.version>
</properties>
Next, because we’re upgrading the project to use the latest version of the JDBC driver including a more recent version of Java, we’ll have to instruct Maven to skip resolving the previous artifact that Spring Boot has configured, otherwise we’ll end with duplicate artifacts of the drivers but with different versions. For this we have to define a set of exclusions in the spring-ai-starter-vector-store-oracle dependency, like so
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-oracle</artifactId>
<exclusions>
<exclusion>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
</exclusion>
<exclusion>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ucp</artifactId>
</exclusion>
</exclusions>
</dependency>
Now, we can configure the actual artifact we need to connect to cloud databases
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc17-production</artifactId>
<version>${oracle-database.version}</version>
<type>pom</type>
</dependency>
Notice the use of the <type>pom</type> element. This is quite important otherwise Apache Maven will be unable to resolve all required dependencies. There’s one final bit that needs to be updated in the pom.xml file. As we are no longer connecting to a database running in a container we also have to skip the use of the Docker compose plugins
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
-->
Good, we’re almost there with all required changes. The last bit is to tell the application which connection URL it should use to connect to the cloud database. Open up src/main/resources/application.properties and change the value of the spring.datasource.url property to match your configuration, that is, service name and wallet location
spring.datasource.url=jdbc:oracle:thin:@<service>?TNS_ADMIN=<path/to/wallet>
You can obtain the name of a given service by uncompressing the wallet archive and looking inside the tnsnames.ora file. For example, in my case I’d use oraclevector_medium because I named my database as oraclevector. The path to your wallet must be absolute.
With these settings in place you can now launch the application and connect to the database. As you can see, there’s not much that needs to be changed to switch from a container instance to a cloud instance. You can safely and securely connect to a cloud database in this way.
