diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index a2c9053c89e5588da519e4a3faccc193d6f278e1..3510238f02dfcf6c04dd733153a357be22d5b219 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -48,7 +48,6 @@
 		<mapping-file>org/olat/course/nodes/projectbroker/datamodel/Project.hbm.xml</mapping-file>
 		<mapping-file>org/olat/course/nodes/projectbroker/datamodel/ProjectBroker.hbm.xml</mapping-file>
 		<mapping-file>org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml</mapping-file>
-		<mapping-file>org/olat/course/assessment/model/UserCourseInfosImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/modules/fo/ForumImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/modules/fo/MessageImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/modules/fo/ReadMessage.hbm.xml</mapping-file>
@@ -92,6 +91,7 @@
 		<class>org.olat.core.dispatcher.mapper.model.PersistedMapper</class>
 		<class>org.olat.core.commons.services.taskexecutor.model.PersistentTask</class>
 		<class>org.olat.core.commons.services.taskexecutor.model.PersistentTaskModifier</class>
+		<class>org.olat.course.assessment.model.UserCourseInfosImpl</class>
 		<class>org.olat.group.model.BusinessGroupParticipantViewImpl</class>
 		<class>org.olat.group.model.BusinessGroupOwnerViewImpl</class>
 		<class>org.olat.group.model.BusinessGroupLazyImpl</class>
diff --git a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java
index d7067095d9275cdc53aba59940dfc19aa7ef4251..5b51b3fc5fd6200c88bb9c551738c3f17b50ad99 100644
--- a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java
+++ b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManager.java
@@ -39,7 +39,7 @@ public interface UserCourseInformationsManager {
 	public List<UserCourseInformations> getUserCourseInformations(Identity identity, List<OLATResource> resources);
 	
 	
-	public void updateUserCourseInformations(Long courseResId, Identity identity);
+	public void updateUserCourseInformations(Long courseResId, Identity identity, boolean strict);
 	
 	public Date getInitialLaunchDate(Long courseResourceId, Identity identity);
 	
diff --git a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
index d1a3dc5ff3e4f57f2768fbb45887f2af6f51fed6..4da9e894e903d02fbfc47d4aafc51226b020033d 100644
--- a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
+++ b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
@@ -65,8 +65,9 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 		try {
 			StringBuilder sb = new StringBuilder();
 			sb.append("select infos from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ")
-				.append(" inner join infos.resource as resource")
-			  .append(" where infos.identity.key=:identityKey and resource.resId=:resId and resource.resName='CourseModule'");
+			  .append(" inner join fetch infos.resource as resource")
+			  .append(" inner join infos.identity as identity")
+			  .append(" where identity.key=:identityKey and resource.resId=:resId and resource.resName='CourseModule'");
 
 			List<UserCourseInfosImpl> infoList = dbInstance.getCurrentEntityManager()
 					.createQuery(sb.toString(), UserCourseInfosImpl.class)
@@ -93,8 +94,8 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 		try {
 			StringBuilder sb = new StringBuilder();
 			sb.append("select infos from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ")
-				.append(" inner join fetch infos.resource as resource")
-				.append(" inner join fetch infos.identity as identity")
+			  .append(" inner join fetch infos.resource as resource")
+			  .append(" inner join infos.identity as identity")
 			  .append(" where identity.key=:identityKey and resource.key in (:resKeys)");
 
 			List<Long> resourceKeys = PersistenceHelper.toKeys(resources);
@@ -117,35 +118,94 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 	 * @return
 	 */
 	@Override
-	public void updateUserCourseInformations(final Long courseResourceableId, final Identity identity) {
-		OLATResourceable lockRes = OresHelper.createOLATResourceableInstance("CourseLaunchDate::Identity", identity.getKey());
-		CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(lockRes, new SyncerExecutor(){
-			@Override
-			public void execute() {
-				try {
-					UserCourseInfosImpl infos = getUserCourseInformations(courseResourceableId, identity);
-					if(infos == null) {
-						OLATResource courseResource = resourceManager.findResourceable(courseResourceableId, "CourseModule");
-						infos = new UserCourseInfosImpl();
-						infos.setIdentity(identity);
-						infos.setInitialLaunch(new Date());
-						infos.setLastModified(new Date());
-						infos.setRecentLaunch(new Date());
-						infos.setVisit(1);
-						infos.setResource(courseResource);
-						dbInstance.getCurrentEntityManager().persist(infos);
-					} else if(needUpdate(infos)) {
-						dbInstance.getCurrentEntityManager().refresh(infos);
-						infos.setVisit(infos.getVisit() + 1);
-						infos.setRecentLaunch(new Date());
-						infos.setLastModified(new Date());
-						infos = dbInstance.getCurrentEntityManager().merge(infos);
+	public void updateUserCourseInformations(final Long courseResourceableId, final Identity identity, final boolean strict) {
+		UltraLightInfos ulInfos = getUserCourseInformationsKey(courseResourceableId, identity);
+		if(ulInfos == null) {
+			OLATResourceable lockRes = OresHelper.createOLATResourceableInstance("CourseLaunchDate::Identity", identity.getKey());
+			CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(lockRes, new SyncerExecutor(){
+				@Override
+				public void execute() {
+					try {
+						UltraLightInfos ulInfos = getUserCourseInformationsKey(courseResourceableId, identity);
+						if(ulInfos == null) {
+							OLATResource courseResource = resourceManager.findResourceable(courseResourceableId, "CourseModule");
+							UserCourseInfosImpl infos = new UserCourseInfosImpl();
+							infos.setIdentity(identity);
+							infos.setCreationDate(new Date());
+							infos.setInitialLaunch(new Date());
+							infos.setLastModified(new Date());
+							infos.setRecentLaunch(new Date());
+							infos.setVisit(1);
+							infos.setResource(courseResource);
+							dbInstance.getCurrentEntityManager().persist(infos);
+						} else if(strict || needUpdate(ulInfos)) {
+							UserCourseInfosImpl infos = loadById(ulInfos.getKey());
+							if(infos != null) {
+								infos.setVisit(infos.getVisit() + 1);
+								infos.setRecentLaunch(new Date());
+								infos.setLastModified(new Date());
+								infos = dbInstance.getCurrentEntityManager().merge(infos);
+							}
+						}
+					} catch (Exception e) {
+						logError("Cannot update course informations for: " + identity + " from " + identity, e);
 					}
-				} catch (Exception e) {
-					logError("Cannot update course informations for: " + identity + " from " + identity, e);
 				}
+			});
+		} else if(strict || needUpdate(ulInfos)) {
+			UserCourseInfosImpl infos = loadById(ulInfos.getKey());
+			if(infos != null) {
+				infos.setVisit(infos.getVisit() + 1);
+				infos.setRecentLaunch(new Date());
+				infos.setLastModified(new Date());
+				infos = dbInstance.getCurrentEntityManager().merge(infos);
 			}
-		});
+		}
+	}
+	
+	private UserCourseInfosImpl loadById(Long id) {
+		try {
+			String sb = "select infos from usercourseinfos as infos where infos.key=:key";
+
+			TypedQuery<UserCourseInfosImpl> query = dbInstance.getCurrentEntityManager()
+					.createQuery(sb, UserCourseInfosImpl.class)
+					.setParameter("key", id);
+
+			List<UserCourseInfosImpl> infoList = query.getResultList();
+			if(infoList.isEmpty()) {
+				return null;
+			}
+			return infoList.get(0);
+		} catch (Exception e) {
+			logError("Cannot retrieve course informations for: " + id, e);
+			return null;
+		}
+	}
+	
+	private UltraLightInfos getUserCourseInformationsKey(Long courseResourceId, Identity identity) {
+		try {
+			StringBuilder sb = new StringBuilder();
+			sb.append("select infos.key, infos.lastModified from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ")
+			  .append(" inner join infos.resource as resource")
+			  .append(" inner join infos.identity as identity")
+			  .append(" where identity.key=:identityKey and resource.resId=:resId and resource.resName='CourseModule'");
+
+			List<Object[]> infoList = dbInstance.getCurrentEntityManager()
+					.createQuery(sb.toString(), Object[].class)
+					.setParameter("identityKey", identity.getKey())
+					.setParameter("resId", courseResourceId)
+					.getResultList();
+
+			if(infoList.isEmpty()) {
+				return null;
+			}
+			Object[] infos = infoList.get(0);
+			
+			return new UltraLightInfos((Long)infos[0], (Date)infos[1]);
+		} catch (Exception e) {
+			logError("Cannot retrieve course informations for: " + identity + " from " + identity, e);
+			return null;
+		}
 	}
 	
 	/**
@@ -155,10 +215,10 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 	 * opens a course several times.
 	 * @return
 	 */
-	private final boolean needUpdate(UserCourseInfosImpl infos) {
+	private final boolean needUpdate(UltraLightInfos infos) {
 		Date lastModified = infos.getLastModified();
 		if(System.currentTimeMillis() - lastModified.getTime()  < 60000) {
-			return false;
+			return true;
 		}
 		return true;
 	}
@@ -173,7 +233,8 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			StringBuilder sb = new StringBuilder();
 			sb.append("select infos.initialLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ")
 			  .append(" inner join infos.resource as resource")
-			  .append(" where infos.identity.key=:identityKey and resource.resId=:resId and resource.resName='CourseModule'");
+			  .append(" inner join infos.identity as identity")
+			  .append(" where identity.key=:identityKey and resource.resId=:resId and resource.resName='CourseModule'");
 
 			List<Date> infoList = dbInstance.getCurrentEntityManager()
 					.createQuery(sb.toString(), Date.class)
@@ -256,4 +317,21 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			return -1;
 		}
 	}
+	
+	private static class UltraLightInfos {
+		private final Long key;
+		private final Date lastModified;
+		
+		public UltraLightInfos(Long key, Date lastModified) {
+			this.key = key;
+			this.lastModified = lastModified;
+		}
+		
+		public Long getKey() {
+			return key;
+		}
+		public Date getLastModified() {
+			return lastModified;
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.hbm.xml b/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.hbm.xml
deleted file mode 100644
index b34c9dfc065a0d1949f2a62f132213348432170d..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.hbm.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
-	"-//Hibernate/Hibernate Mapping DTD//EN"
-	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-<hibernate-mapping default-lazy="false">
-  
-  <class name="org.olat.course.assessment.model.UserCourseInfosImpl" table="o_as_user_course_infos">	
-	<cache usage="transactional" />
-
-	<id name="key" type="long" column="id"	unsaved-value="null">
-		<generator class="hilo"/>
-	</id>
-
-	<version name="version" access="field" column="version" type="int"/>
-	<property name="creationDate" column="creationdate" type="timestamp" />
-	<property name="lastModified" column="lastmodified" type="timestamp" />
-	
-	
-	<property name="initialLaunch" column="initiallaunchdate" type="timestamp" />
-	<property name="recentLaunch" column="recentlaunchdate" type="timestamp" />
-
-	<property name="visit" column="visit" type="int" />
-	<property name="timeSpend" column="timespend" type="long" />
-	
-	<many-to-one name="resource"
-                 column="fk_resource_id"
-                 foreign-key="none"
-                 class="org.olat.resource.OLATResourceImpl"
-                 outer-join="true"
-                 unique="false"
-                 not-found="ignore"
-                 cascade="none"/>
-                 
-	<many-to-one name="identity"
-                 column="fk_identity"
-                 foreign-key="cx_eff_statement_to_identity"
-                 class="org.olat.basesecurity.IdentityImpl"
-                 outer-join="true"
-                 unique="false"
-                 cascade="none"/>
-	
-  </class>
-</hibernate-mapping>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.java b/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.java
index c1b870c652cfdf164f01949990f8952328fb0cc6..e7692db2badb0417d13e792d41f3d61b9929bd29 100644
--- a/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.java
+++ b/src/main/java/org/olat/course/assessment/model/UserCourseInfosImpl.java
@@ -1,5 +1,5 @@
 /**
- * <a href="http://www.openolat.org">
+$ * <a href="http://www.openolat.org">
  * OpenOLAT - Online Learning and Training</a><br>
  * <p>
  * Licensed under the Apache License, Version 2.0 (the "License"); <br>
@@ -21,25 +21,84 @@ package org.olat.course.assessment.model;
 
 import java.util.Date;
 
-import org.olat.core.commons.persistence.PersistentObject;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.basesecurity.IdentityImpl;
 import org.olat.core.id.Identity;
 import org.olat.core.id.ModifiedInfo;
+import org.olat.core.id.Persistable;
 import org.olat.course.assessment.UserCourseInformations;
 import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceImpl;
 
-public class UserCourseInfosImpl extends PersistentObject implements UserCourseInformations, ModifiedInfo {
+@Entity(name="usercourseinfos")
+@Table(name="o_as_user_course_infos")
+public class UserCourseInfosImpl implements UserCourseInformations, Persistable, ModifiedInfo {
 
 	private static final long serialVersionUID = -6933599547069673655L;
 	
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+
+	//de facto removing the optimistic locking
+	@Column(name="version", nullable=false, insertable=true, updatable=false)
+	private Integer version = 0;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
 	private Date lastModified;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="initiallaunchdate", nullable=false, insertable=true, updatable=true)
 	private Date initialLaunch;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="recentlaunchdate", nullable=false, insertable=true, updatable=true)
 	private Date recentLaunch;
+
+	@Column(name="visit", nullable=false, insertable=true, updatable=true)
 	private int visit;
+	@Column(name="timespend", nullable=false, insertable=true, updatable=true)
 	private long timeSpend;
 	
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_identity", nullable=false, updatable=false)
 	private Identity identity;
+	@ManyToOne(targetEntity=OLATResourceImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_resource_id", nullable=false, updatable=false)
 	private OLATResource resource;
 
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
 	@Override
 	public Date getLastModified() {
 		return lastModified;
@@ -107,6 +166,11 @@ public class UserCourseInfosImpl extends PersistentObject implements UserCourseI
 	public int hashCode() {
 		return getKey() == null ? 9271 : getKey().hashCode();
 	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
 	
 	@Override
 	public boolean equals(Object obj) {
diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java
index 01ff99294d9ace375a12e49636290a399e99dd02..aaed4a201919029d528d82359c0d6a75d8a1737e 100644
--- a/src/main/java/org/olat/course/run/RunMainController.java
+++ b/src/main/java/org/olat/course/run/RunMainController.java
@@ -344,8 +344,8 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	}
 	
 	private void setLaunchDates(final Identity identity) {
-		UserCourseInformationsManager efficiencyStatementManager = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
-		efficiencyStatementManager.updateUserCourseInformations(uce.getCourseEnvironment().getCourseResourceableId(), getIdentity());
+		UserCourseInformationsManager userCourseInfoMgr = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
+		userCourseInfoMgr.updateUserCourseInformations(uce.getCourseEnvironment().getCourseResourceableId(), getIdentity(), false);
 	}
 	
 	/**
diff --git a/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java b/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java
index 9d0316529bbbf556f9c79c642fa4293a0e1a36ab..106d0f6dbc66b9c069c2b384d5b0c010480cb316 100644
--- a/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java
+++ b/src/test/java/org/olat/course/assessment/manager/UserCourseInformationsManagerTest.java
@@ -20,15 +20,20 @@
 package org.olat.course.assessment.manager;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.UserCourseInformations;
 import org.olat.restapi.repository.course.CoursesWebService;
@@ -43,6 +48,8 @@ import org.springframework.beans.factory.annotation.Autowired;
  *
  */
 public class UserCourseInformationsManagerTest extends OlatTestCase {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserCourseInformationsManagerTest.class);
 
 	@Autowired
 	private DB dbInstance;
@@ -50,12 +57,12 @@ public class UserCourseInformationsManagerTest extends OlatTestCase {
 	private UserCourseInformationsManager userCourseInformationsManager;
 	
 	@Test
-	public void createUpdateCourseInfos() {
+	public void createUpdateCourseInfos_create() {
 		Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-1-" + UUID.randomUUID().toString());
 		ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null);
 		dbInstance.commitAndCloseSession();
 		
-		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user);
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user, true);
 		dbInstance.commitAndCloseSession();
 		
 		UserCourseInformations infos = userCourseInformationsManager.getUserCourseInformations(course.getResourceableId(), user);
@@ -71,13 +78,30 @@ public class UserCourseInformationsManagerTest extends OlatTestCase {
 		Assert.assertEquals(course.getResourceableTypeName(), infos.getResource().getResourceableTypeName());
 	}
 	
+	@Test
+	public void createUpdateCourseInfos_updateToo() {
+		Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-1-" + UUID.randomUUID().toString());
+		ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null);
+		dbInstance.commitAndCloseSession();
+		
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user, true);
+		dbInstance.commitAndCloseSession();
+		
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user, true);
+		dbInstance.commitAndCloseSession();
+		
+		UserCourseInformations infos = userCourseInformationsManager.getUserCourseInformations(course.getResourceableId(), user);
+		Assert.assertNotNull(infos);
+		Assert.assertNotNull(infos.getIdentity());
+	}
+	
 	@Test
 	public void getInitialLaunchDate() {
 		Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-2-" + UUID.randomUUID().toString());
 		ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null);
 		dbInstance.commitAndCloseSession();
 		
-		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user);
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user, true);
 		dbInstance.commitAndCloseSession();
 		
 		Date launchDate = userCourseInformationsManager.getInitialLaunchDate(course.getResourceableId(), user);
@@ -91,8 +115,8 @@ public class UserCourseInformationsManagerTest extends OlatTestCase {
 		ICourse course = CoursesWebService.createEmptyCourse(user1, "course-launch-dates", "course long name", null);
 		dbInstance.commitAndCloseSession();
 		
-		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user1);
-		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user2);
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user1, true);
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user2, true);
 		dbInstance.commitAndCloseSession();
 		
 		List<Identity> users = new ArrayList<Identity>();
@@ -107,4 +131,105 @@ public class UserCourseInformationsManagerTest extends OlatTestCase {
 		Assert.assertTrue(launchDates.containsKey(user2.getKey()));
 		Assert.assertNotNull(launchDates.get(user2.getKey()));
 	}
+	
+	
+	/**
+	 * This test is to analyze a red screen
+	 */
+	@Test
+	public void updateInitialLaunchDates_loop() {
+		Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-5-" + UUID.randomUUID().toString());
+		ICourse course = CoursesWebService.createEmptyCourse(user, "course-launch-dates", "course long name", null);
+		dbInstance.commitAndCloseSession();
+		
+		for(int i=0; i<10; i++) {
+			userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), user, true);
+		}
+		dbInstance.commitAndCloseSession();
+		
+		List<Identity> users = Collections.singletonList(user);
+		Map<Long,Date> launchDates = userCourseInformationsManager.getInitialLaunchDates(course.getResourceableId(), users);
+		Assert.assertNotNull(launchDates);
+		Assert.assertEquals(1, launchDates.size());
+		Assert.assertTrue(launchDates.containsKey(user.getKey()));
+		Assert.assertNotNull(launchDates.get(user.getKey()));
+	}
+	
+	/**
+	 * This test is to analyze a red screen
+	 */
+	@Test
+	public void updateInitialLaunchDates_concurrent() {
+		Identity user = JunitTestHelper.createAndPersistIdentityAsUser("user-launch-concurrent-6-" + UUID.randomUUID().toString());
+		ICourse course = CoursesWebService.createEmptyCourse(user, "course-concurrent-launch-dates", "course long name", null);
+		dbInstance.commitAndCloseSession();
+		
+		final int numThreads = 20;
+		
+		CountDownLatch latch = new CountDownLatch(numThreads);
+		UpdateThread[] threads = new UpdateThread[numThreads];
+		for(int i=0; i<threads.length;i++) {
+			threads[i] = new UpdateThread(user, course.getResourceableId(), userCourseInformationsManager, latch, dbInstance);
+		}
+
+		for(int i=0; i<threads.length;i++) {
+			threads[i].start();
+		}
+		
+		try {
+			latch.await(120, TimeUnit.SECONDS);
+		} catch (InterruptedException e) {
+			log.error("", e);
+		}
+		
+		int countErrors = 0;
+		for(int i=0; i<threads.length;i++) {
+			countErrors += threads[i].getErrors();
+		}
+		
+		Assert.assertEquals(0, countErrors);
+	}
+	
+	private static class UpdateThread extends Thread {
+		
+		private final DB db;
+		private final CountDownLatch latch;
+		private final UserCourseInformationsManager uciManager;
+		
+		private final Long courseResourceableId;
+		private final Identity user;
+		
+		private int errors = 0;
+		
+		public UpdateThread(Identity user, Long courseResourceableId,
+				UserCourseInformationsManager uciManager, CountDownLatch latch, DB db) {
+			this.user = user;
+			this.courseResourceableId = courseResourceableId;
+			this.uciManager = uciManager;
+			this.latch = latch;
+			this.db = db;
+		}
+
+		public int getErrors() {
+			return errors;
+		}
+
+		@Override
+		public void run() {
+			try {
+				Thread.sleep(10);
+				for(int i=0; i<25;i++) {
+					uciManager.updateUserCourseInformations(courseResourceableId, user, true);
+					uciManager.getUserCourseInformations(courseResourceableId, user);
+					uciManager.updateUserCourseInformations(courseResourceableId, user, true);
+					db.commitAndCloseSession();
+				}
+			} catch (Exception e) {
+				log.error("", e);
+				errors++;
+			} finally {
+				latch.countDown();
+			}
+		}
+	}
 }