Alors ce que nous voulons, c'est une seule instance de notre connexion ; voici une classe qui permet ça :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | package com.sdz.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class SdzConnection{
/**
* URL de connection
*/
private String url = "jdbc:postgresql://localhost:5432/Ecole";
/**
* Nom du user
*/
private String user = "postgres";
/**
* Mot de passe du user
*/
private String passwd = "postgres";
/**
* Objet Connection
*/
private static Connection connect;
/**
* Constructeur privé
*/
private SdzConnection(){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Méthode qui va nous retourner notre instance
* et la créer si elle n'existe pas...
* @return
*/
public static Connection getInstance(){
if(connect == null){
new SdzConnection();
}
return connect;
}
}
|
Nous avons ici une classe avec un constructeur privé (même si, ici, ce n'était pas nécessaire) : du coup, impossible d'avoir une instance de cet objet et impossible d'accéder aux attributs puisqu'ils sont déclarés
private !
Notre objet
Connection est instancié dans le constructeur privé et la seule méthode accessible de l'extérieur de la classe est
getInstance()
. C'est donc cette méthode qui aura pour rôle de créer la connexion lorsque celle-ci n'existe pas, et seulement dans ce cas.
Pour en être bien sûrs, nous allons faire un petit test...
Voici le code un peu modifié de la méthode
getInstance()
...
Code : Java 1
2
3
4
5
6
7
8
9
10 | public static Connection getInstance(){
if(connect == null){
new SdzConnection();
System.out.println("INSTANCIATION DE LA CONNEXION SQL ! ");
}
else{
System.out.println("CONNEXION SQL EXISTANTE ! ");
}
return connect;
}
|
Ceci a pour but de voir quand la connexion est réellement créée. Ensuite, il ne nous manque plus qu'un code de test. Oh ! Ben ça alors ! J'en ai un sous la main :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | package com.sdz.connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class Test {
public static void main(String[] args) {
try {
//1
PreparedStatement prepare = SdzConnection.getInstance().prepareStatement("SELECT * FROM classe WHERE cls_nom = ?");
//2
Statement state = SdzConnection.getInstance().createStatement();
//3
SdzConnection.getInstance().setAutoCommit(false);
//Et 4 appels à la méthode getInstance()
DatabaseMetaData meta = SdzConnection.getInstance().getMetaData();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
|
Il y a 4 appels à la méthode en question,
que croyez-vous que ce code va afficher ?
Secret (cliquez pour afficher)
Vous avez la preuve que l'instanciation ne se fait qu'une seule fois et donc, que notre connexion à la BDD est unique !
Bon, ça c'est compris, par contre, pourquoi tu disais que le constructeur n'était pas nécessaire ?
Tout simplement parce que nous aurions pu avoir cela à la place et ça aurait tout aussi bien fonctionné :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | package com.sdz.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class SdzConnection{
/**
* URL de connection
*/
private static String url = "jdbc:postgresql://localhost:5432/Ecole";
/**
* Nom du user
*/
private static String user = "postgres";
/**
* Mot de passe du user
*/
private static String passwd = "postgres";
/**
* Objet Connection
*/
private static Connection connect;
/**
* Méthode qui va nous retourner notre instance
* et la créer si elle n'existe pas...
* @return
*/
public static Connection getInstance(){
if(connect == null){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connect;
}
}
|
Par contre, vous devrez rajouter la déclaration static de vos paramètres de connexion...
Vous pouvez relancer le code de test, vous verrez qu'il fonctionne toujours !
J'ai mis un constructeur privé d'abord car vous deviez savoir que cela existait, mais c'était superflu dans notre cas...
D'accord, mais j'ai une application multi-threads, tu es sûr qu'il n'y aura pas de conflit ?
Hum ! Vous savez déjà répondre à cette question si vous avez lu le
chapitre sur les threads du tuto Java !
Il vous suffit de synchroniser la méthode
getInstance()
et le tour est joué...
Mais, parce qu'il y a un mais... cette méthode ne règle le problème qu'avant que la connexion ne soit instanciée. Autrement dit, une fois la connexion instanciée, la synchronisation ne sert plus à rien...
Le problème de
multi-threading ne se pose pas vraiment pour une connexion à une BDD puisque ce
singleton sert surtout de passerelle entre votre BDD et votre application, mais il peut y avoir d'autres objets que des connexions SQL qui ne doivent être instanciés qu'une fois et tous ne sont pas aussi laxistes concernant le multi-threading...
Voyons comment parfaire ce pattern avec un autre exemple qu'une connexion SQL...