J'ai un problème d'hibernation que je ne peux pas résoudre.
La configuration: Java EE, application Web, Hibernate 3.2, Tomcat 6, Struts 2.
Fondamentalement, je persiste un objet avec la logique de mon serveur (une action struts), puis j'essaie d'extraire ces données pour la page suivante et de les afficher.
Je vérifie la base de données après avoir sauvegardé l'objet et, bien entendu, je peux voir la ligne avec toutes les données.
Mais quand j'essaye de le récupérer, j'obtiens ceci:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [msc.model.Picture#73]
Pour rendre les choses encore plus confuses, lorsque je redémarre Tomcat et que j'essaie d'accéder au même objet, je ne reçois pas l'erreur - Hibernate trouve la ligne correctement.
Hibernate sera également capable de voir la ligne si je fais d'autres opérations - peut-être ajouter une ligne ici et là à la base de données, même pas sur la même table.
De tout cela, je soupçonne un bug d'Hibernate, mais je suis un débutant d'Hibernate, alors je me trompe probablement. S'il vous plaît aider! J'ai googlé et googlé en vain.
Voici ma configuration Hibernate:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/msc</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">-------</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">80</property>
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping resource="msc/model/Picture.hbm.xml"/>
<mapping resource="msc/model/Comment.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Voici mes deux fichiers de mapping:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="msc.model.Picture" table="PICTURE">
<id column="PICTURE_ID" name="id">
<generator class="native"/>
</id>
<property name="story"/>
<property name="email"/>
<property name="category"/>
<property name="state"/>
<property name="ratings"/>
<property name="views"/>
<property name="timestamp"/>
<property name="title"/>
<property lazy="true" name="image" type="blob">
<column name="IMAGE"/>
</property>
<property lazy="true" name="refinedImage" type="blob">
<column name="REFINEDIMAGE"/>
</property>
<property lazy="true" name="thumbnail" type="blob">
<column name="THUMBNAIL"/>
</property>
<bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
<key column="PICTURE"/>
<one-to-many class="msc.model.Comment"/>
</bag>
</class>
</hibernate-mapping>
et
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="msc.model.User" table="USER">
<id column="USER_ID" name="id">
<generator class="native"/>
</id>
<property name="username"/>
<property name="email"/>
<bag cascade="save-update" lazy="true" name="pictures" table="PICTURE">
<key column="USER"/>
<one-to-many class="msc.model.Picture"/>
</bag>
<bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
<key column="USER"/>
<one-to-many class="msc.model.Comment"/>
</bag>
</class>
</hibernate-mapping>
S'il vous plaît laissez-moi savoir si vous avez besoin de plus d'informations, je suis heureux d'obliger.
(note: ceci n'est pas un doublon de cette question, le scénario n'est pas le même "Aucune ligne avec l'identifiant donné n'existe" bien qu'il existe } _)
EDIT: comme demandé, en postant du code Java:
Code pour sauvegarder l'objet
Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();
hib_ses.beginTransaction();
hib_ses.save(user);
hib_ses.getTransaction().commit();
Code pour afficher les données (une image dans ce cas)
public class ImageAction extends ActionSupport implements ServletResponseAware, SessionAware {
private HttpServletResponse response;
Map session;
private Long id;
private int thumbnail;
private InputStream inputStream;
@Override
public String execute() throws Exception {
response.setContentType("image/jpeg");
Session hib_session = HibernateUtil.getSessionFactory().getCurrentSession();
hib_session.beginTransaction();
//what is the ID now?
Picture pic = (Picture) hib_session.load(Picture.class, getId());
if (thumbnail == 1) {
inputStream = (ByteArrayInputStream) pic.getThumbnail().getBinaryStream();
} else {
inputStream = (ByteArrayInputStream) pic.getRefinedImage().getBinaryStream();
}
hib_session.close();
return SUCCESS;
}
Vérifiez tous vos mappages et paramètres de base de données. Il est possible que vous définissiez des valeurs non-null = "true" dans les relations de clé étrangère lorsque votre base de données dit nullable = "true". La première cause une jointure interne et la seconde cause une jointure gauche.
Définissez le niveau de consignation sur TRACE pour afficher toutes les étapes et recherchez le SQL généré lors de la récupération des objets.
Cela est dû au fait que vous avez inséré quelque chose qui est censé être une clé étrangère sans faire référence à rien ..__ Vérifiez si votre base de données existe ou non (même si elle est dans la base de données d’autres tables).
Il suffit de vérifier dans votre base de données si l'ID 73 est disponible ou non dans votre table
Dans plusieurs relations, vous devez indiquer à Hibernate ce qui doit être fait si la ligne mappée est introuvable. Vous pouvez le configurer des manières suivantes:
Annotation:
@NotFound(action = NotFoundAction.IGNORE)
Mapping XML:
<many-to-one name="user" column="user_id" class="com.xyz.User" cascade="save-update, evict" not-found="ignore"/>
D'accord, je vais lancer une théorie ici. Se pourrait-il que vous essayiez de charger la photo la première fois avant que la transaction ait été validée?
Comme la transaction n'est pas encore validée, la ligne que vous utilisez pour la lecture de l'image n'est pas visible (cela dépend du niveau d'isolation de la transaction que vous avez).
Ensuite, comme hib_session.close()
ne se trouve pas dans un bloc finally
, celui-ci ne sera pas exécuté et la session liée au thread aura toujours une transaction ouverte. La requête suivante obtient la session same Hibernate, avec la même transaction ouverte, et vous obtenez le même résultat des requêtes select it (encore une fois, en fonction du niveau d’isolation de transaction - voir documentation ici , en particulier pour REPEATABLE_READ).
Cela pourrait aussi expliquer pourquoi flush()
le rend légèrement meilleur, car si flush()
survient plus tôt que commit()
, les chances que la situation de concurrence critique se produise sont moins grandes.
Je vous suggère d'essayer de fermer la session dans un bloc finally et de voir si le comportement change pour les requêtes suivantes.
Je ne vois pas de vrais problèmes concernant l'exception dans le code, vous pouvez essayer:
flush()
manuellement après validation;load()
et si le bon ID lui est transmis via le débogueurJ'ai un problème similaire avec Hibernate 3.6.10, alors que je ne fais que chercher et sélectionner (le cas échéant).
Annotation:
@Entity
public class Familiares {
@OneToMany(mappedBy = "familiares")
private List<FamiliaresBaja> bajas;
@Entity
@Table(name = "familiares_baja")
public class FamiliaresBaja implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@JoinColumn(name = "familiares_id")
@ManyToOne(optional = false)
private Familiares familiares;
alors je récupère une liste et avec ceux-ci regardant dans FamiliaresBaja s'il y en a au moins un.
createQuery("from FamiliaresBaja where familiares.id="+ id).uniqueResult() // should return a single result or null not throw a Exception
Ce doit être un bogue Hibernate
Veuillez vérifier la valeur de lower_case_table_names de votre serveur mysql. Si sa valeur est 0, vérifiez le SQL généré par hibernate, assurez-vous que la casse du nom de la table est cohérente avec le nom de la table dans mysql.
J'ai fait face à ce problème et voici ce qui s'est passé et comment je l'ai résolu. Vous avez probablement la même chose se passe aussi.
J'avais POST et les objets USER. Ils sont dans une relation OneToMany (un utilisateur peut avoir plusieurs publications). En le rendant bidirectionnel, ils sont également dans une relation ManyToOne (une publication n'appartient qu'à un seul utilisateur).
Looks post-classe
@Entity
@Table(name="Post")
public class Post {
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
private long postId;
private String title;
private String body;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "postUserId")
private AutoUser autoUser;
// getter and setters
La classe d'utilisateurs est
@Entity
@Table(name = "AUTO_USER")
public class AutoUser implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long autoUserId;
@Column(name = "USERNAME")
private String username;
@OneToMany
private List<Post> postList = new ArrayList<>();
// getter and setters
Les premiers noms de table étaient Post et AUTO_USER. Trois utilisateurs ont persisté dans une table AUTO_USER (avec l'ID 1, 2, 3) .. et 3 entrées dans la table Post 1 pour chaque utilisateur . (Les colonnes de jointure ou la clé étrangère étaient 1, 2, 3)
Ensuite, j'ai changé uniquement le nom de la table pour l'objet utilisateur uniquement et l'ai nommé @Table(name = "AUTO_USER2")
. et je n'avais qu'un seul utilisateur dans cette table avec l'identifiant 1.
Dans mon code, j'effectue une itération sur chaque message et identifie celui qui appartient à quel utilisateur et leur affiche ceux appartenant à l'utilisateur actuellement connecté.
Après avoir changé le nom de la table des messages, j'ai eu cette exception
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#2
Ce qui me dit que l'objet utilisateur avec l'id 2 n'est pas disponible dans la nouvelle table des utilisateurs.
puis j'ai enregistré un autre utilisateur avec l'identifiant 2 et plus tard, j'ai eu cette
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#3
Cette fois, il n'a pas pu trouver l'utilisateur ayant l'identifiant 3
Enfin enregistré un troisième utilisateur et n'avait pas d'exception.
Comme vous pouvez le constater, la clé étrangère existe dans la table post mais, depuis que j'ai modifié la table utilisateur, il ne pouvait y avoir de correspondance pour eux et c'est la raison pour laquelle j'ai été confronté à ce problème.
Pour éviter cette situation, j'ai créé de nouveaux noms de table pour les deux objets et commencé à nouveau
J'espère que cela aidera