Today I wanted to read the contents of a JMS Text Message sitting in a queue. I wrote a Spring Boot micrsoervice that sends a message, and I have not written the one that recieves and processes the message yet, so I wanted to look at the message on the queue to check it was correct.
So I went and did a good old “select user_data from deposits_qt” and stared at the answer: “Object”. Hmmm, not what I wanted.
After a quick bit of Googling, I found Rob’s post which told me exactly what I needed to know. Yay! Thanks Rob!
Then I changed my query to this:
select qt.user_data.text_vc from account.deposits_qt qt;
And I got exactly what I needed:
{"accountId":2,"amount":200}
Fantastic! Thnaks a lot Rob!
]]>
Register for VMWare Explore here. Learn more about Oracle Backend for Spring Boot here.
]]>Here’s the dependency to add:
<dependency>
<groupId>com.oracle.database.spring</groupId>
<artifactId>oracle-spring-boot-starter-ucp</artifactId>
<version>3.0.2</version> <!-- or 2.7.7 for Spring Boot 2.x -->
<type>pom</type>
</dependency>
Here’s an example, assuming you are also using Spring Data JPA:
spring:
application:
name: aqjms
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle12cDialect
format_sql: true
show-sql: true
datasource:
url: jdbc:oracle:thin:@//1.2.3.4:1521/pdb1
username: someuser
password: somepassword
driver-class-name: oracle.jdbc.OracleDriver
type: oracle.ucp.jdbc.PoolDataSource
oracleucp:
connection-factory-class-name: oracle.jdbc.pool.OracleDataSource
connection-pool-name: AccountConnectionPool
initial-pool-size: 15
min-pool-size: 10
max-pool-size: 30
That’s super easy, right?
We are working to add more Spring Boot Starters for Oracle Database to make it even easier to use, and to make sure we cover all the versions you need! Stay tuned for more updates!
p.s. If you use Spring Boot and Oracle Database, be sure to check out Oracle Backend for Spring Boot!
]]>I hope you can check it out!
Data strategies for developers – Sessions at a glance
I hope to see some of you there!
]]>If you’re in the Bay Area and you’d like to attend in person – or if you’d like to attend from anywhere digitally – you can find more information and register here:
https://developer.oracle.com/community/events/devlive-level-up-march-2023.html
]]>I want to create a “customer” microservice that I can use to create/register customers, and to get customer details. I want the customer information to be stored in my Oracle database. I am going to create a dedicated schema for this microservice, where it will keep its data. I could create a separate pluggable database, but that seems a little excessive given the simplicity of this service.
So my “customer” data will have the following attributes:
My service will have endpoints to:
I am going to use Spring 3.0.0 with Java 17 and Maven. Spring 3.0.0 was just released (when I started writing this post) and has support for GraalVM native images and better observability and tracing.
Let’s start by creating a project. If you set up your development environment like mine, with Visual Studio Code and the Spring Extension Pack, you can type Ctrl+Shift+P to bring up the actions and type in “Spring Init” to find the “Spring Initializr: Create a Maven project” action, then hit enter.

It will now ask you a series of questions. Here’s how I set up my project:
After that, it will ask you which directory to create the project in. Once you answer all the questions, it will create the project for you and then give you the option to open it (in a new Visual Studio Code window.)
Note: If you prefer, you can go to the Spring Initializr website instead and answer the same questions there instead. It will then generate the project and give you a zip file to download. If you choose this option, just unzip the file and open it in Visual Studio Code.

Whichever approach you take, you should end up with a project open in Code that looks a lot like this:

I like to trim out a few things that we don’t really need. I tend to delete the “.mvn” directory, the “mvnw” and “mvnw.cmd” files and the “HELP.md” file. Now is also a great time to create a git repository for this code. I like to add/commit all of these remaining files and keep that as my starting point.
Here’s the Maven POM (pom.xml) that was generated:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.redstack</groupId>
<artifactId>customer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>customer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
There’s a few things to note here. The parent is the standard spring-boot-starter-parent and this will bring in a bunch of useful defaults for us. The dependencies list contains the items we chose in the Spring Initializr (as expected) and finally, note the build section has the spring-boot-maven-plugin included. This will let us build and run the Spring Boot application easily from maven (with “mvn spring-boot:run“).
Let’s add one more dependency:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
Lombok offers various annotations aimed at replacing Java code that is well known for being boilerplate, repetitive, or tedious to write. We’ll use it to avoid writing getters, setters, constructors and builders.
And here is the main CustomerApplication Java class file:
package com.redstack.customer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
Nothing much to see here. Notice it has the SpringBootApplciation annotation.
Let’s go ahead and define our data model now. Since we are using JPA, we define our data model using a POJO. Create a Customer.java file in src/main/java/com/redstack/customer with this content:
package com.redstack.customer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Customer {
@Id
@SequenceGenerator(
name = "customer_id_sequence",
sequenceName = "customer_id_sequence"
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "customer_id_sequence"
)
private Integer id;
private String firstName;
private String lastName;
private String email;
}
Starting from the bottom, we see the definition of the four fields that we wanted for our Customer entity – ID, first and last names, and email address.
The id field has some annotations on it. First it has @Id which identifies it as the key. Then we have a @SequenceGenerator annotation, which tells JPA that we want to create a “sequence” in the database and gives it a name. A sequence is a database object from which multiple users may generate unique integers. The last annotation, @GeneratedValue tells JPA that this field should be populated from that sequence.
The class also has some annotations on it. It has the JPA @Entity annotation which tells JPA that this is an entity that we want to store in the database. The other annotations are Lombok annotations to save us writing a bunch of boilerplate code. @Data generates getters for all fields, a useful toString method, and hashCode and equals implementations that check all non-transient fields. It will also generate setters for all non-final fields, as well as a constructor. @Builder generates some nice APIs to create instances of our object – we’ll see how we use it later on. And @AllArgsConstructor and @NoArgsConstructor generate pretty much what their names suggest they do.
Ok, next let’s set up the JPA configuration in the Spring Boot Application Properties. You will find a file called application.properties in src/main/resources. This file can be in either the “properties” format, or in YAML. I personally prefer to use YAML, so I renamed that file to application.yaml and here is the content:
server:
port: 8080
spring:
application:
name: customer
datasource:
username: 'customer'
url: jdbc:oracle:thin:@//172.17.0.2:1521/pdb1
password: 'Welcome123'
driver-class-name: oracle.jdbc.driver.OracleDriver
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.OracleDialect
format-sql: 'true'
hibernate:
ddl-auto: update
show-sql: 'true'
Let’s look at what we have here. First we set the port to 8080, and the application’s name to “customer”. If you prefer to use the properties format these first two setting would like like this:
server.port=8080
spring.application.name=customer
After that we set up the data source. You can provide the JDBC URL for your Oracle Database, and the username and password and the JBDC driver class, as shown. Note that the use will need to actually exist. You can create the user in the database by running these statements as an admin user:
create user customer identified by Welcome123;
grant connect, resource to customer;
alter user customer quota unlimited on users;
commit;
The final section of config we see here is the JPA configuration where we need to declare which “dialect” we are using – this identifies what kind of SQL should be generated, in our case Oracle. The format-sql and show-sql settings are jsut there to make the SQL statements we see in logs easier for us to read.
The ddl-auto setting is interesting. Here’s a good article that explains the possible values and what they do. We’ve used update in this example, which “instructs Hibernate to update the database schema by comparing the existing schema with the entity mappings and generate the appropriate schema migration scripts.” That’s a resonable choice for this scenario, but you shoudl be aware that there are probably better choices in some cases. For example, if you are actively developing the entity and making changes to it, create-drop might be better for you. And if the database objects already exist and you just want to use them, then none might be the best choice – we’ll talk more about this in a future post!
Next, let’s create the JPA Repository class which we can use to save, retrieve and delete entities in/from the database. Create a file called CustomerRepository.java in src/main/java/com/redstack/customer with this content:
package com.redstack.customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
}
Ok, that takes care of our JPA work. Now, let’s get started on our services.
Let’s start with a service to register (create) a new customer. We can start by defining the input data that we expect. Let’s create a CustomerRegistrationRequest.java in the same directory with this content:
package com.redstack.customer;
public record CustomerRegistrationRequest(
String firstName,
String lastName,
String email) {
}
Notice that we did not include the ID, because we are going to get that from the database sequence. So we just need the client/caller to give us the remaining three fields.
Next, we can create our controller. Create a new file called CustomerController.java in the same directory with this content:
package com.redstack.customer;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api/v1/customers")
public record CustomerController(CustomerService service) {
@PostMapping
@ResponseBody
public ResponseEntity<String> registerCustomer(@RequestBody CustomerRegistrationRequest req) {
service.registerCustomer(req);
return ResponseEntity.status(HttpStatus.CREATED).body("Customer registered successfully.\n");
}
}
So here we used a Java record to define the controller, and we ask Spring to inject the CustomerService for us. Obviously, we have not created that yet, we’ll get to that in a minute! The reocrd has two annotations – @RestController tells spring to expose a REST API for this record, and @RequestMapping lets us set up the URL path for this controller. Since we set the port to 8080 earlier, and assuming we just run this on our development machine for now, this REST API will have a URL of http://localhost:8080/api/v1/customers.
Next we can define the handlers. Here we have just the first one, to handle HTTP POST requests. We will add others later. Our registerCustomer method will be exposed as the handler for POST requests, because we gavt it the @PostMapping annotation, and it will be able to return an HTTP response with a status code and body becauase we gave it the @RepsonseBody annotation. This method accepts the CustomerRegistrationRequest that we defined earlier. Notice that we add the @RequestBody annotation to that method argument. This tells Spring that the data will be provided by the caller as JSON in the HTTP Request Body (as opposed to being in a query or header, etc.) And this handler simply calls the registerCustomer method in the service and passes through the data.
So, its time to write the service! Create a new file called CusotmerService.java in the same directory with this content:
package com.redstack.customer;
import org.springframework.stereotype.Service;
@Service
public record CustomerService(CustomerRepository repository) {
public void registerCustomer(CustomerRegistrationRequest req) {
Customer customer = Customer.builder()
.firstName(req.firstName())
.lastName(req.lastName())
.email(req.email())
.build();
repository.saveAndFlush(customer);
}
}
Again, we are using a Java record for the service. Records are immutable data classes that require only the type and name of fields. The equals, hashCode, and toString methods, as well as the private, final fields and public constructor, are generated by the Java compiler. You can also include static variables and methods in records. I’m using them here to save a bunch of boilerplate code that I do not want to write.
We put the @Service annotation on the record to tell Spring that this is a service. In the record arguments, we have Spring inject an instance of our CustomerRepository which we will need to talk to the database.
For now, we just need one method in our service, registerCustomer(). We’ll add more later. This method also accepts the CustomerRegistrationRequest and the first thing we do with it is create a new Customer entity object. Notice that we are using the builder that we auto-generated with Lombok – we never wrote any code to create this builder! Yay! Then, all we need to do is use our JPA repository’s saveAndFlush() method to save that customer in the database. saveAndFlush will do an INSERT and then a COMMIT in the database.
Let’s start up our service and test it! Before we start, you might want to connect to your database and satisfy yourself that there is no CUSTOMER table there:
sql customer/Welcome123@//172.17.0.2:1521/pdb1
SQL> select table_name from user_tables;
no rows selected
To run the service, run this Maven command:
mvn spring-boot:run
This will compile the code and then run the service. You will see a bunch of log messages appear. In around the middle you should see something like this:
2023-02-03T11:15:37.827-05:00 INFO 8488 --- [ main] SQL dialect : HHH000400: Using dialect: org.hibernate.dialect.OracleDialect
Hibernate: create global temporary table HTE_customer(id number(10,0), email varchar2(255 char), first_name varchar2(255 char), last_name varchar2(255 char), rn_ number(10,0) not null, primary key (rn_)) on commit delete rows
Hibernate: create table customer (id number(10,0) not null, email varchar2(255 char), first_name varchar2(255 char), last_name varchar2(255 char), primary key (id))
There’s the SQL that it ran to create the CUSTOMER table for us! If you’d like to, you can check in the database with this statement:
SQL> describe customer;
Name Null? Type
_____________ ___________ _____________________
ID NOT NULL NUMBER(10)
EMAIL VARCHAR2(255 CHAR)
FIRST_NAME VARCHAR2(255 CHAR)
LAST_NAME VARCHAR2(255 CHAR)
You can also take a look at the sequence if you would like to:
SQL> select sequence_name, min_value, increment_by, last_number from user_sequences;
SEQUENCE_NAME MIN_VALUE INCREMENT_BY LAST_NUMBER
_______________________ ____________ _______________ ______________
CUSTOMER_ID_SEQEUNCE 1 50 1001
Now, let’s invoke the service to test it! We can invoke the service using cURL, we need to do a POST, set the Content-Type header and provide the data in JSON format:
$ curl -i \
-X POST \
-H 'Content-Type: application/json' \
-d '{"firstName": "Mark", "lastName": "Nelson", "email": "[email protected]"}' \
http://localhost:8080/api/v1/customers
HTTP/1.1 201
Content-Type: text/plain;charset=UTF-8
Content-Length: 34
Date: Fri, 03 Feb 2023 17:41:39 GMT
Customer registered successfully.
The “-i” tells cURL to pring out the response. You can see that we got a HTTP 201 (created), i.e., success!
Now we see the new record in the database, as expected:
SQL> select * from customer ;
ID EMAIL FIRST_NAME LAST_NAME
_____ ________________ _____________ ____________
1 [email protected] Mark Nelson
Great, that is working the way we wanted, so we can create customers and have them stored in the database. Now let’s add some endpoints to query customers from the database.
The first endpoint we want to add will allow us to get a list of all customers. To do this, let’s add this new method to our controller:
// add these imports
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
// ...
@GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public List<Customer> getAllCustomers() {
return service.getAllCustomers();
}
Here we have a getAllCustomers() method that simply calls the corresponding method in the service (we’ll write that in a moment) and returns the results. Of course, we have some annotations too. The @GetMapping tells Spring Boot that this method will be exposed as an HTTP GET method handler. The produces defines the output body’s Content-Type, in this case it will be “application/json“. The @ResponseStatus sets the HTTP status code.
Here’s the method we need ot add to our CustomerService, notice it just uses a built-in method on the repository to get the data, its very simple:
// add this import
import java.util.List;
// ...
public List<Customer> getAlCustomers() {
return repository.findAll();
}
With those changes in place, we can restart the service and call this new GET endpoint like this:
$ curl -i http://localhost:8080/api/v1/customers
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 03 Feb 2023 17:55:17 GMT
[{"id":1,"firstName":"Mark","lastName":"Nelson","email":"[email protected]"}]
You might like to do a few more POSTs and another GET to observe what happens.
Let’s add the final endpoint that we wanted in our service. We want to be able to get a specific customer using the ID. Here’s the code to add to the controller:
// add these imports
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// ...
@GetMapping(path="/{id}", produces = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
public ResponseEntity<Customer> getCustomer(@PathVariable Integer id) {
Optional<Customer> c = service.getCustomer(id);
if (c.isPresent()) {
return ResponseEntity.status(HttpStatus.OK).body(c.get());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
}
Here we see some differences to the previous endpoint implementation. This one is a little more sophisticated. First, we have added a path to the @GetMapping annotation to add a positional parameter to the end of the path, so this endpoint will be /api/v1/customers/{id}. In the method arguments we have a @PathVariable annotation to grab that {id} from the path and use it as an argument to our method.
Also, notice that the method returns ResponseEntity<Customer>. This gives us some more control over the response, and allows us to set different HTTP status codes (and if we wanted to we could also control the headers, body, etc.) based on our own business logic.
Inside this method we call our service’s (soon to be written) getCustomer(id) method which returns an Optional<Customer>. Then we check if the Optional actually contains a Customer, indicating that a customer entity/record was found for the specified id, and if so we return it along with an HTTP 200 (OK). If the Optional is empty, then return an HTTP 404 (not found).
Here’s the new method to add to the service:
// add this import
import java.util.Optional;
// ...
public Optional<Customer> getCustomer(Integer id) {
return repository.findById(id);
}
This one is fairly sinple, we are just calling a standard built-in method on the JPA Repository class to get the data.
Now we can restart the application, and test the new endpoint by asking for customers that we know exist, and do not exist to observe the different outcomes:
$ curl -i http://localhost:8080/api/v1/customers/1
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 03 Feb 2023 18:15:30 GMT
{"id":1,"firstName":"Mark","lastName":"Nelson","email":"[email protected]"}
$ curl -i http://localhost:8080/api/v1/customers/5
HTTP/1.1 404
Content-Length: 0
Date: Fri, 03 Feb 2023 18:15:37 GMT
Notice the HTTP status codes are different in each case. Also, notice that the JSON returned when a customer is found is just one JSON object {…} not a list [{…}, … ,{…}] as in the get all customers endpoint.
Well there you have it, we have completed our simple customer microservice built using Spring Boot and Oracle Database. I hope you followed along and built it too, and enjoyed learing a bit about Spring Boot and Oracle! Stay tuned for more posts on this topic, each covering a little more advanced toopic than the last. See you soon!
]]>Personally, I work on Windows 11 with the Windows Subsystem for Linux and Ubuntu 20.04. Of course you can adjust these instructions to work on macOS or Linux.
First thing we need is the Java Development Kit. I used Java 17, here’s a permalink to download the latest tar for x64: https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
You can just decompress that in your home directory and then add it to your path:
export JAVA_HOME=$HOME/jdk-17.0.3
export PATH=$JAVA_HOME/bin:$PATH
You can verify it is installed with this command:
$ java -version
java version "17.0.3" 2022-04-19 LTS
Java(TM) SE Runtime Environment (build 17.0.3+8-LTS-111)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.3+8-LTS-111, mixed mode, sharing)
Great! Now, let’s move on to build automation.
You can use Maven or Gradle to build Spring Boot projects, and when you generate a new project from Spring Initialzr (more on that later) it will give you a choice of these two. Personally, I prefer Maven, so that’s what I document here. If you prefer Gradle, I’m pretty sure you’ll already know how to set it up
I use Maven 3.8.6, which you can download from the Apache Maven website in various formats. Here’s a direct link for the zip file: https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
You can also just decompress this in your home directory and add it to your path:
export PATH=$HOME/apache-maven-3.8.6/bin:$PATH
You can verify it is installed with this command:
$ mvn -v
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /home/mark/apache-maven-3.8.6
Java version: 17.0.3, vendor: Oracle Corporation, runtime: /home/mark/jdk-17.0.3
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "5.10.102.1-microsoft-standard-wsl2", arch: "amd64", family: "unix"
Ok, now we are going to need an IDE!
These days I find I am using Visual Studio Code for most of my coding. It’s free, lightweight, has a lot of plugins, and is well supported. Of course, you can use a different IDE if you prefer.
Another great feature of Visual Studio Code that I really like is the support for “remote coding.” This lets you run Visual Studio Code itself on Windows but it connects to a remote Linux machine and that’s where the actual code is stored, built, run, etc. This could be an SSH connection, or it could be connecting to a WSL2 “VM” on your machine. This latter option is what I do most often. So I get a nice friendly, well-behaved native desktop applciation, but I am coding on Linux. Kind of the best of both worlds!
You can download Visual Studio Code from its website and install it.
I use a few extensions (plugins) that you will probably want to get too! These add support for the languages and frameworks and give you things like completion and syntax checking and so on:
You can install these by opening the extensions tab (Ctrl-Shift-X) and using the search bar at the top to find and install them.
Since our microservices applications are probably almost certainly going to end up running in Kubernetes, its a good idea to have a local test environment. I like to use “docker compose” for initial testing locally and then move to Kubernetes later.
I use Rancher Desktop for both containers and Kubernetes on my laptop. There are other options if you prefer to use something different.
And last, but not least, you will need the Oracle Database container image so we can run a local database to test against. If you don’t already have it, you will need to go to Oracle Container Registry first, and navigate to “Database,” then “Enterprise,” and accept the license agreement, then pull the image with these commands:
docker login container-registry.oracle.com -u [email protected]
docker pull container-registry.oracle.com/database/enterprise:21.3.0.0
Then you can start a database with this command:
docker run -d \
--name oracle-db \
-p 1521:1521 \
-e ORACLE_PWD=Welcome123 \
-e ORACLE_SID=ORCL \
-e ORACLE_PDB=PDB1 \
container-registry.oracle.com/database/enterprise:21.3.0.0
The first time yoiu start it up, it will create a database instacne for you. This takes a few minutes, you can watch the logs to see when it is done:
docker logs -f oracle-db
You will see this message in the logs when it is ready:
#########################
DATABASE IS READY TO USE!
#########################
You can then stop and start the database container as needed – you won’t need to wait for it to create the database instance each time, it will stop and start in just a second or two.
docker stop oracle-db
docker start oracle-db
You are going to want to grab its IP address for later on, you can do that with this command:
docker inspect oracle-db | grep IPAddress
This container image has SQL*Plus in it, and you can use that as a database command line client, but I prefer the new Oracle SQLcl which is a lot nicer – it has completion and arrow key navigation and lots of other cool new features. Here’s a permalink for the latest version: https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip
You can just unzip this and add it to your path too, like Maven and Java.
You can connect to the database using SQLcl like this (use the IP address you got above):
sql sys/Welcome123@//172.12.0.2:1521/pdb1 as sysdba
Well, that’s about everything we need! In the next post we’ll get started building a Spring Boot microservice!
]]>