Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 86866e2

Browse files
committed
Merge branch 'master' of github.com:clojure-cookbook/clojure-cookbook
2 parents 697ad7f + 69acd7d commit 86866e2

File tree

37 files changed

+1745
-1594
lines changed

37 files changed

+1745
-1594
lines changed

.license-assignments/nbessi.md

Lines changed: 1 addition & 84 deletions
Large diffs are not rendered by default.

databases/SQL-database-connection-pooling/SQL-database-connection-pooling.asciidoc

Lines changed: 78 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,72 +5,82 @@ by Tom Hicks and Filippo Diotalevi
55

66
==== Problem
77

8-
You would like to connect to an SQL database efficiently using a connection pool.
8+
You would like to connect to an SQL database efficiently using a
9+
connection pool.
910

1011
==== Solution
1112

12-
Use the +BoneCP+ connection and statement pooling library to wrap your JDBC-based
13-
drivers, creating a pooled data source. The pooled data source is then usable
14-
by the +clojure.java.jdbc+ library, as described in the
15-
<<sec_db_connecting_to_a_sql_database>> recipe.
13+
Use the BoneCP connection and statement pooling library to wrap your
14+
JDBC-based drivers, creating a pooled data source. The pooled data
15+
source is then usable by the +clojure.java.jdbc+ library, as described
16+
in the <<sec_db_connecting_to_a_sql_database>> recipe.
1617

17-
Add a dependency to your Leiningen project file for the +BoneCP+ library. You
18-
will also need to add dependencies for the +clojure.java.jdbc+ library and the
19-
JDBC library used with the RDBMS you are connecting to (e.g. MySQL):
18+
[NOTE]
19+
====
20+
You'll need a running SQL database and existing table to connect to
21+
for this recipe. We suggest PostgreSQL.
2022
21-
[source,clojure]
23+
If you're a Mac user and don't have PostgreSQL installed yet, you can
24+
go here http://postgresapp.com/ for an easy to use DMG.
25+
26+
After you have PostgreSQL running (presumably on _localhost:5432_) run
27+
the following command to create a database for this recipe:
28+
29+
[source,bash]
2230
----
23-
:dependencies [ ; ...
24-
[org.clojure/java.jdbc "0.3.0-alpha4"]
25-
[mysql/mysql-connector-java "5.1.25"]
26-
[com.jolbox/bonecp "0.7.1.RELEASE"]
31+
$ /Applications/Postgres.app/Contents/MacOS/bin/createdb cookbook_experiments
2732
----
33+
====
2834

29-
In your +project.clj+ file, and import the +BoneCP+ classes you intend to use:
35+
Before starting, add the BoneCP dependency (`[com.jolbox/bonecp
36+
"0.8.0.RELEASE"]`), as well as the appropriate JDBC libraries for your
37+
RDBMS, to your project's dependencies. You'll also need a valid SLF4J
38+
logger. Alternatively, you can follow along in a REPL using lein-try:
3039

31-
[source,clojure]
40+
[source,shell]
3241
----
33-
(ns myproj.core
34-
(:require [clojure.java.jdbc :as jdbc]
35-
[clojure.java.jdbc.sql :as sql])
36-
(:import com.jolbox.bonecp.BoneCPDataSource))
42+
$ lein try com.jolbox/bonecp "0.8.0.RELEASE" \
43+
org.clojure/java.jdbc "0.3.0-beta1" \
44+
postgresql/postgresql "8.4-702.jdbc4" \
45+
org.slf4j/slf4j-nop # Just don't log anything...
3746
----
3847

39-
40-
Create a database specification containing the parameters for accessing the
41-
database:
48+
First, create a database specification containing the parameters for
49+
accessing the database. This includes keys for the initial and maximum
50+
pool sizes, as well as the number of partitions.
4251

4352
[source,clojure]
4453
----
45-
(def db-spec {:classname "com.mysql.jdbc.Driver"
46-
:subprotocol "mysql"
47-
:subname "//localhost:3306/lotr_db"
48-
:user "bilbo"
49-
:password "secret"
54+
(def db-spec {:classname "org.postgresql.Driver"
55+
:subprotocol "postgresql"
56+
:subname "//localhost:5432/cookbook_experiments"
5057
:init-pool-size 4
5158
:max-pool-size 20
5259
:partitions 2})
5360
----
5461

55-
Define a function (for convenience) which uses the parameters in the database
56-
specification map to create a pooled data source.
62+
To create a pooled +BoneCPDataSource+ object define a function (for
63+
convenience) which uses the parameters in the database
64+
specification map.
5765

5866
[source,clojure]
5967
----
68+
(import 'com.jolbox.bonecp.BoneCPDataSource)
69+
6070
(defn pooled-datasource [db-spec]
61-
(let [ {:keys [classname subprotocol subname user password
62-
init-pool-size max-pool-size idle-time partitions]} db-spec
71+
(let [{:keys [classname subprotocol subname user password
72+
init-pool-size max-pool-size idle-time partitions]} db-spec
6373
cpds (doto (BoneCPDataSource.)
64-
(.setDriverClass classname)
65-
(.setJdbcUrl (str "jdbc:" subprotocol ":" subname))
66-
(.setUsername user)
67-
(.setPassword password)
68-
(.setMinConnectionsPerPartition (inc (int (/ init-pool-size partitions))))
69-
(.setMaxConnectionsPerPartition (inc (int (/ max-pool partitions))))
70-
(.setPartitionCount partitions)
71-
(.setStatisticsEnabled true)
72-
(.setIdleMaxAgeInMinutes (or idle-time 60))
73-
{:datasource cpds} ))
74+
(.setDriverClass classname)
75+
(.setJdbcUrl (str "jdbc:" subprotocol ":" subname))
76+
(.setUsername user)
77+
(.setPassword password)
78+
(.setMinConnectionsPerPartition (inc (int (/ init-pool-size partitions))))
79+
(.setMaxConnectionsPerPartition (inc (int (/ max-pool-size partitions))))
80+
(.setPartitionCount partitions)
81+
(.setStatisticsEnabled true)
82+
(.setIdleMaxAgeInMinutes (or idle-time 60)))]
83+
{:datasource cpds}))
7484
----
7585

7686
Use the convenience function to define a pooled data source for connecting to
@@ -79,27 +89,43 @@ your database:
7989
[source,clojure]
8090
----
8191
(def pooled-db-spec (pooled-datasource db-spec))
92+
93+
pooled-db-spec
94+
;; -> {:datasource #<BoneCPDataSource ...>}
8295
----
8396

84-
Pass the database specification as the first argument to several of the
85-
library's other functions which query and manipulate your database.
97+
Pass the database specification as the first argument to any
98+
+clojure.java.jdbc+ functions that query or manipulate your database.
8699

87100
[source,clojure]
88101
----
89-
(jdbc/insert! pooled-db-spec :players
90-
{:name "Bilbo" :type "hobbit"} {:name "Galadriel" :type "elf"}
91-
{:name "Frodo" :type "hobbit"} {:name "Ori" :type "dwarf"})
92-
;; -> (nil nil nil nil)
93-
94-
(jdbc/query pooled-db-spec (sql/select * :players (sql/where {:type "hobbit"})))
95-
;; -> ({:type "hobbit", :name "Bilbo"} {:type "hobbit", :name "Frodo"})
102+
(require '[clojure.java.jdbc :as jdbc]
103+
'[clojure.java.jdbc.ddl :as ddl]
104+
'[clojure.java.jdbc.sql :as sql])
105+
106+
(jdbc/db-do-commands pooled-db-spec false
107+
(ddl/create-table
108+
:blog_posts
109+
[:id :serial "PRIMARY KEY"]
110+
[:title "varchar(255)" "NOT NULL"]
111+
[:body :text]))
112+
;; -> (0)
113+
114+
(jdbc/insert! pooled-db-spec
115+
:blog_posts
116+
{:title "My first post!" :body "This is going to be good!"})
117+
;; -> ({:body "This is going to be good!", :title "My first post!", :id 1})
118+
119+
(jdbc/query pooled-db-spec
120+
(sql/select * :blog_posts (sql/where{:title "My first post!"})))
121+
;; -> ({:body "This is going to be good!", :title "My first post!", :id 1})
96122
----
97123

98124
==== Discussion
99125

100126
As shown above, the +clojure.java.jdbc+ library can create database
101127
connections from JDBC data sources, which allows connections to be easily
102-
pooled by the +BoneCP+ or other pooling library.
128+
pooled by the +BoneCP+ or other pooling libraries.
103129

104130
The +BoneCP+ library wraps existing JDBC classes to allow the creation of
105131
efficient data sources. It can adapt traditional unpooled drivers and
@@ -124,7 +150,7 @@ in an SQL exception.
124150

125151
[source,clojure]
126152
----
127-
(.close pooled-db-spec)
153+
(.close (:datasource pooled-db-spec))
128154
;; -> nil
129155
----
130156

databases/connecting-to-an-SQL-database/connecting-to-an-SQL-database.asciidoc

Lines changed: 84 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,85 @@ You want to connect your program to an SQL database.
99

1010
==== Solution
1111

12-
Use the +clojure.java.jdbc+ library for JDBC-based access to SQL databases.
12+
Use the +clojure.java.jdbc+ library for JDBC-based access to SQL
13+
databases.
1314

14-
Add a dependency to your Leiningen project file for the +clojure.java.jdbc+
15-
library. You will also need to add a dependency for the JDBC library used
16-
with the RDBMS you are connecting to (e.g. MySQL):
15+
[NOTE]
16+
====
17+
You'll need a running SQL database and existing table to connect to
18+
for this recipe. We suggest PostgreSQL.
1719
18-
[source,clojure]
20+
If you're a Mac user and don't have PostgreSQL installed yet, you can
21+
go here http://postgresapp.com/ for an easy to use DMG.
22+
23+
After you have PostgreSQL running (presumably on _localhost:5432_) run the following
24+
command to create a database for this recipe:
25+
26+
[source,bash]
1927
----
20-
:dependencies [ ; ...
21-
[org.clojure/java.jdbc "0.3.0-alpha4"]
22-
[mysql/mysql-connector-java "5.1.25"] ]
28+
$ /Applications/Postgres.app/Contents/MacOS/bin/createdb cookbook_experiments
2329
----
30+
====
2431

25-
Require the necessary parts of the +clojure.java.jdbc+ library in your Clojure source code:
32+
Before starting, add `[org.clojure/java.jdbc "0.3.0-alpha4"]` to your
33+
project's dependencies. You'll also need a JDBC-driver for the RDBMS
34+
of your choice. If you're following along with this sample, use
35+
`[org.postgresql/postgresql "9.2-1002-jdbc4"]`. To start a REPL using
36+
lein-try, enter the following Leiningen command:
2637

27-
[source,clojure]
38+
[source,shell]
39+
----
40+
$ lein try org.clojure/java.jdbc org.postgresql/postgresql
2841
----
29-
(ns myproj.core
30-
(:require [clojure.java.jdbc :as jdbc]
31-
[clojure.java.jdbc.sql :as sql]))
3242

43+
To interact with a database using +clojure.java.jdbc+, all you need is
44+
a connection specification. This specification takes the form of a
45+
plain Clojure map with values indicating the database driver type,
46+
location and authentication credentials.
47+
48+
[source,clojure]
49+
----
50+
(def db-spec {:classname "org.postgresql.Driver"
51+
:subprotocol "postgresql"
52+
:subname "//localhost:5432/cookbook_experiments"
53+
;; Not needed for a non-secure local database...
54+
;; :user "bilbo"
55+
;; :password "secret"
56+
})
3357
----
3458

35-
Create a database specification containing the parameters for accessing the
36-
database:
59+
Create a relation in the specified database by invoking the
60+
+clojure.java.jdbc/create-table+ function with the specification
61+
and any number of column specifications.
3762

3863
[source,clojure]
3964
----
40-
(def db-spec {:classname "com.mysql.jdbc.Driver"
41-
:subprotocol "mysql"
42-
:subname "//localhost:3306/lotr_db"
43-
:user "bilbo"
44-
:password "secret"})
65+
(require '[clojure.java.jdbc :as jdbc]
66+
'[clojure.java.jdbc.ddl :as ddl])
67+
68+
(jdbc/db-do-commands db-spec false
69+
(ddl/create-table
70+
:tags
71+
[:id :serial "PRIMARY KEY"]
72+
[:name :varchar "NOT NULL"]))
73+
;; -> (0)
4574
----
4675

47-
Pass the database specification as the first argument to several of the
48-
library's other functions which query and manipulate your database.
76+
Many other functions which query and manipulate a database, such as
77+
+clojure.java.jdbc/insert!+, take a database specification directly as
78+
their first argument.
4979

5080
[source,clojure]
5181
----
52-
(jdbc/insert! db-spec :blocks_world
53-
{:color "RED" :shape "square" :size 1.4}
54-
{:color "BLUE" :shape "cone" :size 2.0}
55-
{:color "WHITE" :shape "rectangle" :size 0.5})
56-
;; -> (nil nil nil)
82+
(require '[clojure.java.jdbc.sql :as sql])
83+
84+
(jdbc/insert! db-spec :tags
85+
{:name "Clojure"}
86+
{:name "Java"})
87+
;; -> ({:name "Clojure", :id 1} {:name "Java", :id 2})
5788
58-
(jdbc/query db-spec (sql/select * :blocks_world (sql/where {:shape "cone"})))
59-
;; -> ({:size 2.0, :shape "cone", :color "BLUE"})
89+
(jdbc/query db-spec (sql/select * :tags (sql/where {:name "Clojure"})))
90+
;; -> ({:name "Clojure", :id 1})
6091
----
6192

6293
==== Discussion
@@ -83,14 +114,17 @@ and plain strings. For example, a complete URI string may be provided under the
83114

84115
[source,clojure]
85116
----
86-
(def db-spec {:connection-uri "jdbc:mysql://localhost:3306/lotr_db?user=bilbo&password=secret"})
117+
(def db-spec {:connection-uri "jdbc:postgresql://localhost:5432/clojure_experiments"}))
118+
119+
;; If you had a username and password...
120+
(def db-spec {:connection-uri "jdbc:postgresql://localhost:5432/clojure_experiments?user=bilbo&password=secret"})
87121
----
88122

89123
Or provided directly as the database specification itself:
90124

91125
[source,clojure]
92126
----
93-
(def db-spec "jdbc:mysql://bilbo:secret@localhost:3306/lotr_db")
127+
(def db-spec "jdbc:postgresql://bilbo:secret@localhost:5432/clojure_experiment")
94128
----
95129

96130
Database records are represented as Clojure maps, with the table's column names
@@ -99,25 +133,31 @@ maps which can then be processed with all the normal Clojure functions.
99133

100134
[source,clojure]
101135
----
102-
(jdbc/query db-spec (sql/select * :abc_words))
103-
;; -> ({:name "ant" :id 11} {:name "bat" :id 12} {:name "cat" :id 13}
104-
;; {:name "dog" :id 14} {:name "fat" :id 16} {:name "elf" :id 15})
136+
(jdbc/query db-spec (sql/select * :tags))
137+
;; -> ({:name "Clojure", :id 1}
138+
; {:name "Java", :id 2})
105139
106-
(filter #(not (.endsWith (:name %) "at"))
107-
(jdbc/query db-spec (sql/select * :abc_words)))
108-
;; -> ({:name "ant", :id 11} {:name "dog", :id 14} {:name "elf", :id 15})
140+
(filter #(not (.endsWith (:name %) "ure"))
141+
(jdbc/query db-spec (sql/select * :tags)))
142+
;; -> ({:name "Java", :id 2})
109143
----
110144

111145
There are other Clojure libraries to access relational databases and each
112146
provides a different abstraction and DSL for the manipulation of SQL data and
113-
expressions. The +clojure.java.jdbc+ library, however, covers a large portion
147+
expressions, such as Korma. The +clojure.java.jdbc+ library, however, covers a large portion
114148
of everyday database access needs.
115149

116150
==== See Also
117151

118-
* See <<sec_db_manipulating_a_sql_database>> to learn about using +clojure.java.jdbc+ to interact with an SQL database.
119-
* See <<sec_db_connecting_with_a_connection_pooling>> to learn about pooling connections to an SQL database with +c3p0+ and +clojure.java.jdbc+.
120-
121-
* Visit the +clojure.java.jdbc+ https://github.com/clojure/java.jdbc[GitHub repository] for more detailed information on the library.
122-
* See http://sqlkorma.com/[Korma SQL] for an alternative SQL DSL.
123-
* See https://github.com/jkk/honeysql[HoneySQL] for another alternative SQL DSL.
152+
* See <<sec_db_manipulating_a_sql_database>> to learn about using
153+
+clojure.java.jdbc+ to interact with an SQL database.
154+
* See <<sec_db_connecting_with_a_connection_pooling>> to learn about
155+
pooling connections to an SQL database with +c3p0+ and
156+
+clojure.java.jdbc+.
157+
* Visit the +clojure.java.jdbc+
158+
https://github.com/clojure/java.jdbc[GitHub repository] for more
159+
detailed information on the library.
160+
* See http://sqlkorma.com/[Korma SQL] and recipe <<sec_sql_korma>> for
161+
an alternative SQL DSL.
162+
* See https://github.com/jkk/honeysql[HoneySQL] for another
163+
alternative SQL DSL.

databases/databases.asciidoc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,8 @@ include::datomic/schema.asciidoc[]
2525

2626
include::datomic/transact-basics.asciidoc[]
2727

28-
include::datomic/transact-relations.asciidoc[]
29-
3028
include::datomic/transact-retract-data.asciidoc[]
3129

32-
include::datomic/transact-with-consistency.asciidoc[]
33-
3430
include::datomic/dry-run-transactions.asciidoc[]
3531

3632
include::datomic/traversing-indices/traversing-indices.asciidoc[]

0 commit comments

Comments
 (0)