emacs.d/clones/clojure-doc.org/articles/ecosystem/java_jdbc/reusing_connections.html
2022-08-24 19:36:32 +02:00

289 lines
17 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8"/>
<title>Clojure Guides: java.jdbc - How to reuse database connections</title>
<meta name="description" content="Contents">
<meta property="og:description" content="Contents">
<meta property="og:url" content="https://clojure-doc.github.io/articles/ecosystem/java_jdbc/reusing_connections/" />
<meta property="og:title" content="java.jdbc - How to reuse database connections" />
<meta property="og:type" content="article" />
<link rel="canonical" href="https://clojure-doc.github.io/articles/ecosystem/java_jdbc/reusing_connections/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Alegreya:400italic,700italic,400,700" rel="stylesheet"
type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.7.0/styles/default.min.css">
<link href="../../../css/screen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="../../../index.html">Clojure Guides</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li ><a href="../../../index.html">Home</a></li>
<li><a href="https://github.com/clojure-doc/clojure-doc.github.io">Contribute</a></li>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</nav>
<div class="container">
<div class="row">
<div class="col-lg-9">
<div id="content">
<div id="custom-page">
<div id="page-header">
<h2>java.jdbc - How to reuse database connections</h2>
</div>
<h2 id="contents">Contents</h2><ul><li><a href="home.html">Overview</a></li><li><a href="using_sql.html">Using SQL</a></li><li><a href="using_ddl.html">Using DDL</a></li><li><a href="reusing_connections.html">Reusing Connections</a></li></ul><h2 id="reusing-connections">Reusing Connections</h2><p>Since you rarely want every database operation to create a new connection,
there are two ways to reuse connections:</p><ul><li>Grouping Operations using <code>with-db-connection</code>: If you don't want to deal
with a connection pooling library, you can use this macro to automatically open a
connection and maintain it for a body of code, with each operation executed in its
own transaction, then close the connection.</li><li>Grouping Operations using <code>with-db-transaction</code>: If you want to execute multiple
operations in a single transaction, you can use this macro to automatically open a
connection, start a transaction, execute multiple operations, commit the transaction,
and then close the connection.</li><li>Connection Pooling: This is the recommended approach and is fairly
straightforward, with a number of connection pooling libraries available. See
<em>How To Use Connection Pooling</em> below for more information.</li></ul><h2 id="using-with-db-connection">Using <code>with-db-connection</code></h2><p>This macro provides the simplest way to reuse connections, without having to
add a dependency on an external connection pooling library:</p><pre><code class="clojure">(ns dbexample
(:require [clojure.java.jdbc :as jdbc]))
(def db-spec ... ) ;; see above
(jdbc/with-db-connection [db-con db-spec]
(let [;; fetch some rows using this connection
rows (jdbc/query db-con ["SELECT * FROM table WHERE id = ?" 42])]
;; insert a copy of the first row using the same connection
(jdbc/insert! db-con :table (dissoc (first rows) :id))))
</code></pre><p>The <code>query</code> and the <code>insert!</code> are each run in their own transaction and committed
if they succeed. If you want to run multiple operations in a single transaction
see the next section about <code>with-db-transaction</code>.</p><h2 id="using-with-db-transaction">Using <code>with-db-transaction</code></h2><p>This macro provides a way to reuse connections, committing or rolling back
multiple operations in a single transaction:</p><pre><code class="clojure">(ns dbexample
(:require [clojure.java.jdbc :as jdbc]))
(def db-spec ... ) ;; see above
(jdbc/with-db-transaction [t-con db-spec]
(let [;; fetch some rows using this connection
rows (jdbc/query t-con ["SELECT * FROM table WHERE id = ?" 42])]
;; insert a copy of the first row using the same connection
(jdbc/insert! t-con :table (dissoc (first rows) :id))))
</code></pre><p>If any operation inside <code>with-db-transaction</code> fails (throws an exception), then
all of the operations performed so far are rolled back. If all the operations
succeed, then the entire transaction is committed.</p><p>Transactions are not nested (since not all databases support that) so if this is
used another active transaction, the outer transaction (and connection) are used
as-is. If the isolation levels of the outer and inner transaction do not match
you will get an <code>IllegalStateException</code>.</p><p>See also <code>db-set-rollback-only!</code>, <code>db-unset-rollback-only!</code>, and <code>db-is-rollback-only</code>
for additional control over the commit/rollback behavior of the enclosing transaction.</p><h2 id="using-connection-pooling">Using Connection Pooling</h2><p><code>java.jdbc</code> does not provide connection pooling directly but it is relatively
easy to add to your project. There are several connection pooling libraries out
there, but here we will provide instructions for the popular <code>c3p0</code> library.</p><p>The basic idea is to add your chosen connection pooling library to your
project, import the appropriate class(es), define a function that consumes a
"database spec" and produces a map containing a <code>:datasource</code> key whose value
is the constructed pooled <code>DataSource</code> object, then use that hash map in place of your
bare <code>db-spec</code> variable. You are responsible for creating the pooled data
source object and passing the map containing it into any functions that need a
database connection.</p><h3 id="using-the-c3p0-library">Using the c3p0 library</h3><p>For more information on c3p0, consult the <a href="http://www.mchange.com/projects/c3p0/">c3p0
documentation</a>.</p><p>If you're using Leiningen, you can add the following to your dependencies:</p><pre><code class="clojure">[com.mchange/c3p0 "0.9.5.2"] ;; check the documentation for latest version
</code></pre><p>For a Maven-based project, you would add:</p><pre><code class="xml">&lt;dependency&gt;
&lt;groupId&gt;com.mchange&lt;/groupId&gt;
&lt;artifactId&gt;c3p0&lt;/artifactId&gt;
&lt;version&gt;0.9.5.2&lt;/version&gt;
&lt;/dependency&gt;
</code></pre><h3 id="create-the-pooled-datasource-from-your-db-spec">Create the pooled datasource from your db-spec</h3><p>Define your <code>db-spec</code> using the long form, for example (for MySQL):</p><pre><code class="clojure">(def db-spec
{:classname "com.mysql.jdbc.Driver"
:subprotocol "mysql"
:subname "//127.0.0.1:3306/mydb"
:user "myaccount"
:password "secret"})
</code></pre><p>We have to use the long form here because c3p0 operates on the class name, subprotocol,
and subname elements. Of course, you don't really need to define a <code>db-spec</code> here
because you're not going to use it with <code>java.jdbc</code> directly, only with c3p0.</p><p>Import the c3p0 class as part of your namespace declaration, for example:</p><pre><code class="clojure">(ns example.db
(:import (com.mchange.v2.c3p0 ComboPooledDataSource)))
</code></pre><p>Define a function that creates a pooled datasource:</p><pre><code class="clojure">(defn pool
[spec]
(let [cpds (doto (ComboPooledDataSource.)
(.setDriverClass (:classname spec))
(.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
(.setUser (:user spec))
(.setPassword (:password spec))
;; expire excess connections after 30 minutes of inactivity:
(.setMaxIdleTimeExcessConnections (* 30 60))
;; expire connections after 3 hours of inactivity:
(.setMaxIdleTime (* 3 60 60)))]
{:datasource cpds}))
</code></pre><p>Now you can create a single connection pool:</p><pre><code class="clojure">(def pooled-db (delay (pool db-spec)))
(defn db-connection [] @pooled-db)
</code></pre><p>And then call <code>(db-connection)</code> wherever you need access to it. If you're using
a <a href="https://github.com/stuartsierra/component">component</a> lifecycle for your
application, you won't need <code>pooled-db</code> or <code>db-connection</code>. You'll just create
<code>(pool db-spec)</code> as part of your application's initialization and pass it
around as part of your system configuration.</p>
<div id="prev-next">
<a href="using_ddl.html">&laquo; java.jdbc - Using DDL and Metadata</a>
||
<a href="../core_typed/home/index.html">core.typed - User Documentation Home &raquo;</a>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div id="sidebar">
<h3>Links</h3>
<ul id="links">
<li><a href="../../about/index.html">About</a></li>
<li><a href="../../content/index.html">Table of Contents</a></li>
<li><a href="../../tutorials/getting_started/index.html">Getting Started with Clojure</a></li>
<li><a href="../../tutorials/introduction/index.html">Introduction to Clojure</a></li>
<li><a href="../../tutorials/emacs/index.html">Clojure with Emacs</a></li>
<li><a href="../../tutorials/vim_fireplace/index.html">Clojure with Vim and fireplace.vim</a></li>
<li><a href="../../tutorials/eclipse/index.html">Starting with Eclipse and Counterclockwise For Clojure Development</a></li>
<li><a href="../../tutorials/basic_web_development/index.html">Basic Web Development</a></li>
<li><a href="../../tutorials/parsing_xml_with_zippers/index.html">Parsing XML in Clojure</a></li>
<li><a href="../../tutorials/growing_a_dsl_with_clojure/index.html">Growing a DSL with Clojure</a></li>
<li><a href="../../language/core_overview/index.html">Overview of clojure.core, the standard Clojure library</a></li>
<li><a href="../../language/namespaces/index.html">Clojure Namespaces and Vars</a></li>
<li><a href="../../language/collections_and_sequences/index.html">Collections and Sequences in Clojure</a></li>
<li><a href="../../language/functions/index.html">Functions in Clojure</a></li>
<li><a href="../../language/laziness/index.html">Laziness in Clojure</a></li>
<li><a href="../../language/interop/index.html">Clojure interoperability with Java</a></li>
<li><a href="../../language/macros/index.html">Clojure Macros and Metaprogramming</a></li>
<li><a href="../../language/polymorphism/index.html">Polymorphism in Clojure: Protocols and Multimethods</a></li>
<li><a href="../../language/concurrency_and_parallelism/index.html">Concurrency and Parallelism in Clojure</a></li>
<li><a href="../../language/glossary/index.html">Clojure Terminology Guide</a></li>
<li><a href="../libraries_directory/index.html">A Directory of Clojure Libraries</a></li>
<li><a href="../libraries_authoring/index.html">Library Development and Distribution</a></li>
<li><a href="../generating_documentation/index.html">Generating Documentation</a></li>
<li><a href="../data_processing/index.html">Data Processing (Help Wanted)</a></li>
<li><a href="../web_development/index.html">Web Development (Overview)</a></li>
<li><a href="../maven/index.html">How to use Maven to build Clojure projects</a></li>
<li><a href="../community/index.html">Clojure Community</a></li>
<li><a href="../user_groups/index.html">Clojure User Groups</a></li>
<li><a href="../running_cljug/index.html">Running a Clojure User Group</a></li>
<li><a href="../books/index.html">Books about Clojure and ClojureScript</a></li>
<li><a href="../../cookbooks/data_structures/index.html">Data Structures (Help wanted)</a></li>
<li><a href="../../cookbooks/strings/index.html">Strings</a></li>
<li><a href="../../cookbooks/math/index.html">Mathematics with Clojure</a></li>
<li><a href="../../cookbooks/date_and_time/index.html">Date and Time (Help wanted)</a></li>
<li><a href="../../cookbooks/files_and_directories/index.html">Working with Files and Directories in Clojure</a></li>
<li><a href="../../cookbooks/middleware/index.html">Middleware in Clojure</a></li>
<li><a href="home.html">java.jdbc - Getting Started</a></li>
<li><a href="using_sql.html">java.jdbc - Manipulating data with SQL</a></li>
<li><a href="using_ddl.html">java.jdbc - Using DDL and Metadata</a></li>
<li><a href="reusing_connections.html">java.jdbc - How to reuse database connections</a></li>
<li><a href="../core_typed/home/index.html">core.typed - User Documentation Home</a></li>
<li><a href="../core_typed/user_documentation/index.html">core.typed - User Documentation</a></li>
<li><a href="../core_typed/rationale/index.html">core.typed - Rationale</a></li>
<li><a href="../core_typed/quick_guide.html">core.typed - Quick Guide</a></li>
<li><a href="../core_typed/start/introduction_and_motivation/index.html">core.typed - Getting Started: Introduction and Motivation</a></li>
<li><a href="../core_typed/types/index.html">core.typed - Types</a></li>
<li><a href="../core_typed/start/annotations/index.html">core.typed - Annotations</a></li>
<li><a href="../core_typed/poly_fn/index.html">core.typed - Polymorphic Functions</a></li>
<li><a href="../core_typed/filters/index.html">core.typed - Filters</a></li>
<li><a href="../core_typed/mm_protocol_datatypes/index.html">core.typed - Protocols</a></li>
<li><a href="../core_typed/loops/index.html">core.typed - Looping constructs</a></li>
<li><a href="../core_typed/function_types/index.html">core.typed - Functions</a></li>
<li><a href="../core_typed/limitations/index.html">core.typed - Limitations</a></li>
</ul>
</div>
</div>
</div>
<footer>Copyright &copy; 2021 Multiple Authors
<p style="text-align: center;">Powered by <a href="http://cryogenweb.org">Cryogen</a></p></footer>
</div>
<script src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="../../../js/highlight.pack.js" type="application/javascript"></script>
<script>hljs.initHighlightingOnLoad();</script>
</body>
</html>