<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Parkinson</title>
    <description>The latest articles on DEV Community by Paul Parkinson (@paulparkinson).</description>
    <link>https://dev.to/paulparkinson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F643583%2F0a5ea75f-eb1b-4ca5-af4e-05ea908c2165.jpeg</url>
      <title>DEV Community: Paul Parkinson</title>
      <link>https://dev.to/paulparkinson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/paulparkinson"/>
    <language>en</language>
    <item>
      <title>Developing Microservices in Java, JavaScript, Python, .NET, and Go with the Oracle Converged Database</title>
      <dc:creator>Paul Parkinson</dc:creator>
      <pubDate>Thu, 30 Sep 2021 18:21:10 +0000</pubDate>
      <link>https://dev.to/paulparkinson/developing-microservices-in-java-javascript-python-net-and-go-with-the-oracle-converged-database-58</link>
      <guid>https://dev.to/paulparkinson/developing-microservices-in-java-javascript-python-net-and-go-with-the-oracle-converged-database-58</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The complete source can be found at &lt;a href="https://github.com/oracle/microservices-datadriven"&gt;https://github.com/oracle/microservices-datadriven&lt;/a&gt; and you can take the "Building Microservices with Oracle Converged Database Workshop" found at &lt;a href="http://bit.ly/simplifymicroservices"&gt;http://bit.ly/simplifymicroservices&lt;/a&gt; at anytime to easily set up a full micro services 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!&lt;/p&gt;

&lt;p&gt;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 micro service patterns.  All shown in these five languages, but for now let’s just get connected…&lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 be set as an environment value as previously mentioned.  See snippets for example comments.  &lt;/p&gt;

&lt;h1&gt;
  
  
  Java
&lt;/h1&gt;

&lt;p&gt;source...&lt;/p&gt;

&lt;p&gt;import oracle.ucp.jdbc.PoolDataSource;&lt;br&gt;
import java.sql.Connection;&lt;br&gt;
import java.sql.SQLException;&lt;/p&gt;

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

&lt;p&gt;FROM openjdk:11-jre-slim&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Python
&lt;/h1&gt;

&lt;p&gt;source...&lt;/p&gt;

&lt;p&gt;import cx_Oracle&lt;/p&gt;

&lt;p&gt;db_user = env.get('DB_USER') &lt;br&gt;
db_password = env.get('DB_PASSWORD')&lt;br&gt;
db_connect_string = env.get('DB_CONNECT_STRING') //for example "examplepdb_tp"&lt;br&gt;
pool = cx_Oracle.SessionPool(&lt;br&gt;
    db_user,&lt;br&gt;
    db_password,&lt;br&gt;
    db_connect_string)&lt;br&gt;
conn = pool.acquire()&lt;br&gt;
Dockerfile...&lt;/p&gt;

&lt;p&gt;FROM oraclelinux:7-slim&lt;/p&gt;

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

&lt;h1&gt;
  
  
  JavaScript
&lt;/h1&gt;

&lt;p&gt;source...&lt;/p&gt;

&lt;p&gt;const oracledb = require('oracledb');&lt;/p&gt;

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

&lt;p&gt;FROM oraclelinux:7-slim&lt;/p&gt;

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

&lt;h1&gt;
  
  
  .NET
&lt;/h1&gt;

&lt;p&gt;source...&lt;/p&gt;

&lt;p&gt;using System.Data;&lt;br&gt;
using System.Data.Common;&lt;br&gt;
using Oracle.ManagedDataAccess.Client;&lt;/p&gt;

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

&lt;p&gt;FROM mcr.microsoft.com/dotnet/aspnet:5.0&lt;br&gt;
WORKDIR /app&lt;br&gt;
COPY /app /app &lt;br&gt;
ENTRYPOINT ["dotnet", "inventory-dotnet.dll"]&lt;br&gt;
Dockerfile (including build)...&lt;/p&gt;

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

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

&lt;h1&gt;
  
  
  Go
&lt;/h1&gt;

&lt;p&gt;source...&lt;/p&gt;

&lt;p&gt;import (&lt;br&gt;
   "context"&lt;br&gt;
   "database/sql"&lt;br&gt;
   "github.com/godror/godror"&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;user := os.Getenv("DB_USER")&lt;br&gt;
dbpassword := os.Getenv("DB_PASSWORD") &lt;br&gt;
connectString := os.Getenv("DB_CONNECT_STRING") //for example "examplepdb_tp"&lt;br&gt;
connectionString := user + "/" + dbpassword + "@" + connectString&lt;br&gt;
connection, err := sql.Open("godror", connectionString)&lt;br&gt;
Dockerfile...&lt;/p&gt;

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

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

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

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;As mentioned, this is just the beginning in a series of blogs that will go into various aspects of polyglot microservices using the Oracle converged database not limited to the following...&lt;/p&gt;

&lt;p&gt;Various SQL calls (queries, updates, store procedure calls, etc.)&lt;/p&gt;

&lt;p&gt;Various data models such as JSON, Spatial, XML, and so on&lt;/p&gt;

&lt;p&gt;Messaging with AQ and Kafka APIs&lt;/p&gt;

&lt;p&gt;Various frameworks (such as Helidon, Micronaut, Springboot, .NET, DJango, Express, etc.)&lt;/p&gt;

&lt;p&gt;Data-driven microservice patterns such as Event Sourcing, CQRS, Sagas, etc.&lt;/p&gt;

&lt;p&gt;Please feel free to provide any feedback here, on the workshop, on the github repos, or directly. We are happy to hear from you.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>dotnet</category>
      <category>go</category>
    </item>
  </channel>
</rss>
