想象一下,我有一个名为 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
}
}