OpenLiberty / docs

See Open Liberty documentation on https://openliberty.io/docs/
https://openliberty.io/docs/
Other
13 stars 47 forks source link

Relational Database Connectivity Overview #2867

Closed aguibert closed 1 year ago

aguibert commented 4 years ago

Relational databases are a very common part of many applications. This article describes how to configure your server to interact with a relational database.

JDBC driver library configuration

Connectivity with a relational database requires a JDBC driver, which is typically provided by the database vendor. JDBC drivers allow you to define data sources, from which you obtain connections to the database. In order to configure a JDBC data source in Liberty server configuration, you must enable one of the JDBC features and configure a <library> containing your JDBC driver jar:

<featureManager>
    <feature>jdbc-4.2</feature>
</featureManager>

<library id="jdbcLib">
    <fileset dir="${server.config.dir}/jdbc" includes="*.jar"/>
</library>

To be usable in Liberty, your JDBC driver must provide at least one of these types of data sources or must provide a java.sql.Driver with the ServiceLoader facility:

For the commonly used JDBC drivers, Liberty is already aware of the implementation class names for the various data source types. In most cases, you only need to tell Liberty where to find the JDBC driver.

If you use Maven to build your application, you can download and deploy the JDBC driver to the proper location using pom.xml configuration similar to the following:

      <plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.3-M2</version>
        <configuration>
          <!-- Copies the 'com.ibm.db2:jcc:11.5.4.0' dependency to ${server.config.dir}/jdbc at build time -->
          <copyDependencies>
            <dependency>
              <filter>com.ibm.db2:jcc:11.5.4.0</filter>
              <location>jdbc</location>
            </dependency>
          </copyDependencies>
        </configuration>
      </plugin>

Data source configuration

Any JDBC compliant driver may be configured with Liberty. Liberty also has built-in configuration of commonly used database types. The general pattern for configuring a DataSource in Liberty follows the following pattern:

<library id="jdbcLib">
    <fileset dir="${server.config.dir}/jdbc" includes="*.jar"/>
</library>

<dataSource id="myDB" jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties serverName="localhost" portNumber="5432"
                databaseName="myDB"
                user="exampleUser" password="examplePassword"/>
</dataSource>

To use a <dataSource> configured in server.xml, you can inject or lookup the DataSource using one of the following approaches:

Injection (in a web component or enterprise bean component)

@Resource(lookup = "jdbc/myDB")
DataSource myDB;

JNDI lookup (requires the jndi-1.0 feature to be enabled in server.xml)

DataSource myDB = InitialContext.doLookup("jdbc/myDB");

PostgreSQL configuration

JDBC driver available at: https://mvnrepository.com/artifact/org.postgresql/postgresql

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.postgresql serverName="localhost" portNumber="5432"
                databaseName="myDB"
                user="exampleUser"
                password="examplePassword"/>
</dataSource>

To run a Postgres Docker container locally, run the command:

docker run -it --rm=true --memory-swappiness=0 --ulimit memlock=-1:-1 \
           --name postgres-liberty \
           -e POSTGRES_USER=exampleUser \
           -e POSTGRES_PASSWORD=examplePassword \
           -e POSTGRES_DB=myDB \
           -p 5432:5432 \
           postgres:10.5

IBM DB2

JDBC driver available at: https://mvnrepository.com/artifact/com.ibm.db2/jcc

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.db2.jcc serverName="localhost" portNumber="50000"
                databaseName="test"
                user="db2inst1"
                password="foobar1234"/>
</dataSource>

To run a DB2 Docker container locally, run the command:

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 \
           --name db2-liberty \
           -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e LICENSE=accept \
           -e DBNAME=test \
           -e DB2INSTANCE=db2inst1 \
           -e DB2INST1_PASSWORD=foobar1234 \
           -p 50000:50000 \
           --privileged \
           ibmcom/db2:11.5.0.0a

Microsoft SQLServer

JDBC driver available at: https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.microsoft.sqlserver serverName="localhost" portNumber="1433"
                databaseName="tempdb"
                user="sa"
                password="examplePassw0rd"/>

</dataSource>

To run a SQL Server Docker container locally, run the command:

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 \
           --name mssql-liberty \
           -e ACCEPT_EULA=Y \
           -e SA_PASSWORD=examplePassw0rd \
           -p 1433:1433 \
           mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04

Oracle

JDBC driver available at: https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.oracle URL="jdbc:oracle:thin:@//localhost:1521/myDB" 
                user="exampleUser"
                password="examplePassword"/>
</dataSource>

MySQL

JDBC driver available at: https://mvnrepository.com/artifact/mysql/mysql-connector-java

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties serverName="localhost" portNumber="3306"
                databaseName="myDb"
                user="exampleUser"
                password="examplePassword"/>
</dataSource>

To run a MySQL Docker container locally, run the command:

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 \
           --name mysql-liberty \
           -e MYSQL_DATABASE=myDB \
           -e MYSQL_USER=exampleUser \
           -e MYSQL_PASSWORD=examplePassword \
           -p 3306:3306 \
           mysql:8

Derby Embedded (in-memory DB)

JDBC driver available at: https://mvnrepository.com/artifact/org.apache.derby/derby/10.14.2.0

Sample data source configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.derby.embedded databaseName="memory:myDB" createDatabase="create"/>
</dataSource>

Generic database unknown to Liberty

Sample data source configuration:

<dataSource id="myDB" jndiName="jdbc/myDB" type="javax.sql.XADataSource">
    <jdbcDriver libraryRef="jdbcLib"
                        javax.sql.XADataSource="com.example.jdbc.SampleXADataSource"/>
    <properties serverName="localhost" portNumber="1234"
                databaseName="myDB"
                user="exampleUser"
                password="examplePassword"/>
</dataSource>

Specify the type of the DataSource using the <dataSource type="..."> attribute, where type can be one of the interface class names described in the "JDBC driver library configuration" section. Then, specify the mapping of interface class name to the driver's implementation of that class on the <jdbcDriver> element as shown above.

Configuring driver-specific data source attributes

Every JDBC driver provides a different collection of attributes that may be configured on its data source implementation classes. As long as the JDBC driver's data source has setter methods with a String or primitive parameter it is possible to configure these attributes in Liberty configuration by following the pattern:

    <properties someProperty="someValue" anotherProperty="5" />

For example, consider the currentLockTimeout attribute on the DB2 JDBC driver's data source classes:

It is possible to configure this setting with the following server.xml configuration:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties serverName="localhost" portNumber="1234" databaseName="myDB"
                user="exampleUser" password="examplePassword"
                currentLockTimeout="30s"/>
</dataSource>

Types of data sources and resolution strategy

To access a database from your application, application code must use the javax.sql.DataSource interface. The application server provides a managed implementation of this javax.sql.DataSource interface, which is backed by one of the various data source or driver implementations that JDBC drivers provide. These data source or driver implementations come in the following varieties:

When the <dataSource type="..."/> attribute is omitted, Liberty chooses the data source type in the following order, depending on which is available.

If you are using the jdbc-4.3 feature or higher or if it is the DefaultDataSource, then Liberty chooses the data source type in the following order, depending on which is available:

If you are using the jdbc-4.2, 4.1, or 4.0 feature and it is not the DefaultDataSource, then Liberty chooses the data source type in the following order, depending on which is available:

It should be noted that the capability that is provided by XADataSource is generally a superset of the capability that is provided by the other data source types, although some JDBC vendors might have subtle differences in behavior or introduce different limitations between the various data source types that are not spelled out in the JDBC specification.

Configuring a default data source

If you enable any Java EE or Jakarta EE features it is possible to configure a default data source. To configure a default data source, set the ID of the <dataSource> element to DefaultDataSource. For example:

<dataSource id="DefaultDataSource">
    <!-- properties and jdbcDriver -->
</dataSource>

When a default data source is configured, a reference can be obtained in either of the following ways:

Injection

@Resource
DataSource myDB;

JNDI lookup (requires the jndi-1.0 feature to be enabled in server.xml)

DataSource myDB = InitialContext.doLookup("java:comp/DefaultDataSource");

Configuring the connection pool

Every <dataSource> element may have an optional <connectionManager> element nested inside of it. By default, the connection manager for each <dataSource> element has sensible default values, but can be customized if needed. For example:

<dataSource jndiName="jdbc/myDB">
  <jdbcDriver libraryRef="jdbcLib"/>
  <connectionManager maxPoolSize="10" minPoolSize="2"/>
  <properties ... />
</dataSource>

For complete details on <connectionManager> configuration attributes, refer to this page: https://openliberty.io/docs/20.0.0.10/reference/config/connectionManager.html

Validating JDBC Connections

Once you have configured your data source, you may want to quickly test the configuration to see if your Liberty server can access your database. To do this, refer to the "Testing database connections" topic here: https://draft-openlibertyio.mybluemix.net/docs/20.0.0.11/testing-database-connections.html

dmuelle commented 4 years ago

Thanks @aguibert - this looks good. I can work on an asciidoc draft for your review on the OL draft site. I can see a few tweaks to make per ID guidelines and a couple blanks I will probably need help filling in due to my limited familiarity with the subject.

One question I have is about the example configs for different datasources- Are the examples you give here just a template that I should fill out with the values in the KC topic? I see some database-specific example values there that are not in your PostgreSQL example.

I also notice that topic doesn't mention the docker command- is that for development environments where there you'd want to run the db in a local container for testing purposes?

aguibert commented 4 years ago

@dmuelle don't port this to asciidoc quite yet please. I'm still soliciting feedback from other SMEs in this area and have just made the first round of updates a few minutes ago, but there will likely be a few more edits.

One question I have is about the example configs for different datasources- Are the examples you give here just a template that I should fill out with the values in the KC topic? I see some database-specific example values there that are not in your PostgreSQL example.

I have example configs for each DB, I'll fill them in now since the other SMEs seem to be happy with the overall structure of the article.

I also notice that topic doesn't mention the docker command- is that for development environments where there yopu'd want to run the db in a local container for testing purposes?

Yes, the docker commands are very handy for local development. I've copied this information from my cheat sheet here: https://aguibert.github.io/openliberty-cheat-sheet/#_postgresql

dmuelle commented 3 years ago

@aguibert initial draft is now available for review at https://draft-openlibertyio.mybluemix.net/docs/20.0.0.12/relational-database-connections-JDBC.html

aguibert commented 3 years ago

Thanks for putting this together @dmuelle !

Review comments:

dmuelle commented 3 years ago

@aguibert thanks for reviewing! I made the following edits per your comments:

dmuelle commented 3 years ago

from @aguibert via slack:

Lets just use dir="jdbc" then. Using server1/jdbc is misleading because if a relative path is specified, then it is relative to ${server.config.dir}, meaning that server1/jdbc would evaluate to ${server.config.dir}/server1/jdbc and it would be strange if someone had a server1 folder in their server folder.

however, I think we should be allowed to use built-in variables like ${server.config.dir} in config docs @lauracowen, because it makes it more clear where the dir actually is. Not everyone knows that if you specify dir="jdbc" that it's relative to ${server.config.dir}

I've updated the example to just use dir="jdbc"

dmuelle commented 3 years ago

@lauracowen this is ready for your review

https://draft-openlibertyio.mybluemix.net/docs/20.0.0.12/relational-database-connections-JDBC.html

dmuelle commented 3 years ago

See issue #369 re default data source config example on the JDBC feature page- should the example go both on that page and in this doc?

lauracowen commented 3 years ago

In general, looks good. Some specific comments:

dmuelle commented 3 years ago

Thanks for reviewing @lauracowen. I've made edits for the following items, will break out the stuff that needs @aguibert input into a separate comment and address there.

dmuelle commented 3 years ago

Hi @aguibert - Laura and I had a couple questions re this draft:

Is the reference here to a generic example of a database that liberty doesn't recognize, or is it specifically about a generic database? If the latter, I can include a brief clarification of the term

aguibert commented 3 years ago

Where it says to get the driver from Maven Central, should that be "Download the xxx driver" rather than "Get"?

To me "Download" implies manually downloading. I think "Get" is a fine term to use here because on the front page of openliberty.io we have a "Get Open Liberty" button which links to the downloads page with instructions for getting in image using maven/gradle/docker/zip.

With the docker commands, I can see how they're useful in themselves but does the user have to have a particular docker container image for them to work?

Not entirely sure what you mean here, but by running those commands you get a container for that particular database. Also, the exact params in the docker command pair with the corresponding server.xml config snippets I've shown. So for example to get up and running with a DB2 database and configure their Liberty server to use it, they just run the command:

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 \
           --name db2-liberty \
           -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e LICENSE=accept \
           -e DBNAME=test \
           -e DB2INSTANCE=db2inst1 \
           -e DB2INST1_PASSWORD=foobar1234 \
           -p 50000:50000 \
           --privileged \
           ibmcom/db2:11.5.0.0a

which will start up a DB2 container instance on the developer's machine that they can connect to with user=db2inst1 and password=foobar1234 and so they can paste the XML config snippet into their server.xml to talk to that container:

<dataSource jndiName="jdbc/myDB">
    <jdbcDriver libraryRef="jdbcLib"/>
    <properties.db2.jcc serverName="localhost" portNumber="50000"
                databaseName="test"
                user="db2inst1"
                password="foobar1234"/>
</dataSource>

"Generic database that is unknown to Open Liberty" - this doesn't feel like a "common configuration". ... even if it's unknown to Liberty is surely not "generic" - the configuration template we provide is generic, not the database itself?

I'm fine with changing the heading to Configuring databases that are unknown to Open Liberty as you suggest. And yes, the database itself is not "generic", we are instead showing a more generic way to configure a database. FYI the original source for this section is from the For a JDBC driver that is not known to Liberty section of this page: https://www.ibm.com/support/knowledgecenter/SSD28V_liberty/com.ibm.websphere.wlp.core.doc/ae/twlp_dep_configuring_ds.html

Is the reference here to a generic example of a database that liberty doesn't recognize, or is it specifically about a generic database?

A database that liberty doesn't recognize. Even if Liberty does know about it (e.g. DB2) you can still configure a datasource using the "generic way" (although the config is more verbose)

Does OL choose from these options, or look for databases of each type in the given order until it finds one and stops looking? Also- is a dev even likely to need to know this?

OL looks for these datasource types in the given order until it finds one. A dev probably would not need to know this info, but I think it's important enough that it should be documented

lauracowen commented 3 years ago

@aguibert

To me "Download" implies manually downloading. I think "Get" is a fine term to use here because on the front page of openliberty.io we have a "Get Open Liberty" button which links to the downloads page with instructions for getting in image using maven/gradle/docker/zip. That was what I was asking really. By "Get", do you mean they should get it by adding it into their Maven pom.xml rather than by manual download? It wasn't clear to me in reading that section what you expected the reader to do with the information and, if they should be adding it to their pom.xml, should we explicitly say that?

dmuelle commented 3 years ago

Thanks @lauracowen @aguibert , made the following updates to the draft

lauracowen commented 3 years ago
aguibert commented 3 years ago

Minor thing but should "Default data source configuration" heading be "Configuration of a default data source"? I read it as a default configuration (in which case I wondered why you were even telling me about it) but actually it's about setting a default data source.

I think either Default data source configuration or Configuration of the default data source would be correct (notice a --> the since there can only be one default data source)

Should "Data source types" be a lower-level heading beneath the "unknown to OL" section (like it was before)? Or is it applicable beyond just doing a generic configuration?

It is generally applicable

dmuelle commented 3 years ago

Thanks @lauracowen @aguibert - I made the following changes to the draft:

lauracowen commented 3 years ago

Thanks - signing off.

Charlotte-Holt commented 3 years ago

@dmuelle Looks great!

Peer review feedback

Data source configuration

Common data source configuration examples

Data source types

Application configuration for relational database connections

dmuelle commented 3 years ago

Thanks for reviewing @Charlotte-Holt , I have updated the file per your suggestions above, with the exception being for Oracle UCP I realized the property was actually just user instead of username, so I made that change accordingly. Also had to shuffle a few sentences around to avoid acrolinx word length restrictions.

dmuelle commented 3 years ago

Doc is now on vNext branch, will publish with 20.0.0.12 on 11.20

Draft link: https://draft-openlibertyio.mybluemix.net/docs/latest/relational-database-connections-JDBC.html

lfielke commented 3 years ago

Some constructive criticism, for this page if I may: I had some trouble following this documentation page using the Open Liberty Gradle plugin. The page talks about using the Maven plugin to copy dependencies to the server config directory, however it doesn't mention the Gradle plugin.

We're already using Gradle to build our other projects, so I went searching for more information. I did find a blog post at https://openliberty.io/blog/2021/02/18/dev-mode-container-liberty-maven-gradle-plugins.html that describes that:

In this blog post, we introduce the general availability of container support in dev mode and support for copying dependencies. Both of these new capabilities are included in the latest releases of the Liberty Maven and Gradle Plug-ins.

Based on this I thought there should be a way to configure the Gradle plugin to copy dependencies. I couldn't find any examples of this in the docs or elsewhere on the web, so I opened an issue https://github.com/OpenLiberty/ci.gradle/issues/619 to see if I had overlooked this. The suggestion was to use a Gradle copy task to achieve this, which makes sense because it's easy to add ad-hoc Gradle tasks to a build.

So reflecting on this, I humbly suggest a couple of things to help steer new users in the right direction:

For reference, the docs page I'm referring to is: https://openliberty.io/docs/21.0.0.7/relational-database-connections-JDBC.html#_jdbc_driver_library_configuration However the version 21.0.0.7 docs don't seem to be available currently, but the version 21.0.0.6 page seems to be the same.

dmuelle commented 3 years ago

Thanks so much for this feedback @lfielke- I've opened a new issue #4446 to track the work to update the page with this information asap.

dmuelle commented 1 year ago

https://openliberty.io/docs/latest/relational-database-connections-JDBC.html

dmuelle commented 1 year ago

Edited content is on vNext and will publish with 23.0.0.9. Closing as completed.