Bonjour,
Je voudrais mettre un lock sur une table durant la transaction. C-à-d très exactement faire une "LOCK TABLE personne WRITE;"
Comme on peut le lire dans le code ci-dessous, je n'accepte de faire un "update" que si la valeur du champ [VERSION] est identique à la valeur que j'ai lu avant de faire la mise à jour.
Extrait:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 //modifier une personne protected void updatePersonne(Personne personne) { [...] //modification int n = getSqlMapClientTemplate().update("Personne.updateOne", personne); if (n==0) throw new DaoException("La personne d'Id ["+personne.getId()+" n'existe pas ou bien a été modifié", 2); }Ce que je veux faire, c'est "locker" la table personne avant ma transaction pour m'assurer que personne ne pourra modifier la valeur du champ [VERSION] durant ma transaction et enfin à la fin de la transaction libérer le verrou par un "UNLOCK TABLES".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 [...] <sqlMap> [...] <!-- mettre à jour une personne --> <update id="Personne.updateOne" parameterClass="Personne.classe"> UPDATE PERSONNES SET VERSION=#version#+1, NOM=#nom#, PRENOM=#prenom#, DATENAISSANCE=#dateNaissance#, MARIE=#marie#, NBENFANTS=#nbEnfants# WHERE ID=#id# AND VERSION=#version# </update> [...] </sqlMap>
Comment puis-je faire cela?
table [personne]
CODE SOURCE COMPLET:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ID VERSION NOM PRENOM DATENAISSANCE MARIE NBENFANTS 424 3 DUPONT Alain 1975-11-03 0 2 443 1 DURANT Nathalie1984-12-07 0 2 445 2 DUVAL Giuseppe1991-02-05 1 0
Classe personne:
Pour accèder à la table, les classes et interfaces:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 package istia.st.springmvc.personnes.entites; import java.text.SimpleDateFormat; import java.util.Date; public class Personne { //identifiant unique de la personne private int id; //la version actuelle private long version; //le nom private String nom; //le prénom private String prenom; //la date de naissance private Date dateNaissance; //l'état marital private boolean marie = false; //le nombre d'enfants private int nbEnfants; public int getId() { return id; } public void setId(int id) { this.id = id; } public long getVersion() { return version; } public void setVersion(long version) { this.version = version; } public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; } public String getPrenom() { return prenom; } public void setPrenom(String prenom) { this.prenom = prenom; } public Date getDateNaissance() { return dateNaissance; } public void setDateNaissance(Date dateNaissance) { this.dateNaissance = dateNaissance; } public boolean isMarie() { return marie; } public void setMarie(boolean marie) { this.marie = marie; } public int getNbEnfants() { return nbEnfants; } public void setNbEnfants(int nbEnfants) { this.nbEnfants = nbEnfants; } //constructeur par défaut public Personne() { } //constructeur avec initialisation des champs de la personne public Personne(int id, String nom, String prenom, Date dateNaissance, int nbEnfants, boolean marie) { this.id = id; this.marie = marie; this.nom = nom; this.prenom = prenom; this.dateNaissance = dateNaissance; this.nbEnfants = nbEnfants; } public Personne(int id, String nom, String prenom, Date dateNaissance, boolean marie, int nbEnfants ) { this.id = id; this.marie = marie; this.nom = nom; this.prenom = prenom; this.dateNaissance = dateNaissance; this.nbEnfants = nbEnfants; } //constructeur d'une perosnne par recopie d'une autre personne public Personne(Personne p) { setId(p.getId()); setVersion(p.getVersion()); setNom(p.getNom()); setPrenom(p.getPrenom()); setDateNaissance(p.getDateNaissance()); setMarie(p.isMarie()); setNbEnfants(p.getNbEnfants()); } //toString public String toString() { return "[" + id + ", " + version + ", " + prenom + ", " + nom + ", " + new SimpleDateFormat("dd/MM/yyyy").format(dateNaissance) + ", " + marie + ", " + nbEnfants + "]"; } }
IDAO interface:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package istia.st.springmvc.personnes.dao; import istia.st.springmvc.personnes.entites.Personne; import java.util.Collection; public interface IDao { //liste de toutes les personnes Collection getAll(); //obtenir une personne particulière Personne getOne(int id); //ajouter/modifier une personne void saveOne(Personne personne); //supprimer une personne void deleteOne(int id); }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 package istia.st.springmvc.personnes.dao; import istia.st.springmvc.personnes.entites.Personne; import java.util.ArrayList; import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport; import java.util.Collection; import java.util.List; public class DaoImplCommon extends SqlMapClientDaoSupport implements IDao { //liste des personnes @Override public Collection getAll() { return getSqlMapClientTemplate().queryForList("Personne.getAll", null); } //obtenir une personne en particulier @Override public Personne getOne(int id) { Personne personne; // on la récupère dans le BD List tmpP = (List) getSqlMapClientTemplate().queryForList("Personne.getOne", new Integer(id)); if (tmpP.isEmpty()) personne=null; else { personne = (Personne) tmpP.get(0); } //Personne personne = (Personne) getSqlMapClientTemplate().queryForList("Personne.getOne", new Integer(id)); // a-t-on récupéré qq chose? if (personne==null) { //on lance une exception throw new DaoException("La personne d'id [" + id + "] n'existe pas", 2); } return personne; } @Override public void saveOne(Personne personne) { // le paramètre personne est-il valide ? check(personne); //ajout ou modification ? if (personne.getId()==-1) insertPersonne(personne); else updatePersonne(personne); //on attend 5 sec - pour les tests mettre true au lieu de false System.out.println("attend 5 sec..."); if (true) wait(5000); } //suppression d'une personne @Override public void deleteOne(int id) { //on supprime la personne int n = getSqlMapClientTemplate().delete("Personne.deleteOne", new Integer(id)); // a-t-on réussi if (n==0) throw new DaoException("Personne d'id ["+id+"] inconnue", 2); } //ajouter une personne protected void insertPersonne(Personne personne) { //1ère version personne.setVersion(1); //on attend 10 ms - pour les tests mettre true au lieu de false if (true) wait(10); //on insère la nouvelle perosnne dans la table de la BD getSqlMapClientTemplate().insert("Personne.insertOne", personne); } //modifier une personne protected void updatePersonne(Personne personne) { //on attend 10 ms - pour les tests mettre true au lieu de false if (true) wait(10); /* try { synchronized(this){ wait(10); } } catch(InterruptedException e) { } */ //modification int n = getSqlMapClientTemplate().update("Personne.updateOne", personne); if (n==0) throw new DaoException("La personne d'Id ["+personne.getId()+" n'existe pas ou bien a été modifié", 2); } //vérifier validité d'une personn private void check(Personne p) { // personne p if (p == null) { throw new DaoException("Personne null", 10); } // id if (p.getId() != -1 && p.getId() < 0) { throw new DaoException("Id [" + p.getId() + "] invalide", 11); } // date de naissance if (p.getDateNaissance() == null) { throw new DaoException("Date de naissance manquante", 12); } // nombre d'enfants if (p.getNbEnfants() < 0) { throw new DaoException("Nombre d'enfants [" + p.getNbEnfants() + "] invalide", 13); } // nom if (p.getNom() == null || p.getNom().trim().length() == 0) { throw new DaoException("Nom manquant", 14); } // prénom if (p.getPrenom() == null || p.getPrenom().trim().length() == 0) { throw new DaoException("Prénom manquant", 15); } } // attente private void wait(int N) { // on attend N ms try { Thread.sleep(N); } catch (InterruptedException e) { // on affiche la trace de l'exception e.printStackTrace(); return; } } }Les classes et interfaces pour configurer la transaction:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package istia.st.springmvc.personnes.dao; public class DaoException extends RuntimeException { private int code; public int getCode() { return code; } public DaoException(String message, int code) { super(message); this.code = code; } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 istia.st.springmvc.personnes.service; import istia.st.springmvc.personnes.entites.Personne; import java.util.Collection; public interface IService { // liste de toutes les personnes Collection getAll(); // obtenir une personne particuli�re Personne getOne(int id); // ajouter/modifier une personne void saveOne(Personne personne); // supprimer une personne void deleteOne(int id); // ajouter plusieurs personnes void saveMany(Personne[] personnes); // supprimer plusieurs personnes void deleteMany(int ids[]); }Les fichiers xml pour les beans:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
49
50
51
52
53
54
55
56
57 package istia.st.springmvc.personnes.service; import istia.st.springmvc.personnes.entites.Personne; import istia.st.springmvc.personnes.dao.IDao; import java.util.Collection; public class ServiceImpl implements IService { // la couche [dao] private IDao dao; public IDao getDao() { return dao; } public void setDao(IDao dao) { this.dao = dao; } // liste des personnes public Collection getAll() { return dao.getAll(); } // obtenir une personne en particulier public Personne getOne(int id) { return dao.getOne(id); } // ajouter ou modifier une personne public void saveOne(Personne personne) { dao.saveOne(personne); } // suppression d'une personne public void deleteOne(int id) { dao.deleteOne(id); } // sauvegarder une collection de personnes public void saveMany(Personne[] personnes) { // on boucle sur le tableau des personnes for (int i = 0; i < personnes.length; i++) { dao.saveOne(personnes[i]); } } // supprimer une collection de personnes public void deleteMany(int[] ids) { // ids : les id des personnes à supprimer for (int i = 0; i < ids.length; i++) { dao.deleteOne(ids[i]); } } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- la source de données DBCP --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://192.168.1.199:3306/test</value> </property> <property name="username"> <value>[LOGIN]</value> </property> <property name="password"> <value>[MOT DE PASSE]</value> </property> </bean> <!-- SqlMapClient --> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="dataSource"> <ref local="dataSource" /> </property> <property name="configLocation"> <value>classpath:sql-map-config-mysql.xml</value> </property> </bean> <!-- la classe d'accès à la couche [dao] --> <bean id="dao" class="istia.st.springmvc.personnes.dao.DaoImplCommon"> <property name="sqlMapClient"> <ref local="sqlMapClient" /> </property> </bean> <!-- gestionnaire de transactions --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="dataSource" /> </property> </bean> <!-- la classe d'accès à la couche [service] --> <bean id="service" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="transactionManager" /> </property> <property name="target"> <bean class="istia.st.springmvc.personnes.service.ServiceImpl"> <property name="dao"> <ref local="dao" /> </property> </bean> </property> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="delete*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 <?xml version="1.0" encoding="UTF-8"?> <!-- <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> --> <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL MAP Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <sqlMap resource="personne-mysql.xml" /> </sqlMapConfig>Et enfin le prog. principal:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap> <!-- alias classe [Personne] --> <typeAlias alias="Personne.classe" type="istia.st.springmvc.personnes.entites.Personne" /> <!-- mapping table [PERSONNES] - objet [Personne] --> <resultMap id="Personne.map" class="istia.st.springmvc.personnes.entites.Personne"> <result property="id" column="ID" /> <result property="version" column="VERSION" /> <result property="nom" column="NOM" /> <result property="prenom" column="PRENOM" /> <result property="dateNaissance" column="DATENAISSANCE" /> <result property="marie" column="MARIE" /> <result property="nbEnfants" column="NBENFANTS" /> </resultMap> <!-- LISTE DE TOUTES LES PERSONNES --> <select id="Personne.getAll" resultMap="Personne.map"> SELECT ID, VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES </select> <!-- obtenir une personne en particulier --> <select id="Personne.getOne" resultMap="Personne.map"> SELECT ID, VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES WHERE ID=#value# </select> <!-- ajouter une personne --> <insert id="Personne.insertOne" parameterClass="Personne.classe"> INSERT INTO PERSONNES (VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS) VALUES (#version#, #nom#, #prenom#, #dateNaissance#, #marie#, #nbEnfants#) <selectKey keyProperty="id"> select LAST_INSERT_ID() as value </selectKey> </insert> <!-- mettre à jour une personne --> <update id="Personne.updateOne" parameterClass="Personne.classe"> UPDATE PERSONNES SET VERSION=#version#+1, NOM=#nom#, PRENOM=#prenom#, DATENAISSANCE=#dateNaissance#, MARIE=#marie#, NBENFANTS=#nbEnfants# WHERE ID=#id# AND VERSION=#version# </update> <!-- supprimer une perosnne --> <delete id="Personne.deleteOne" parameterClass="int"> DELETE FROM PERSONNES WHERE ID=#value# </delete> <!-- obtenir la valeur de la clé primaire [id] de la dernière personne insérée --> <select id="Personne.getNextId" resultClass="int"> SELECT LAST_INSERT_ID() </select> </sqlMap>
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package istia.st.springmvc.personnes.tests; import istia.st.springmvc.personnes.dao.IDao; import istia.st.springmvc.personnes.entites.Personne; import istia.st.springmvc.personnes.service.IService; import java.util.Collection; import java.util.Iterator; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.interceptor.TransactionProxyFactoryBean; public class MainTestServiceDao { public static void main(String[] args) { IService service= (IService) new XmlBeanFactory(new ClassPathResource("spring-config-dao-mysql.xml")).getBean("service"); Personne pers = service.getOne(424); pers.setNbEnfants(15); service.saveOne(pers); } }
Partager