Developing Microservices in Java, JavaScript, Python, .NET, and Go with the Oracle Converged Database

June 4, 2021 | 7 minute read
Paul Parkinson
Architect and Developer Evangelist, Microservices and Converged Database
Text Size 100%:

 

This is the first in a series of blogs on data-driven microservices design mechanisms and transaction patterns with the Oracle converged database. The goal of this first blog is to illustrate how to connect to an Oracle database in Java, JavaScript, Python, .NET, and Go as succinctly as possible with source and Dockerfile examples making it a quick and easy way for you to get your microservices to connect whether on-prem or in the cloud and take advantage of the Oracle converged database.  JavaScript, Python, and Go drivers are built on Oracle's C stack "Oracle Call Interface" API and the Oracle Data Provider for .NET (ODP.NET) Core is used as the .NET driver.

The complete source can be found at https://github.com/oracle/microservices-datadriven and you can take the "Building Microservices with Oracle Converged Database Workshop" found at http://bit.ly/simplifymicroservices at any time to easily set up a full microservices environment complete with an OCI Kubernetes cluster, 2 ATP (Autonomous Transaction Processing) Oracle databases, AQ messaging propagation, container registry, object storage, etc. in ~25 minutes!

In future pieces of this series, we will explore different SQL calls (queries, commands, store procedure calls, etc.) and data models (JSON, Spatial, XML, etc.). We will also show messaging with Oracle AQ, convenience features in various frameworks, and delve into details of data-driven microservice patterns.  All shown in these five languages, but for now let’s just get connected…

We'll provide just the basic facts you need... imports, source, and Dockerfile.  There can of course be a few variations in how connections can be obtained (wallet location, use of connection pool, how connection strings are constructed, etc.) but what is presented in the following are the general approaches for connectivity and can be modified as needed. 

Instructions for downloading the client credentials (wallet) needed to connect to an Oracle cloud database such as ATP can be found here and the TNS_ADMIN environment variable must be assigned to the location of this unzipped wallet. Generally, the wallet is mounted in a Kubernetes deployment such that it can be set in the environment of the microservice container(s) it deploys. You can refer to the various *-deployment.yaml files in the repos and workshop for examples of this.

Likewise, you will notice the connection property values in the source snippets are taken from the environment. The DB_CONNECT_STRING is the service name of the DB (as found in the tnsnames.ora file) for all languages except Java where it is the full JDBC connection URL.  Note that in Java it is also possible to set the TNS_ADMIN value via this URL whereas all other languages require it to be set as an environment value as previously mentioned.  See snippets for example comments.  

 


Java

source...

import oracle.ucp.jdbc.PoolDataSource;
import java.sql.Connection;
import java.sql.SQLException;

PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
dataSource.setUser(System.getEnv("DB_USER"));
dataSource.setPassword(System.getEnv("DB_PASSWORD"));
dataSource.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
dataSource.setURL(System.getEnv("url")); //for example "jdbc:oracle:thin:@examplepdb_tp?TNS_ADMIN=/msdataworkshop/creds"
Connection connection = dataSource.getConnection();

Dockerfile...

FROM openjdk:11-jre-slim

# Oracle OJDBC and UCP jars are packaged with application jar via Maven dependencies
ENTRYPOINT ["java", "-jar", "/usr/share/myservice/myservice.jar"]
ADD target/libs           /usr/share/myservice/libs
ARG JAR_FILE
ADD target/${JAR_FILE} /usr/share/myservice/myservice.jar

 


Python

source...

import cx_Oracle

db_user = env.get('DB_USER') 
db_password = env.get('DB_PASSWORD')
db_connect_string = env.get('DB_CONNECT_STRING') //for example "examplepdb_tp"
pool = cx_Oracle.SessionPool(
    db_user,
    db_password,
    db_connect_string)
conn = pool.acquire()

Dockerfile...

FROM oraclelinux:7-slim

ARG release=19
ARG update=9
RUN  yum -y install oracle-release-el7 && \
     yum-config-manager --enable ol7_oracle_instantclient && \
     yum -y install oracle-instantclient${release}.${update}-basiclite && \
     yum install -y oracle-epel-release-el7
WORKDIR /app
COPY inventory/requirements.txt .
RUN  yum install -y python36 && \
     yum install -y tar && \
     rm -rf /var/cache/yum && \
     python3.6 -m pip install -r requirements.txt
ADD myapp .
CMD ["gunicorn", "app:app", "--config=config.py"]

 

 

JavaScript

source...

const oracledb = require('oracledb');

const dbConfig = {
  inventoryPool: {
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD, 
    connectString: process.env.DB_CONNECT_STRING //for example "examplepdb_tp"
  }
};
const pool = await oracledb.createPool(dbConfig.inventoryPool);
connection = await oracledb.getConnection();

Dockerfile...

FROM oraclelinux:7-slim

ARG release=19
ARG update=9
RUN  yum -y install oracle-release-el7 && \
     yum-config-manager --enable ol7_oracle_instantclient && \
     yum -y install oracle-instantclient${release}.${update}-basiclite && \
     yum install -y oracle-epel-release-el7
RUN  yum -y install oracle-nodejs-release-el7 && \
     yum-config-manager --disable ol7_developer_EPEL && \
     yum -y install nodejs && \
     rm -rf /var/cache/yum
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "node", "app.js" ]

 

 

.NET

source...

using System.Data;
using System.Data.Common;
using Oracle.ManagedDataAccess.Client;

OracleConfiguration.WalletLocation = Environment.GetEnvironmentVariable("TNS_ADMIN");
string connString =
    "User Id=" +
    Environment.GetEnvironmentVariable("DB_USER") +
    ";Password=" +
    Environment.GetEnvironmentVariable("DB_PASSWORD") +
    ";Data Source=" +
    Environment.GetEnvironmentVariable("DB_CONNECT_STRING") + //for example "examplepdb_tp"
    ";";
OracleConnection connection = new OracleConnection(connString)

Dockerfile...

FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY /app /app 
ENTRYPOINT ["dotnet", "inventory-dotnet.dll"]

Dockerfile (including build)...

FROM mcr.microsoft.com/dotnet/sdk:5.0.300-alpine3.13-amd64 AS build
WORKDIR /src
COPY inventory-dotnet.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "inventory-dotnet.dll"]

 


Go

source...

import (
   "context"
   "database/sql"
   "github.com/godror/godror"
)

user := os.Getenv("DB_USER")
dbpassword := os.Getenv("DB_PASSWORD") 
connectString := os.Getenv("DB_CONNECT_STRING") //for example "examplepdb_tp"
connectionString := user + "/" + dbpassword + "@" + connectString
connection, err := sql.Open("godror", connectionString)

Dockerfile...

FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    cp -r instantclient_19_3/* /lib && \
    rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    apk add libaio && \
    apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]

Dockerfile (including build)...

FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git build-base
WORKDIR /src
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/inventory-go

FROM alpine:latest
ENV LD_LIBRARY_PATH=/lib
RUN wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    cp -r instantclient_19_3/* /lib && \
    rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && \
    apk add libaio && \
    apk add libaio libnsl libc6-compat
RUN cd /lib
RUN ln -s /lib64/* /lib
RUN ln -s libnsl.so.2 /usr/lib/libnsl.so.1
RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2
COPY --from=builder /go/bin/inventory-go /usr/lib/inventory-go
ENTRYPOINT ["/usr/lib/inventory-go"]

 

Conclusion

As mentioned, this is just the beginning of a series of blogs that will go into various aspects of polyglot microservices using the Oracle converged database.

The second blog in this series uses the connection created in this blog to receive and send messages with Oracle AQ (Advanced Queueing) queues and topics and conduct an update and read from the database, all within the same local transaction, using all of these same languages in order to implement a robust and simplified event-driven microservices architectural groundwork. It can be found here.

A third installment of the series will look at various frameworks of these languages and how they provide additional convenience and functionality when creating microservices using the converged Oracle Database.

Please feel free to provide any feedback here, on the workshop, on the GitHub repos, or directly. We are happy to hear from you.

 

I would like to thank Kuassi Mensah, Alex Keh, Christian Shay, Christopher Jones, Richard Exley, Irina Granat, and Curtis Dunkel for their development help in these languages and contributions to the workshop.

Paul Parkinson

Architect and Developer Evangelist, Microservices and Converged Database

Paul is Architect and Developer Evangelist for Microservices and the Converged Database

His focus includes data and transaction processing, service mesh and event mesh, observability, and polyglot data models, languages, and frameworks.

The 18 years prior to this he was the Transaction Processing Dev Lead for the Mid-tier and Microservices (including WebLogic and Helidon)

Creator of the workshop "Building Microservices with Oracle Converged Database" @ http://bit.ly/simplifymicroservices

Holds 20+ patents and has given numerous presentations and publications over the past 20+ years.


Previous Post

How to Securely Connect to Private Resources (for Free!) via the OCI Bastion Service

Todd Sharp | 8 min read

Next Post


Enterprise Messaging via Oracle Advanced Queuing with Autonomous DB & Micronaut

Todd Sharp | 9 min read