0

想象一下,我有一个名为 Photo 的表和一个名为 Tag 的表。

一张照片可以有任意数量的标签。就像柏林勃兰登堡门的照片一样,标签为“柏林”,“门”,......

现在有第二张柏林国会大厦的照片,也有“柏林”作为它的标签之一。

目前这将被冗余保存在我的数据库中,这意味着在我的标记表中“柏林”出现了两次,并且在我的由休眠创建的连接表中,每个元组都指向它自己的“柏林”标记。

我不喜欢这种情况,因为这意味着我在我的数据库中保存了冗余数据。我更喜欢标签“Berlin”在我的标签表中只保存一次的情况,并且每张具有此标签的照片都会获得对这个标签对象的引用。

总结如下:

之前(我希望现在可以正确显示,当我发送这个问题时)

照片

身份证 | 照片名称
1 | 勃兰登堡门
2 | 德国国会大厦 ...| ...

标签

身份证 | 标记名 1 | 柏林 2 | 仓鼠 3 | 柏林 4 | 柏林 5 | 鸟...| ...

PHOTO_TAG(连接表)

照片ID | 标签ID 1 | 1 2 | 3 3 | 4 ... | ...

希望之后:

照片

身份证 | 照片名称
1 | 勃兰登堡门
2 | 德国国会大厦 ...| ...

标签

身份证 | 标记名 1 | 柏林 2 | 仓鼠 3 | 鸟...| ...

PHOTO_TAG(加入表) photoID | 标签ID 1 | 1 2 | 1 3 | 1 ... | ...

如您所见,Berlin 只需要在 Tag 表中保存一次,而仍然没有信息丢失,因为连接表在 tupel 上引用正确。

我试图在 postgresql 数据库上使用休眠(我不是专业人士)来实现这一点。我的 Photo-Class 有一个属性 photoTags,我给了它一个 ManyToMany 关系(我认为这可能意味着每张照片可以有任意数量的标签,而每个标签可以有任意数量的它们被引用的照片)

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Tag> photoTags;

但很简单,这行不通。我的标签表中有很多冗余数据。a 现在我的问题是:你知道任何足以让我意识到这一点的方法吗?感谢您的每一个回答和评论(如果您需要任何进一步的信息,例如我的 hibernate.cfg.xml,请告诉我)。

(这里的这个问题正在处理类似的问题,但答案对我来说并不令人满意: Normalize repeating values in Hibernate - Java

编辑:我现在附上我的休眠类:

用户.java

import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;

@Column(unique = true)
private String userID;
private String userName; 
private String userRealName;
private int userPhotoCount;
private Date userPhotoF;
private Date userPhot_1;
private String userLocation;
private String userThumbnailURL;
private int userIsPro;
private int userIsAdmin;
private int userContact;
private int userPhotoS;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Photo> photos;

public User(String userID, String userName, String userRealName, int userPhotoCount,
        Date userPhotoF, Date userPhot_1, String userLocation,
        String userThumbnailURL, int userIsPro, int userIsAdmin,
        int userContact, int userPhotoS, Set<Photo> photos) {
    this.userID = userID;
    this.userName = userName; 
    this.userRealName = userRealName;
    this.userPhotoCount = userPhotoCount;
    this.userPhotoF = userPhotoF;
    this.userPhot_1 = userPhot_1;
    this.userLocation = userLocation;
    this.userThumbnailURL = userThumbnailURL;
    this.userIsPro = userIsPro;
    this.userIsAdmin = userIsAdmin;
    this.userContact = userContact;
    this.userPhotoS = userPhotoS;
    this.photos = photos;

}

// Hibernate requirement
public User() {
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getUserID() {
    return userID;
}

public void setUserID(String userID) {
    this.userID = userID;
}

public String getUserRealName() {
    return userRealName;
}

public void setUserRealName(String userRealName) {
    this.userRealName = userRealName;
}

public int getUserPhotoCount() {
    return userPhotoCount;
}

public void setUserPhotoCount(int userPhotoCount) {
    this.userPhotoCount = userPhotoCount;
}

public Date getUserPhotoF() {
    return userPhotoF;
}

public void setUserPhotoF(Date userPhotoF) {
    this.userPhotoF = userPhotoF;
}

public Date getUserPhot_1() {
    return userPhot_1;
}

public void setUserPhot_1(Date userPhot_1) {
    this.userPhot_1 = userPhot_1;
}

public String getUserLocation() {
    return userLocation;
}

public void setUserLocation(String userLocation) {
    this.userLocation = userLocation;
}

public String getUserThumbnailURL() {
    return userThumbnailURL;
}

public void setUserThumbnailURL(String userThumbnailURL) {
    this.userThumbnailURL = userThumbnailURL;
}

public int getUserIsPro() {
    return userIsPro;
}

public void setUserIsPro(int userIsPro) {
    this.userIsPro = userIsPro;
}

public int getUserIsAdmin() {
    return userIsAdmin;
}

public void setUserIsAdmin(int userIsAdmin) {
    this.userIsAdmin = userIsAdmin;
}

public int getUserContact() {
    return userContact;
}

public void setUserContact(int userContact) {
    this.userContact = userContact;
}

public int getUserPhotoS() {
    return userPhotoS;
}

public void setUserPhotoS(int userPhotoS) {
    this.userPhotoS = userPhotoS;
}

public Set<Photo> getUserPhotos() {
    return photos;
}

public void setUserPhotos(Set<Photo> userPhotos) {
    this.photos = userPhotos;
}

public void addPhoto(Photo photo){
    this.photos.add(photo); 
}

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

}

照片.java

import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Photo {

@Id
@GeneratedValue
private Long id;

private Long photoID;
private String photoTitle;
private String photoUrl;
private int photoAccur;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Tag> photoTags;

private int photoTagsCount;
// ist das korrekt?
private int photoCommentCount;
// date objekte
private Date photoDateP;
private Date photoDateT;
private String photoDescription;
// korrekter Name?
private String photoNotes;
private int photoNot_1;
private String photoMedia;
private String photoMed_1;
private int photoLicense;
private int photoIsFam;
private int photoIsFri;
private int photoIsPri;
// x-Achse
private float photoLongitude;
// y-Achse
private float photoLatitude;

public Photo(Long photoID, String photoTitle, String photoURL,
        int photoAccur, Set<Tag> photoTags, int photoTagsCount,
        int photoCommentCount, Date photoDateP, Date photoDateT,
        String photoDescription, String photoNotesCount, int photoNot_1,
        String photoMedia, String photoMed_1, int photoLicense,
        int photoIsFam, int photoIsFri, int photoIsPri, float photoLongi,
        float photoLatit) {
    this.photoID = photoID;
    this.photoTitle = photoTitle;
    this.photoUrl = photoURL;
    this.photoAccur = photoAccur;
    this.photoTags = photoTags;
    this.photoTagsCount = photoTagsCount;
    this.photoCommentCount = photoCommentCount;
    this.photoDateP = photoDateP;
    this.photoDateT = photoDateT;
    this.photoDescription = photoDescription;
    this.photoNotes = photoNotesCount;
    this.photoNot_1 = photoNot_1;
    this.photoMedia = photoMedia;
    this.photoMed_1 = photoMed_1;
    this.photoLicense = photoLicense;
    this.photoIsFam = photoIsFam;
    this.photoIsFri = photoIsFri;
    this.photoIsPri = photoIsPri;
    this.photoLongitude = photoLongi;
    this.photoLatitude = photoLatit;
}

// hibernate
public Photo() {
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Long getPhotoID() {
    return photoID;
}

public void setPhotoID(Long photoID) {
    this.photoID = photoID;
}

public String getPhotoTitle() {
    return photoTitle;
}

public void setPhotoTitle(String photoTitle) {
    this.photoTitle = photoTitle;
}

public String getPhotoUrl() {
    return photoUrl;
}

public void setPhotoUrl(String photoUrl) {
    this.photoUrl = photoUrl;
}

public int getPhotoAccur() {
    return photoAccur;
}

public void setPhotoAccur(int photoAccur) {
    this.photoAccur = photoAccur;
}

public Set<Tag> getPhotoTags() {
    return photoTags;
}

public void setPhotoTags(Set<Tag> photoTags) {
    this.photoTags = photoTags;
}

public int getPhotoTagsCount() {
    return photoTagsCount;
}

public void setPhotoTagsCount(int photoTagsCount) {
    this.photoTagsCount = photoTagsCount;
}

public int getPhotoCommentCount() {
    return photoCommentCount;
}

public void setPhotoCommentCount(int photoCommentCount) {
    this.photoCommentCount = photoCommentCount;
}

public Date getPhotoDateP() {
    return photoDateP;
}

public void setPhotoDateP(Date photoDateP) {
    this.photoDateP = photoDateP;
}

public Date getPhotoDateT() {
    return photoDateT;
}

public void setPhotoDateT(Date photoDateT) {
    this.photoDateT = photoDateT;
}

public String getPhotoDescription() {
    return photoDescription;
}

public void setPhotoDescription(String photoDescription) {
    this.photoDescription = photoDescription;
}

public String getPhotoNotesCount() {
    return photoNotes;
}

public void setPhotoNotesCount(String photoNotesCount) {
    this.photoNotes = photoNotesCount;
}

public int getPhotoNot_1() {
    return photoNot_1;
}

public void setPhotoNot_1(int photoNot_1) {
    this.photoNot_1 = photoNot_1;
}

public String getPhotoMedia() {
    return photoMedia;
}

public void setPhotoMedia(String photoMedia) {
    this.photoMedia = photoMedia;
}

public String getPhotoMed_1() {
    return photoMed_1;
}

public void setPhotoMed_1(String photoMed_1) {
    this.photoMed_1 = photoMed_1;
}

public int getPhotoLicense() {
    return photoLicense;
}

public void setPhotoLicense(int photoLicense) {
    this.photoLicense = photoLicense;
}

public int getPhotoIsFam() {
    return photoIsFam;
}

public void setPhotoIsFam(int photoIsFam) {
    this.photoIsFam = photoIsFam;
}

public int getPhotoIsFri() {
    return photoIsFri;
}

public void setPhotoIsFri(int photoIsFri) {
    this.photoIsFri = photoIsFri;
}

public int getPhotoIsPri() {
    return photoIsPri;
}

public void setPhotoIsPri(int photoIsPri) {
    this.photoIsPri = photoIsPri;
}

public float getPhotoLongi() {
    return photoLongitude;
}

public void setPhotoLongi(float photoLongi) {
    this.photoLongitude = photoLongi;
}

public float getPhotoLatit() {
    return photoLatitude;
}

public void setPhotoLatit(float photoLatit) {
    this.photoLatitude = photoLatit;
}
}

标签.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Tag {

@Id
@GeneratedValue
private Long id; 

private String tag;

public Tag(String tag) {
    this.tag = tag;
}

public Tag() {
}

public String getTag() {
    return tag;
}

public void setTag(String tag) {
    this.tag = tag;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

}

我的 Hibernate.cfg.xml

<?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.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/GIS</property>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.connection.username">postgres</property>
        <property name="hibernate.connection.password">mysql15</property>
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.hbm2ddl.auto">create</property>
        <property name="hibernate.show_sql">false</property>

        <mapping class="database.User" />
        <mapping class="database.Photo" />
        <mapping class="database.Tag" />
    </session-factory>
</hibernate-configuration>

**现在一些类正在处理我的会话管理与休眠。它们可能并不那么重要,但以防万一。**

DAO.java

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.stat.Statistics;

/**
 * DAO provides general access methods on the database related to session
 * management (opening and closing)
 * 
 * 
 * 
 */
public abstract class DAO {

    /**
     * Logs about correct behaviour of the hibernate session management
     */
    public static Statistics stats = statistics();

    /**
     * Ensures that every client gets his correct session
     */
    private static final ThreadLocal<Session> sessions = new ThreadLocal<>();

    /**
     * Returns the current hibernate session. Also takes care that there's
     * always an open hibernate transaction when needed.
     * 
     * @return Current hibernate session
     */
    public static Session getSession() {
        Session result = sessions.get();
        if (result == null) {
            result = HibernateUtil.getSessionFactory().openSession();
            sessions.set(result);
            result.beginTransaction();
        }

        return result;
    }

    /**
     * Closes the current hibernate session, if there is one.
     */
    public static void closeSession() {
        Session sess = sessions.get();
        if (sess == null || !sess.isOpen())
            return;
        sessions.remove();

        try {
            Throwable error = null;
            try {
                if (sess.getTransaction().isActive() == true) {
                    sess.getTransaction().commit();
                }
            } catch (Throwable e) {
                sess.getTransaction().rollback();
                error = e;
            } finally {
                try {
                    System.out.println("Sessions geöffnet bisher: "
                            + stats.getSessionOpenCount());
                    sess.close();
                    System.out.println("Sessions geschlossen bisher: "
                            + stats.getSessionCloseCount());
                } catch (Throwable th) {
                    if (error != null) {
                        error.addSuppressed(th);
                    } else {
                        throw th;
                    }
                }
            }
        } catch (HibernateException ex) {
            ex.printStackTrace();
        }
    }

    public static Statistics statistics() {
        Statistics stats = HibernateUtil.getSessionFactory().getStatistics();
        stats.setStatisticsEnabled(true);
        return stats;
    }

}

用户DAO.java

import java.util.List;

import org.hibernate.Session;

public class UserDAO extends DAO {

    public void createUser(User user) {
        if (user == null) {
            throw new IllegalArgumentException("user must be not null");
        }

        Session session = getSession();

        // speichern des test in der datenbank
        session.save(user);

        closeSession();

    }

    public void updateUser(User user) {
        if (user == null) {
            throw new IllegalArgumentException("User doesnt exist");
        }
        Session session = getSession();

        // updaten des Users in der datenbank
        session.saveOrUpdate(user);

        closeSession();
    }

    public User getUser(Long userID) {
        Session session = getSession();

        @SuppressWarnings("unchecked")
        List<User> oneUser = session.createQuery(
                "FROM User WHERE id = " + userID).list();

        closeSession();

        return oneUser.get(0);
    }

    public User getUserByUserID(String userID) {
        Session session = getSession();

        @SuppressWarnings("unchecked")
        List<User> oneUser = session.createQuery(
                "FROM User WHERE userID = '" + userID + "'").list();

        closeSession();
        if (oneUser.size() > 0) {
            return oneUser.get(0);
        } else {
            // user existiert nicht
            return null;
        }

    }

    public List<User> getAllUsers() {
        Session session = getSession();

        @SuppressWarnings("unchecked")
        List<User> allUsers = session.createQuery("FROM users").list();

        closeSession();

        return allUsers;
    }

}

HibernateUtil.java

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * HibernateUtil manages the access to the sessionFactory, which ensures that
 * there's always an open database session
 * 
 * 
 * 
 */
@SuppressWarnings("deprecation")
public class HibernateUtil {

    final private static SessionFactory sessionFactory;

    static {
        try {
            // create the sessionfactory from standardconfig file
            sessionFactory = new Configuration().configure("hibernate.cfg.xml")
                    .buildSessionFactory();

        } catch (Throwable ex) {
            // log the exception
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    /**
     * Returns the current SessionFactory
     * 
     * @return Current SessionFactory
     */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

HibernateListener.java

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;


/**
 * The HibernateListener takes care that hibernate for the database connection
 * management gets initialised on the server start.
 */
public class HibernateListener implements ServletContextListener {

    /**
     * Calls the static initializer of the HibernateUtil class
     */
    public void contextInitialized(ServletContextEvent event) {
        HibernateUtil.getSessionFactory(); // Just call the static initializer
                                            // of that class
    }

    /**
     * Frees all ressources when the server is being restarted
     */
    public void contextDestroyed(ServletContextEvent event) {
        HibernateUtil.getSessionFactory().close(); // Free all resources
    }
}
4

1 回答 1

2

您期望它工作的方式就是它应该如何工作。

我在您发布的 Hibernate 模型类中没有发现任何问题,因此我只能假设您正在为照片设置新的 Tag 实例,而不是加载它们并设置它们。

当你这样做时,hibernate 不知道这些对象是否相等,因为它们没有设置 ID(你只是创建它们还记得吗?)。

加载 Tag 对象并将它们分配给照片,或者如果您一心想要添加新实例,请删除 cascade all 选项并覆盖 equals 方法以考虑除 ID 之外的其他详细信息(如果未设置 id(null))。

于 2013-05-08T02:39:58.433 回答