Discussion:
Singleton mit Connection Pool
(zu alt für eine Antwort)
Markus Pitha
2008-03-06 23:09:03 UTC
Permalink
Hallo,

da ich in mehreren Klassen Datenbankverbindungen brauche, die auch noch
effizient sein sollen, habe ich frühere Tipps von hier versucht zu
befolgen, und einen Pool mit einem Singleton versucht zu verwenden.
So sieht mein funktionierendes Beispiel aus:

----------Testsingleton.class---------
import java.sql.Connection;
import java.sql.SQLException;

import org.postgresql.jdbc2.optional.PoolingDataSource;

public final class TestSingleton {

private static TestSingleton instance;
private static PoolingDataSource pds;

private TestSingleton() throws ClassNotFoundException, SQLException {
pds = new PoolingDataSource();
pds.setServerName("localhost");
pds.setPassword("pwd123456");
pds.setUser("postgres");
pds.setDatabaseName("testdb");
pds.setMaxConnections(20);
}

public synchronized static TestSingleton getInstance() throws
ClassNotFoundException, SQLException {
if (instance == null) {
instance = new TestSingleton();
}
return instance;
}

public synchronized static java.sql.Connection
getPoolConnection() throws SQLException {
return pds.getConnection();
}

public synchronized static void closePoolConnection(Connection c) {
try {
c.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (c != null)
try {
c.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
----------------Testklasse.class---------------
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


public class Testklasse {

public void testeAbfrage() throws SQLException {
Connection con = null;
PreparedStatement pstmt;
con = TestSingleton.getPoolConnection();
pstmt = con.prepareStatement("SELECT vorname,nachname,datum from
testtabelle " +
"WHERE vorname = ?");
pstmt.setString(1, "Tester");
ResultSet rs = pstmt.executeQuery();
while (rs.next())
System.out.println(rs.getString(1) + " " + rs.getString(2) +
" " + rs.getDate(3));
TestSingleton.closePoolConnection(con);
}
}

---------------Main.class-----------------------
import java.sql.SQLException;

public class Main {

public static void main(String[] args) throws ClassNotFoundException,
SQLException {
TestSingleton.getInstance();
Testklasse tk = new Testklasse();
tk.testeAbfrage();
}
}

Das Beispiel funktioniert, aber ist es auch so richtig implementiert?
Mit Connection Pools und Singletons habe ich nämlich bisher keine
Erfahrung.
Ich bedanke mich schon mal im vorhinein für etwaige Antworten.


Markus
Christoph Dahlen
2008-03-07 13:15:21 UTC
Permalink
Post by Markus Pitha
Das Beispiel funktioniert, aber ist es auch so richtig implementiert?
Mit Connection Pools und Singletons habe ich nämlich bisher keine
Erfahrung.
Hmm, für baust Du nur nach, was eine DataSource sowieso bietet, warum?
Im Endeffekt brauchst du maximal eine DataSource-Factory, falls Dir
Deine Laufzeit-Umgebung (App/WebContainer) keine per JDNI zur Verfügung
stellt.

Gruß,

Christoph
Markus Pitha
2008-03-07 16:30:00 UTC
Permalink
Hallo,
Post by Christoph Dahlen
Hmm, für baust Du nur nach, was eine DataSource sowieso bietet, warum?
Im Endeffekt brauchst du maximal eine DataSource-Factory, falls Dir
Deine Laufzeit-Umgebung (App/WebContainer) keine per JDNI zur Verfügung
stellt.
Heißt das, dass eine DataSource genauso wie ein Pool mit pooled
Connections fungiert?
Warum wäre eine DataSource vorteilhafter?

Markus
Bernd Eckenfels
2008-03-08 21:09:07 UTC
Permalink
Post by Markus Pitha
Heißt das, dass eine DataSource genauso wie ein Pool mit pooled
Connections fungiert?
Kommt auf den Treiber (Vendor) an. Schon deswegen wuerde ich einen
allgemeinen/einheitlichen externen Connection Pool verwenden.

Die Oracle Datasource ist inzwischen recht intelligent geworden, aber dinge
wie Keepalive oder "check before return" macht nen App Server Pool oder ein
externer Pool (dbcp) noch flexibler.

Gruss
Bernd
Stephan Hilgers
2008-03-07 17:41:49 UTC
Permalink
Post by Markus Pitha
public synchronized static TestSingleton getInstance() throws
ClassNotFoundException, SQLException {
if (instance == null) {
instance = new TestSingleton();
}
return instance;
}
besser

public static TestSingleton getInstance() throws....
{
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
Post by Markus Pitha
public synchronized static java.sql.Connection getPoolConnection()
public synchronized static void closePoolConnection(Connection c) {
und warum sind diese methoden statisch? Dann brauchst du doch gar kein
Singleton?
Holger Hoffstaette
2008-03-07 18:20:14 UTC
Permalink
public static TestSingleton getInstance() throws.... {
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
}
FAIL

Bitte lies:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet :-(
Stephan Hilgers
2008-03-07 21:22:55 UTC
Permalink
Post by Holger Hoffstaette
public static TestSingleton getInstance() throws.... {
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
}
FAIL
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet :-(
steht so in Head First Design Pattern. :(
Stephan Hilgers
2008-03-11 19:28:04 UTC
Permalink
Post by Stephan Hilgers
Post by Holger Hoffstaette
public static TestSingleton getInstance() throws.... {
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
}
FAIL
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet :-(
steht so in Head First Design Pattern. :(
ich nehme alles zurück. Dort steht ausdrücklich, dass der Double Check
mit Java1.4 und früher wegen der Implementierung von volatile nicht
funktioniert. Entspricht "Fixing Double-Checked Locking using Volatile"
im obigen Dokument.

Und der Mist, dass der double-check 'besser' sei, kam von mir :(. Im
Buch wird er nur als eine Möglichkeit vorgestellt mit dem Hinweis, dass
er in einigen Fällen helfen kann..
Ivan Dolvich
2008-03-11 12:06:47 UTC
Permalink
Post by Holger Hoffstaette
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet :-(
Sehr interessant zu wissen! Ist der Artikel schon älter?
Holger Hoffstaette
2008-03-11 14:38:23 UTC
Permalink
Post by Ivan Dolvich
Post by Holger Hoffstaette
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet :-(
Sehr interessant zu wissen! Ist der Artikel schon älter?
Da dort davon gesprochen wird, daß die memory-model Semantik "in Zukunft"
präzise(r) definiert wird (was dann mit Java 5 passierte), ist das wohl
der Fall, ja. Das ändert aber nichts am Inhalt, da die Fragen auf der
concurrency-Liste auch immer wieder auftauchen. :-)
Scheinbar ist es nur schwer zu vermitteln und ebenso zu akzeptieren, warum
Code "der doch funktioniert" dennoch falsch/kaputt sein soll.

Leicht OT, aber viel interessanter finde ich, warum:

- im Jahr 2008 immer noch so viel Aufwand für ein in 99.9% aller Fälle völlig
irrelevantes Nicht-Problem betrieben wird

- die oftmals völlig unreflektierte und fehlgeleitete "Pattern-Geilheit"
besonders von (falsch angeleiteten?) Anfängern: kommt es wirklich niemandem
ganz intuitiv komisch vor, daß für das einfache zurückgeben einer
struntzdoofen Objektreferenz mehrere Zeilen Code mit if-else und obskurer
Synchronisation "nötig" sind? Warum wird sowas nicht hinterfragt?

Holger
Jan Torben Heuer
2008-03-11 20:27:29 UTC
Permalink
Holger Hoffstaette wrote:

Hi,
Post by Holger Hoffstaette
public static TestSingleton getInstance() throws.... {
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Unglaublich - es ist jetzt 2008 und immer noch wird dieser Mist verbreitet
Also es geht jetzt konkret um das doppelte if instance == null?

i.O wäre aber:
public static synchronized TestSingleton getInstance() {
if(instance == null) {
instance = new ...
}
return instance;
}

Nicht, dass ich da was falsch verstehe?

Jan
Holger Hoffstaette
2008-03-11 21:09:27 UTC
Permalink
Post by Jan Torben Heuer
Also es geht jetzt konkret um das doppelte if instance == null?
Nein, es geht um das Abfragen der Referenz, die nicht volatile ist. Denk
nicht weiter drüber nach ;)
Post by Jan Torben Heuer
public static synchronized TestSingleton getInstance() {
if(instance == null) {
instance = new ...
}
return instance;
}
}
Nicht, dass ich da was falsch verstehe?
Ja, das ist genau der einfachste und "korrekteste" Weg das zu
implementieren. Für alles andere muß man verstehen, was man tut.

-h
Hubert Partl
2008-03-12 12:51:42 UTC
Permalink
Post by Jan Torben Heuer
public static synchronized TestSingleton getInstance() {
if(instance == null) {
instance = new ...
}
return instance;
}
Ja, das ist genau der einfachste und "korrekteste" Weg ...
Es gibt eine noch einfachere, Thread-sichere Variante,
die nur fuer den Fall,
dass die Klasse geladen wird, aber niemals getInstance() aufgerufen wird,
ein bisschen zu viel Memory verbraucht.

(Das ist meiner Meinung nach aber nicht wesentlich,
denn ueblicherweise ist das erste Ansprechen einer Singleton-Klasse
ohnehin immer der Aufruf der getInstance()-Methode.
Oder habe ich da etwas uebersehen?)

Ich meine diese Variante
(wobie ich davon ausgehe,
dass eine Klasse vom Classloader hoechstens 1 Mal geladen wird):

private static TestSingleton instance = new TestSingleton();

public static TestSingleton getInstance() {
return instance;
}

Im uebrigen halte ich die Kombination von static und snchronized fuer etwas,

was fuer einen einfach denkenden Menschen schwer zu durchschauen ist,
der gewohnt ist, dass synchronized am this-Objekt synchronisiert,
daher finde ich "meine" Version nicht nur einfacher,
sondern auch leichter verstaendlich. :-)

Und was kommen jetzt fuer Kommentare?


--
Alfred
2008-03-15 07:20:38 UTC
Permalink
Post by Hubert Partl
...
Ich meine diese Variante
(wobie ich davon ausgehe,
private static TestSingleton instance = new TestSingleton();
public static TestSingleton getInstance() {
return instance;
}
Im uebrigen halte ich die Kombination von static und snchronized fuer etwas,
was fuer einen einfach denkenden Menschen schwer zu durchschauen ist,
der gewohnt ist, dass synchronized am this-Objekt synchronisiert,
daher finde ich "meine" Version nicht nur einfacher,
sondern auch leichter verstaendlich. :-)
Und was kommen jetzt fuer Kommentare?
Dass deine Implementierung die vernünftigste ist,
einen Singleton zu erstellen.

Alfred

Markus Pitha
2008-03-07 19:10:21 UTC
Permalink
Hallo,
Post by Stephan Hilgers
und warum sind diese methoden statisch? Dann brauchst du doch gar kein
Singleton?
Ganz einfach, andernfalls würde ich aus "Testklasse" Fehlermeldungen
bekommen, die mich darauf hinweisen, dass Java keine "static reference
to a non static method" machen kann.
(in dieser Zeile zB: con = TestSingleton.getPoolConnection();)


Markus
Stephan Hilgers
2008-03-07 21:20:57 UTC
Permalink
Post by Markus Pitha
Hallo,
Post by Stephan Hilgers
und warum sind diese methoden statisch? Dann brauchst du doch gar kein
Singleton?
Ganz einfach, andernfalls würde ich aus "Testklasse" Fehlermeldungen
bekommen, die mich darauf hinweisen, dass Java keine "static reference
to a non static method" machen kann.
(in dieser Zeile zB: con = TestSingleton.getPoolConnection();)
con = TestSingleton.getInstance().getPoolConnection();


das der Double-Check kein Sinn macht, lese ich hier zum ersten mal.
Scheint was dran zu sehen. Danke an Holger.
Bernd Eckenfels
2008-03-08 21:56:06 UTC
Permalink
Post by Stephan Hilgers
das der Double-Check kein Sinn macht, lese ich hier zum ersten mal.
Scheint was dran zu sehen. Danke an Holger.
Inzwischen (Implementierung die dem neuen Memory Model folgte, wie z.b. Sun
Java5++) ist es mit einem Volatile moeglich. Der Volatile ist aber
vermutlich nicht viel schneller als ein optimierter synchronized (auch nicht
unter hoher Konkurenz)

Gruss
Bernd
Bernd Eckenfels
2008-03-08 21:11:04 UTC
Permalink
Post by Markus Pitha
(in dieser Zeile zB: con = TestSingleton.getPoolConnection();)
Die ist auch falsch, was du willst ist ein Monostate, ein Siingleton
verwendet man so: TestSingleton.getInstance().getPoolConnection();

Gruss
Bernd
Christian
2008-03-11 20:45:15 UTC
Permalink
Post by Stephan Hilgers
Post by Markus Pitha
public synchronized static TestSingleton getInstance() throws
ClassNotFoundException, SQLException {
if (instance == null) {
instance = new TestSingleton();
}
return instance;
}
besser
public static TestSingleton getInstance() throws....
{
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
Post by Markus Pitha
public synchronized static java.sql.Connection
getPoolConnection() public synchronized static void
closePoolConnection(Connection c) {
und warum sind diese methoden statisch? Dann brauchst du doch gar kein
Singleton?
das iseht mir alles Hässlich und Eklig aus ...
Um einfach Threadsafe lazy singletons zu machen kann man denn
Classloader und dessen synchronisierung benutzen...
warum nicht so:

public class TestSingleton {

private TestSingleton() {}

private static final class SingletonHolder {
private static final TestSingleton test = new TestSingleton();
}

public static DCClient get() {
return SingletonHolder.test;
}

}
Christian
2008-03-11 20:48:31 UTC
Permalink
Post by Stephan Hilgers
Post by Markus Pitha
public synchronized static TestSingleton getInstance() throws
ClassNotFoundException, SQLException {
if (instance == null) {
instance = new TestSingleton();
}
return instance;
}
besser
public static TestSingleton getInstance() throws....
{
if (instance == null) {
synchronized(TestSingleton.Class) {
if (instance == null) {
instance = new TestSingleton();
}
}
}
return instance;
}
Post by Markus Pitha
public synchronized static java.sql.Connection
getPoolConnection() public synchronized static void
closePoolConnection(Connection c) {
und warum sind diese methoden statisch? Dann brauchst du doch gar kein
Singleton?
das sieht mir alles Hässlich und Eklig aus ...
Um einfach Threadsafe lazy singletons zu machen kann man denn
Classloader und dessen synchronisierung benutzen...
warum nicht so:

public class TestSingleton {

private TestSingleton() {}

private static final class SingletonHolder {
private static final TestSingleton test = new TestSingleton();
}

public static TestSingleton get() {
return SingletonHolder.test;
}

}
Holger Hoffstaette
2008-03-11 21:12:03 UTC
Permalink
das sieht mir alles Hässlich und Eklig aus ... Um einfach Threadsafe lazy
singletons zu machen kann man denn Classloader und dessen synchronisierung
public class TestSingleton {
private TestSingleton() {}
private static final class SingletonHolder {
private static final TestSingleton test = new TestSingleton();
}
}
public static TestSingleton get() {
return SingletonHolder.test;
}
}
+1 , endlich mal jemand der Bücher liest :-)

-h
Bernd Eckenfels
2008-03-11 22:20:11 UTC
Permalink
Post by Holger Hoffstaette
Post by Christian
public static TestSingleton get() {
return SingletonHolder.test;
}
+1 , endlich mal jemand der Bücher liest :-)
Vorsicht Vorsicht. Es ist extrem nervig so in einem JavaEE Umfald
vorzugehen. Zum einen braucht der App Server dann ewig bis er gestartet ist
(main deployment scanner muss ein haufen kram single threaded tun) und zum
anderen kann die Klasse die so einen statischen initializer hat nicht
sinnvoll Fehler zurueckgeben oder gar später retryen.

Gruss
Bernd
Lesen Sie weiter auf narkive:
Loading...