--summary (укороченный) -Дубликат ключевой вопрос с Spring и Hibernate - помощь нужна
У меня есть контроллер, который загружает объект профиля из соответствующего DAO. Он обновляет некоторые свойства, многие из них наборы, а затем вызывает saveOrUpdate (через сохранение в DAO) для повторного подключения и обновления объекта профиля. В кажущихся случайными интервалами мы получаем org.hibernate.exception.ConstraintViolationException с основной причиной: вызвано: java.sql.BatchUpdateException: дублирующаяся запись «3-56» для ключа 1. Трассировка стека указывает на метод saveOrUpdate, называемый из контроллера обновления профиля. Я не могу реплицироваться в тестовой среде, мы видим это только в процессе производства, поэтому мне интересно, не хватает ли я чего-то связанного с потоками безопасности (именно поэтому я размещаю столько информации о кодах/конфигурации). Есть идеи?
- Код -
Я пытался представить, как много соответствующей конфигурации/код, как это возможно - дайте мне знать, если еще нужно:
Вот выдержка из контроллера нарушившей:
public class EditProfileController extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception
{
if(!checkLoggedIn(request))
{
return new ModelAndView("redirect:" + invalidRedirect);
}
HttpSession session = request.getSession();
Resource resource = (Resource)session.getAttribute("resource"); //The resource object is stored in session upon login and upon account creation.
Profile profile = profiles.getProfileByResource(resource);
if(profile == null)
{
profile = new Profile();
profile.setResource(resource);
}
//I use custom editors to populate the sets in the command object with objects based on the selection
if(profile.getPrimaryRoleSkills() != null && editProfileCommand.getPrimaryRoleSkills() != null)
{
profile.getPrimaryRoleSkills().addAll(editProfileCommand.getPrimaryRoleSkills());
profile.getPrimaryRoleSkills().retainAll(editProfileCommand.getPrimaryRoleSkills());
}
else
profile.setPrimaryRoleSkills(editProfileCommand.getPrimaryRoleSkills());
profiles.save(profile); //This is the line that appears in the stack trace
return new ModelAndView(getSuccessView());
}
//Other methods omitted
}
Сокращенный Профиль Класс:
public class Profile implements java.io.Serializable {
private long id;
private Resource resource;
private Set<PrimaryRoleSkill> primaryRoleSkills = new HashSet<PrimaryRoleSkill>(0);
public Profile() {
}
//Other properties trivial or similar to above. Getters and setters omitted
//toString, equals, and hashCode are all generated by hbm2java
}
NameValuePairs барельефа е класс (PrimaryRoleSkill расширяет это ничего не добавляя):
public class NameValuePairs implements java.io.Serializable {
private long id;
private String name;
private boolean active = true;
public NameValuePairs() {
}
//equals and hashCode generated by hbm2java, getters & setters omitted
}
Вот мой DAO базовый класс:
public class DAO {
protected DAO() {
}
public static Session getSession() {
Session session = (Session) DAO.session.get();
if (session == null) {
session = sessionFactory.openSession();
DAO.session.set(session);
}
return session;
}
protected void begin() {
getSession().beginTransaction();
}
protected void commit() {
getSession().getTransaction().commit();
}
protected void rollback() {
try {
getSession().getTransaction().rollback();
} catch(HibernateException e) {
log.log(Level.WARNING,"Cannot rollback",e);
}
try {
getSession().close();
} catch(HibernateException e) {
log.log(Level.WARNING,"Cannot close",e);
}
DAO.session.set(null);
}
public boolean save(Object object)
{
try {
begin();
getSession().saveOrUpdate(object);
commit();
return true;
}
catch (HibernateException e) {
log.log(Level.WARNING,"Cannot save",e);
rollback();
return false;
}
}
private static final ThreadLocal<Session> session = new ThreadLocal<Session>();
private static final SessionFactory sessionFactory = new Configuration()
.configure().buildSessionFactory();
private static final Logger log = Logger.getAnonymousLogger();
//Non-related methods omitted.
}
Ниже является важной частью Profiles DAO:
public class Profiles extends DAO {
public Profile getProfileByResource(Resource resource)
{
try
{
begin();
Query q = getSession().createQuery("from Profile where resource = :resource");
q.setLong("resource", resource.getId());
commit();
if(q.uniqueResult() == null)
return null;
return (Profile) q.uniqueResult();
}
catch(HibernateException e)
{
rollback();
}
return null;
}
//Non-related methods omitted.
}
Соответствующий Конфигурация пружины:
<bean id="profiles" class="com.xxxx.dao.Profiles" />
<bean id="editProfileController" class="com.xxxx.controllers.EditProfileController">
<property name="sessionForm" value="false" />
<property name="commandName" value="editProfileCommand" />
<property name="commandClass" value="com.xxxx.commands.EditProfileCommand" />
<property name="profiles" ref="profiles" />
<property name="formView" value="EditProfile" />
<property name="successView" value="redirect:/profile" />
<property name="validator" ref="profileValidator" />
</bean>
hibernate.cfg.xml
<session-factory>
<property name="connection.driver_class">@[email protected]</property>
<property name="connection.url">@[email protected]</property>
<property name="connection.username">@[email protected]</property>
<property name="connection.password">@[email protected]</property>
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="dbcp.maxActive">15</property>
<property name="dbcp.maxIdle">5</property>
<property name="dbcp.maxWait">120000</property>
<property name="dbcp.whenExhaustedAction">2</property>
<property name="dbcp.testOnBorrow">true</property>
<property name="dbcp.testOnReturn">true</property>
<property name="dbcp.validationQuery">
select 1
</property>
<property name="dbcp.ps.maxActive">0</property>
<property name="dbcp.ps.maxIdle">0</property>
<property name="dbcp.ps.maxWait">-1</property>
<property name="dbcp.ps.whenExhaustedAction">2</property>
<!-- Echo all executed SQL to stdout
<property name="show_sql">true</property>
-->
<mapping resource="com/xxxx/entity/Resource.hbm.xml"/>
<mapping resource="com/xxxx/entity/Authentication.hbm.xml"/>
<mapping resource="com/xxxx/entity/NameValuePairs.hbm.xml"/>
<mapping resource="com/xxxx/entity/Profile.hbm.xml"/>
<mapping resource="com/xxxx/entity/FileData.hbm.xml"/>
</session-factory>
Отрывок из Profile.hbm.xml:
<hibernate-mapping>
<class name="com.xxxx.entity.Profile" select-before-update="true">
<id name="id" type="long">
<generator class="foreign">
<param name="property">resource</param>
</generator>
</id>
<set name="primaryRoleSkills" cascade="none">
<key column="profile"/>
<many-to-many column="primary_role_skill" class="com.xxxx.entity.PrimaryRoleSkill"/>
</set>
</class>
</hibernate-mapping>
Отрывок из NameValuePairs.hbm.xml:
<hibernate-mapping>
<class name="com.xxxx.entity.NameValuePairs" abstract="true">
<id name="id" type="long">
<generator class="native" />
</id>
<discriminator column="type" type="string" />
<property type="string" name="name" length="256">
<meta attribute="use-in-equals">true</meta>
</property>
<property type="boolean" name="active">
<meta attribute="default-value">true</meta>
</property>
<subclass name="com.xxxx.entity.PrimaryRoleSkill" discriminator-value="PrimaryRoleSkill" />
</class>
</hibernate-mapping>
Применение работает на Tomcat 6.0.14 и подключается к MySQL версии 5.0.89-сообществу, работающему на Linux , Мы используем Hibernate 3.3.2 и Spring Framework 2.5.6.
попробуйте включить только соответствующую информацию. слишком долго читать .. – Bozho
см. http://sscce.org/ – Bozho
ваш DAO не должен запускать/фиксировать/управлять транзакциями - бизнес-объекты (службы) должны. – les2