Bonjour à tous.
Je suis actuellement sur un très gros projet, qui sera utilisé évidemment par plusieurs personnes à un même instant, et qui bien sûr travailleront souvent sur des objets communs (comme un projet).
L'architecture du projet est très simple. Il s'agit d'un projet J2EE "classique" dans lequel j'utilise le framework ZK (car l'application est une RIA). Mais ZK n'est lié en aucun cas à la persistance et c'est sur ce point justement que j'ai besoin de votre aide. Pour la persistance justement, j'utilise EclipseLink. Grosso modo, j'ai donc simplement un fichier WEB-INF/persistence.xml et mes POJO @Entity.
J'ai besoin de votre aide pour me confirmer que l'architecture actuelle ne permettra pas d'avoir des pertes de données si deux utilisateurs connectés tentent de modifier un même objet ! Voilà tout. Donc je vais vous présenter comment je m'y prend au niveau de la persistance, d'une façon très simple. Et j'ai besoin que vous me disiez si certains points peuvent poser problème.
Le premier point de la persistence de mon application consiste a créer un EntityManager dans une classe singleton que j'ai nommé affectusement PersistenceFactory :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public final class PersistenceFactory {
private static PersistenceFactory instance;
private final EntityManager em;
public static PersistenceFactory getInstance() {
if (PersistenceFactory.instance == null) {
PersistenceFactory.instance = new PersistenceFactory();
}
return PersistenceFactory.instance;
}
private PersistenceFactory() {
this.em = Persistence.createEntityManagerFactory("monprojet").createEntityManager();
}
public EntityManager getEm() {
return this.em;
}
} |
Déjà j'aimerais votre confirmation sur le fait qu'il ne faille qu'un seul EntityManager dans l'application ?
Seconde étape, j'ai créé un DAO générique, le bien nommé GenericDAO :
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 142 143 144 145 146 147 148 149
| public class GenericDAO<T> implements IGenericDAO<T> {
private final Class<?> clazz;
protected EntityManager em;
public GenericDAO(final Class<?> clazz) {
this.clazz = clazz;
this.em = PersistenceFactory.getInstance().getEm();
}
public T find(final Object id) {
if (id == null) {
return null;
}
T entity = null;
if (this.clazz != null) {
try {
entity = (T) this.em.find(this.clazz, id);
} catch (final Exception e) {}
}
return entity;
}
public List<T> getAll() {
return this.getAll(null);
}
public List<T> getAll(final String sqlMore) {
List<T> entities = null;
if (this.clazz != null) {
String q = "SELECT o FROM " + this.clazz.getSimpleName() + " o";
if (StringUtils.isNotBlank(sqlMore)) {
q += " " + sqlMore;
}
try {
entities = this.em.createQuery(q).getResultList();
} catch (final Exception e) {}
}
return entities;
}
public void persist(final T entity) {
this.persist(entity, false);
}
public void persist(final T entity, final boolean refresh) {
if (entity == null) {
return;
}
synchronized (this.em) {
try {
this.em.getTransaction().begin();
if (!this.em.contains(entity)) {
this.em.persist(entity);
} else {
this.em.merge(entity);
}
this.em.getTransaction().commit();
if (refresh) {
this.refresh(entity);
}
} catch (final Exception e) {}
}
}
public void persist(final T[] entities) {
for (final T entity : entities) {
this.persist(entity);
}
}
public void persist(final T[] entities, final boolean refresh) {
for (final T entity : entities) {
this.persist(entity, refresh);
}
}
public void refresh(final T entity) {
if (entity == null) {
return;
}
synchronized (this.em) {
if (this.em.contains(entity)) {
try {
this.em.refresh(entity);
} catch (final Exception e) {}
}
}
}
public void refresh(final T[] entities) {
for (final T entity : entities) {
this.refresh(entity);
}
}
public void remove(final T entity) {
if (entity == null) {
return;
}
synchronized (this.em) {
try {
this.em.getTransaction().begin();
this.em.remove(entity);
this.em.getTransaction().commit();
} catch (final Exception e) {}
}
}
public void remove(final T[] entities) {
for (final T entity : entities) {
this.remove(entity);
}
}
public void removeAll() {
final List<T> entities = this.getAll();
synchronized (this.em) {
try {
this.em.getTransaction().begin();
for (final T entity : entities) {
this.em.remove(entity);
}
this.em.getTransaction().commit();
} catch (final Exception e) {}
}
}
@Deprecated
/**
* Prefer persist
*/
public void update(final T entity) {
if (entity == null) {
return;
}
this.persist(entity);
}
@Deprecated
/**
* Prefer persist
*/
public void update(final T[] entities) {
for (final T entity : entities) {
this.update(entity);
}
}
} |
Comme vous pouvez le voir, j'ai mis quelques synchronized... ZK est multithreads. Sont-ils pertinents ?
Du coup, quand je veux créer un DAO pour la classe Project, je dérive du DAO générique (et je peux ensuite créer les méthodes spécifiques à la classe) :
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
| public final class ProjectDAO extends GenericDAO<Project> implements IProjectDAO {
private static ProjectDAO instance;
public static ProjectDAO getInstance() {
if (ProjectDAO.instance == null) {
ProjectDAO.instance = new ProjectDAO();
}
return ProjectDAO.instance;
}
private ProjectDAO() {
super(Project.class);
}
public Project findOneByName(final Society society, final String name) {
Project project = null;
final String q = "SELECT p FROM Project p WHERE p.name = :name AND p.society = :society";
final Query query = PersistenceFactory.getInstance().getEm().createQuery(q);
query.setParameter("name", name);
query.setParameter("society", society);
try {
project = (Project) query.getSingleResult();
} catch (final NoResultException e) {}
return project;
}
// ...
} |
Je peux donc faire par exemple :
ProjectDAO.getInstance().persist(unObjProjet); // persiste le projet
Alors, qu'en dîtes-vous ? Est-ce que vous voyez un ou plusieurs problème(s) dans ma façon de faire ? J’aimerais simplement confirmer mon choix ou s'il faut, apporter quelques corrections.
Merci d'avance pour votre aide.
Partager