<!--
  canonical-url: https://www.avonture.be/fr/blog/oracle-dotnet-nodejs-php-python
  published:     2025-04-18
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Accéder à une base de données Oracle avec .Net, NodeJS, PHP et Python

> Guide pas à pas pour accéder à un container de base de données Oracle avec .Net, Node.js, PHP et Python. Inclut le Dockerfile et des exemples de code complets pour chaque langage.

---
![Accéder à une base de données Oracle avec .Net, NodeJS, PHP et Python](/img/v2/oracle.webp)

**TL;DR**

Ce guide pas à pas montre comment se connecter à une base de données Oracle depuis .Net, Node.js, PHP et Python. Pour chaque langage, vous trouverez un exemple complet, prêt à l'emploi, avec le `Dockerfile` permettant de construire un container contenant toutes les dépendances nécessaires, ainsi qu'un script d'exemple pour interroger la base. Cet article fournit un template de démarrage rapide pour toute personne devant intégrer une base Oracle dans son application, quel que soit le langage de programmation.

Dans un article précédent ([Running Oracle Database Server as a Docker container](/blog/docker-oracle-database-server)), nous avons créé un container Docker appelé `oracle-db` dans lequel tourne une base de données « Human Resources ».

Cette fois, amusons-nous avec .Net, NodeJS, PHP et Python pour y accéder et afficher des enregistrements.

Pour chaque langage, nous allons construire une image Docker avec tout le nécessaire, comme l'Oracle Instant Client, puis nous écrirons un petit script pour nous connecter à la table `employees` et afficher les enregistrements.

L'idée est de fournir un squelette très rapide pour démarrer un projet dans ces langages lorsque vous avez besoin de vous connecter directement à une base Oracle.

*Si vous préférez ne pas écrire de connecteur du tout, [Transform an Oracle DB as OpenData using Oracle REST Data Services](/blog/docker-oracle-ords) expose les mêmes tables sous forme d'API REST que n'importe quel langage peut consommer avec un simple appel HTTP.*

Voici le résultat, quel que soit le langage choisi ci-dessous : un petit container Docker qui se connecte et affiche la table des employés.

![Utiliser .Net pour accéder à la liste des employés](./images/using_dotnet.webp)

Dans l'article [Running Oracle Database Server as a Docker container](/blog/docker-oracle-database-server), nous avons créé un container Docker appelé `oracle-db` dans lequel tourne une base de données « Human Resources ».

Merci de lire cet article et d'en suivre les étapes afin d'avoir, avant de continuer ici, un container Docker fonctionnel tel que décrit ci-dessous.

## Quelques prérequis {#some-prerequisites}

**Avant de commencer, assurez-vous que...**

1. Vous avez un container Docker en cours d'exécution appelé `oracle-db`,

2. Le container tourne donc sur votre `localhost`,

3. Le numéro de port pour accéder à votre base de données est `1521`,

4. Les identifiants à utiliser sont `SYS` (ou `SYSTEM`) et `admin` comme mot de passe,

5. Le container contient une base de données appelée `ORCLPDB1` (aussi appelée nom de service) qui est l'exemple Human Resources d'Oracle (voir l'article mentionné) et

6. Notre base `oracle-db` tourne sur un réseau appelé `oracle`.

## Les exemples de code ont été largement créés avec l'IA {#the-code-samples-were-largely-created-using-ai}

Parce que c'est rapide et aussi parce que je ne connais pas .Net et très peu NodeJS, j'ai utilisé Google Gemini pour construire mes exemples ci-dessous. Parfois, comme pour .Net, c'était presque prêt à l'emploi. Parfois, comme pour PHP, c'était plus compliqué et il m'a fallu pas mal de bidouillage pour trouver la bonne configuration.

L'objectif de cet article était néanmoins de fournir le minimum de fichiers pour se connecter à une base Oracle, exécuter une requête SELECT et afficher les résultats ; pas d'avoir une base de code exemplaire.

## Accéder à notre container Oracle DB avec .Net {#access-our-oracle-db-container-using-net}

Premier langage par ordre alphabétique ; jouons avec un container .Net :

```bash
$ mkdir -p /tmp/oracle/dotnet && cd $_
```

Créez aussi ce répertoire :

```bash
$ mkdir -p /tmp/oracle/dotnet/OracleConnector
```

Créons un Dockerfile :

**Dockerfile**

```docker
# cspell:ignore libaio1,instantclient,libclntsh,libocci,ldconfig

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

WORKDIR /app

COPY OracleConnector/*.csproj ./OracleConnector/
RUN dotnet restore ./OracleConnector/OracleConnector.csproj

COPY OracleConnector/. ./OracleConnector/
RUN dotnet publish ./OracleConnector/OracleConnector.csproj -c Release -o out

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS final

WORKDIR /app

COPY --from=build /app/out .

# Install necessary Oracle Instant Client libraries
ARG ORACLE_INSTANT_CLIENT_VERSION=21.12
ARG ORACLE_DOWNLOAD_URL=https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip

RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    unzip \
    libaio1 \
    && rm -rf /var/lib/apt/lists/*

RUN curl -sSL "${ORACLE_DOWNLOAD_URL}" -o instantclient.zip \
    && mkdir -p /usr/lib/oracle/instantclient \
    && unzip -qq instantclient.zip -d /usr/lib/oracle/instantclient \
    && rm instantclient.zip \
    && ln -s /usr/lib/oracle/instantclient/libclntsh.so.${ORACLE_INSTANT_CLIENT_VERSION}.1 /usr/lib/oracle/instantclient/libclntsh.so \
    && ln -s /usr/lib/oracle/instantclient/libocci.so.${ORACLE_INSTANT_CLIENT_VERSION}.1 /usr/lib/oracle/instantclient/libocci.so \
    && echo "/usr/lib/oracle/instantclient" > /etc/ld.so.conf.d/oracle-instantclient.conf \
    && ldconfig

ENTRYPOINT ["dotnet", "OracleConnector.dll"]
```

Passons maintenant à la partie DotNet. Nous avons besoin de deux fichiers : `OracleConnector/OracleConnector.csproj` et `OracleConnector/main.cs`.

**OracleConnector/OracleConnector.csproj**

```csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.121" />
  </ItemGroup>

</Project>
```

**OracleConnector/main.cs**

```cs
// cspell:ignore orclpdb1

using Oracle.ManagedDataAccess.Client;
using System;

namespace OracleConnector
{
    class Program
    {
        static void Main(string[] args)
        {
            string dbHost = Environment.GetEnvironmentVariable("ORACLE_HOST") ?? "oracle-db";
            string dbPort = Environment.GetEnvironmentVariable("ORACLE_PORT") ?? "1521";
            string dbService = Environment.GetEnvironmentVariable("ORACLE_SERVICE") ?? "orclpdb1";
            string dbUser = Environment.GetEnvironmentVariable("ORACLE_USER") ?? "system";
            string dbPassword = Environment.GetEnvironmentVariable("ORACLE_PASSWORD") ?? "admin";

            string connectionString = $"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={dbHost})(PORT={dbPort})))(CONNECT_DATA=(SERVICE_NAME={dbService})));User ID={dbUser};Password={dbPassword};";

            try
            {
                using (OracleConnection connection = new OracleConnection(connectionString))
                {
                    connection.Open();

                    string sql = "SELECT employee_id, first_name, last_name, email FROM employees WHERE ROWNUM <= 25";

                    using (OracleCommand command = new OracleCommand(sql, connection))
                    using (OracleDataReader reader = command.ExecuteReader())
                    {
                        Console.WriteLine("\nEmployee ID | First Name           | Last Name            | Email");
                        Console.WriteLine("------------|----------------------|----------------------|-------------------------");

                        while (reader.Read())
                        {
                            int employeeId = reader.GetInt32(0);
                            string firstName = reader.GetString(1);
                            string lastName = reader.GetString(2);
                            string email = reader.GetString(3);

                            Console.WriteLine($"{employeeId,-12}| {firstName,-21}| {lastName,-21}| {email}");
                        }
                    }
                }
            }
            catch (OracleException ex)
            {
                Console.WriteLine($"Error connecting to or querying Oracle: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An unexpected error occurred: {ex.Message}");
            }
        }
    }
}
```

Voici à quoi ressemble votre projet dans VSCode :

![Projet .Net dans VSCode](./images/vscode_dotnet.webp)

Toujours dans la console, dans le dossier `/tmp/oracle/dotnet`, construisez l'image Docker et lancez le container (et donc le script) : `clear ; docker build -t oracle-dotnet . && docker run --rm -it --network oracle oracle-dotnet`.

Et voilà — le même résultat que celui affiché en haut de cet article, notre code .Net a bien accédé à la liste.

## Accéder à notre container Oracle DB avec NodeJS {#access-our-oracle-db-container-using-nodejs}

Deuxième par ordre alphabétique, jouons avec un container NodeJS :

```bash
$ mkdir -p /tmp/oracle/nodejs && cd $_
```

Créons un Dockerfile :

**Dockerfile**

```docker
# cspell:ignore libaio

FROM node:20-alpine

WORKDIR /app

COPY package.json .

RUN npm install -g npm@latest
RUN npm install

RUN apk add --no-cache --update curl unzip libaio

COPY main.js .

CMD ["npm", "start"]
```

Nous avons aussi besoin de ces fichiers :

**package.json**

```json
{
    "name": "oracle-connector-nodejs",
    "version": "1.0.0",
    "description": "Node.js script to connect to Oracle",
    "main": "app.js",
    "scripts": {
      "start": "node main.js"
    },
    "dependencies": {
      "oracledb": "^6.3.0"
    }
}
```

**main.js**

```javascript
// cspell:ignore orclpdb1, oracledb

const oracledb = require("oracledb");

async function run() {
  let connection;

  try {
    const dbHost = process.env.ORACLE_HOST || "oracle-db";
    const dbPort = process.env.ORACLE_PORT || "1521";
    const dbService = process.env.ORACLE_SERVICE || "orclpdb1";
    const dbUser = process.env.ORACLE_USER || "SYSTEM";
    const dbPassword = process.env.ORACLE_PASSWORD || "admin";

    const connectConfig = {
      user: dbUser,
      password: dbPassword,
      connectString: `${dbHost}:${dbPort}/${dbService}`,
    };

    connection = await oracledb.getConnection(connectConfig);

    const result = await connection.execute(
      `SELECT employee_id, first_name, last_name, email FROM employees WHERE ROWNUM <= 25`, // Assuming your table is named 'EMPLOYEES'
    );

    console.log(
      "\nEmployee ID | First Name           | Last Name             | Email",
    );
    console.log(
      "------------|----------------------|-----------------------|-------------------------",
    );

    for (const row of result.rows) {
      const employeeId = row[0];
      const firstName = row[1];
      const lastName = row[2];
      const email = row[3];
      console.log(
        `${employeeId.toString().padEnd(12)}| ${firstName.padEnd(21)}| ${lastName.padEnd(21)}| ${email}`,
      );
    }
  } catch (err) {
    console.error("Error connecting to or querying Oracle:", err);
  } finally {
    if (connection) {
      try {
        await connection.close();
      } catch (err) {
        console.error("Error closing connection:", err);
      }
    }
  }
}

run();
```

Toujours dans la console, dans le dossier `/tmp/oracle/nodejs`, construisez l'image Docker et lancez le container (et donc le script) : `clear ; docker build -t oracle-nodejs . && docker run --rm -it --network oracle oracle-nodejs`.

![Utiliser NodeJS pour accéder à la liste des employés](./images/using_nodejs.webp)

Sympa ! Comme vous pouvez le voir, on accède assez facilement à notre base Oracle avec NodeJS.

## Accéder à notre container Oracle DB avec PHP {#access-our-oracle-db-container-using-php}

Et, dernier par ordre alphabétique ; terminons avec un container PHP :

```bash
$ mkdir -p /tmp/oracle/php && cd $_
```

Et là, créons un Dockerfile :

**Dockerfile**

```docker
# cspell:ignore instantclient,libaio1,libncurses5,libreadline8,ldconfig,pecl

FROM php:fpm

RUN apt-get update && apt-get install -y --no-install-recommends \
    libaio1 \
    libncurses5 \
    libreadline8 \
    locales \
    unzip \
    && rm -rf /var/lib/apt/lists/*

RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

ARG ORACLE_INSTANT_CLIENT_VERSION=21.12

# Downloading Oracle Instant Client
RUN curl -o /tmp/instantclient-basic.zip -L "https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip" \
    && curl -o /tmp/instantclient-sdk.zip -L "https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip" \
    && mkdir -p /usr/lib/oracle \
    && unzip -o /tmp/instantclient-basic.zip -d /usr/lib/oracle \
    && unzip -o /tmp/instantclient-sdk.zip -d /usr/lib/oracle \
    && rm /tmp/*.zip \
    && ln -s /usr/lib/oracle/instantclient_* /usr/lib/oracle/instantclient \
    && sh -c "echo /usr/lib/oracle/instantclient > /etc/ld.so.conf.d/oracle-instantclient.conf" \
    && ldconfig

# Install OCI8 Extension
RUN echo 'instantclient,/usr/lib/oracle/instantclient' | pecl install oci8 \
    && docker-php-ext-enable oci8

WORKDIR /app

COPY main.php .

CMD [ "php", "main.php" ]
```

Créons ensuite un script PHP (*généré avec l'IA*)

**main.php**

```php
<?php

declare(strict_types=1);

// cspell:ignore orclpdb1,rownum,sqlt

$dbUser = "system";
$dbPassword = "admin";
$dbHost = "oracle-db";
$dbPort = "1521";
$dbServiceName = "orclpdb1";

$connection = null;
$statement = null;

try {
    $dsn = "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={$dbHost})(PORT={$dbPort})))(CONNECT_DATA=(SERVICE_NAME={$dbServiceName})))";

    /** @var resource|false $connection */
    $connection = oci_connect($dbUser, $dbPassword, $dsn, "");

    if (!$connection) {
        $e = oci_error();
        throw new Exception("Error connecting to Oracle: " . $e['message']);
    }

    $sql = "SELECT employee_id, first_name, last_name, email FROM system.employees WHERE ROWNUM <= :max_rows";

    /** @var resource|false $statement */
    $statement = oci_parse($connection, $sql);

    if (!$statement) {
        $e = oci_error($connection);
        throw new Exception("Error parsing SQL statement: " . $e['message']);
    }

    $numRows = 25;
    oci_bind_by_name($statement, ":max_rows", $numRows, SQLT_INT);

    $result = oci_execute($statement);

    if (!$result) {
        $e = oci_error($statement);
        throw new Exception("Error executing SQL statement: " . $e['message']);
    }

    echo "Employee ID | First Name          | Last Name           | Email\n";
    echo str_repeat("-", 80) . "\n";

    while (($row = oci_fetch_array($statement, OCI_ASSOC + OCI_RETURN_NULLS)) !== false) {
        $employeeId = (int) $row['EMPLOYEE_ID'];
        $firstName = $row['FIRST_NAME'];
        $lastName = $row['LAST_NAME'];
        $email = $row['EMAIL'];
        printf("%-12d| %-20s| %-20s| %-26s\n", $employeeId, $firstName, $lastName, $email);
    }

} catch (Exception $exception) {
    echo "Error: " . $exception->getMessage() . "\n";
} finally {
    if (is_resource($statement)) {
        oci_free_statement($statement);
    }
    if (is_resource($connection)) {
        oci_close($connection);
    }
}

?>
```

Toujours dans la console, dans le dossier `/tmp/oracle/php`, construisez l'image Docker et lancez le container (et donc le script) : `clear ; docker build -t oracle-php . && docker run --rm -it --network oracle oracle-php`.

![Utiliser PHP pour accéder à la liste des employés](./images/using_php.webp)

## Accéder à notre container Oracle DB avec Python {#access-our-oracle-db-container-using-python}

Créons maintenant un script Python :

```bash
$ mkdir -p /tmp/oracle/python && cd $_
```

Et son Dockerfile ; la seule chose dont nous avons besoin (à part Python) est d'installer la dépendance `oracledb`. Plutôt simple.

**Dockerfile**

```docker
# cspell:ignore oracledb

FROM python:slim

WORKDIR /app

RUN pip install --no-cache-dir oracledb

COPY main.py main.py

CMD ["python", "main.py"]
```

Créons ensuite un script Python (*généré avec l'IA*)

**main.py**

```python
from typing import Optional, Tuple, List

import oracledb

# cspell:ignore oracledb,orclpdb1,sysdba,rownum

DB_USER: str = "SYS"
DB_PASSWORD: str = "admin"
DB_HOST: str = "oracle-db"
DB_PORT: int = 1521
DB_SERVICE_NAME: str = "orclpdb1"

connection: Optional[oracledb.Connection] = None
cursor: Optional[oracledb.Cursor] = None

try:
    dsn: str = f"{DB_HOST}:{DB_PORT}/{DB_SERVICE_NAME}"

    connection = oracledb.connect(
        user=DB_USER,
        password=DB_PASSWORD,
        dsn=dsn,
        mode=oracledb.AuthMode.SYSDBA,
    )

    cursor = connection.cursor()

    sql: str = (
        "SELECT employee_id, first_name, last_name, email "
        "FROM system.employees "
        "WHERE ROWNUM <= :max_rows"
    )

    num_rows: int = 25
    cursor.execute(sql, max_rows=num_rows)

    records: List[Tuple[int, str, str, str]] = cursor.fetchall()

    print("Employee ID | First Name          | Last Name           | Email")
    print("-" * 80)

    employee_id: int
    first_name: str
    last_name: str
    email: str

    for record in records:
        employee_id, first_name, last_name, email = record
        print(f"{employee_id:<12}| {first_name:<20}| {last_name:<20}| {email:<26}")

except oracledb.Error as exception:
    print(f"Error connecting to Oracle: {exception}")

finally:
    if cursor:
        try:
            cursor.close()
        except oracledb.Error as exception:
            print(f"Error closing cursor: {exception}")
    if connection:
        try:
            connection.close()
        except oracledb.Error as exception:
            print(f"Error closing connection: {exception}")
```

Toujours dans la console, dans le dossier `/tmp/oracle/python`, construisez l'image Docker et lancez le container (et donc le script) : `clear ; docker build -t oracle-python . && docker run --rm -it --network oracle oracle-python`.

![Utiliser Python pour accéder à la liste des employés](./images/using_python.webp)

Sympa ! Comme vous pouvez le voir, on accède assez facilement à notre base Oracle avec Python.

## Conclusion {#conclusion}

Vous savez quoi ? J'ai plus de 15 ans d'expérience avec PHP et seulement 6 mois avec Python et, si on regarde le Dockerfile des deux langages, aucun doute possible : celui de Python est tellement plus simple à lire et à configurer. J'ai eu beaucoup de mal à faire fonctionner celui de PHP, et aucune difficulté avec Python puisqu'il s'agit d'une seule dépendance à installer, et c'est tout.

Et si on compare le code PHP et le code Python, ils sont assez similaires mais, je dois l'admettre, celui de Python a ma préférence : pas besoin de vérifier les erreurs à plusieurs endroits, on peut définir plus facilement les types de données des variables, l'instruction echo est plus lisible, ...
