最近工作中遇到几个与JPA相关的问题,本文通过一个例子总结一下这些问题。
1 给出一个例子:
如下图表式Persistent Context中所有实体的关系图:
所有实体间对应关系都是单向的;
User和Event,User和Friend,Event和Property,Wife和Pet,Pet和Property关系为一对多关系;
User和UserCard,Friend和UserCard,Wife和UserCard,User和Wife之间的关系是一对一关系;
如http://kylinsoong.iteye.com/blog/807937所示创建工程;
贴出相关代码:
package com.tibco.hibernate.po; import java.util.Calendar; import java.util.List; 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.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; @Entity(name="User") @Table(name="k_user") public class User { private Long id; private String name; private List<Event> events; private List<Friend> friends; private UserCard userCard; private Wife wife; private Calendar createdDate; private Boolean isMale; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany ( targetEntity=com.tibco.hibernate.po.Event.class, fetch=FetchType.LAZY, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinTable(name="k_user_event", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "EVENT_ID")) @ForeignKey(name = "k_user_event_FK", inverseName = "k_user_event_FK_R") public List<Event> getEvents() { return events; } public void setEvents(List<Event> events) { this.events = events; } @OneToMany ( targetEntity=com.tibco.hibernate.po.Friend.class, fetch=FetchType.EAGER, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinTable(name="k_user_friend", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "FRIEND_ID")) @ForeignKey(name = "k_user_friend_FK", inverseName = "k_user_friend_FK_R") public List<Friend> getFriends() { return friends; } public void setFriends(List<Friend> friends) { this.friends = friends; } @OneToOne( targetEntity = com.tibco.hibernate.po.UserCard.class, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinColumn(name = "UserCard_id") @ForeignKey(name = "USER_TO_USERCARD_FK") public UserCard getUserCard() { return userCard; } public void setUserCard(UserCard userCard) { this.userCard = userCard; } @OneToOne( targetEntity = com.tibco.hibernate.po.Wife.class, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinColumn(name = "Wife_id") @ForeignKey(name = "USER_TO_WIFE_FK") public Wife getWife() { return wife; } public void setWife(Wife wife) { this.wife = wife; } @Column(name = "CREATEDDATE") @Temporal(TemporalType.DATE) public Calendar getCreatedDate() { return createdDate; } public void setCreatedDate(Calendar createdDate) { this.createdDate = createdDate; } @Column public Boolean getIsMale() { return isMale; } public void setIsMale(Boolean isMale) { this.isMale = isMale; } }
package com.tibco.hibernate.po; import java.util.List; 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.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; @Entity(name="Event") @Table(name="k_event") public class Event { private Long id; private String name; private List<Property> properties; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany ( targetEntity=com.tibco.hibernate.po.Property.class, fetch=FetchType.LAZY, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinTable(name="k_event_property", joinColumns = @JoinColumn(name = "EVENT_ID"), inverseJoinColumns = @JoinColumn(name = "PROPERTY_ID")) @ForeignKey(name = "k_event_property_FK", inverseName = "k_event_property_FK_R") public List<Property> getProperties() { return properties; } public void setProperties(List<Property> properties) { this.properties = properties; } }
package com.tibco.hibernate.po; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity(name="Property") @Table(name="k_property") public class Property { private Long id; private String name; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return "Property [id=" + id + ", name=" + name + "]"; } }
package com.tibco.hibernate.po; 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.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; @Entity(name="Friend") @Table(name="k_friend") public class Friend { private Long id; private String name; private UserCard userCard; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToOne( targetEntity = com.tibco.hibernate.po.UserCard.class, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinColumn(name = "UserCard_id") @ForeignKey(name = "FRIEND_TO_USERCARD_FK") public UserCard getUserCard() { return userCard; } public void setUserCard(UserCard userCard) { this.userCard = userCard; } public String toString() { return "Friend [id=" + id + ", name=" + name + "]"; } }
package com.tibco.hibernate.po; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity(name="UserCard") @Table(name="k_userCard") public class UserCard { private Long id; private String cardNumber; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getCardNumber() { return cardNumber; } public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; } }
package com.tibco.hibernate.po; import java.util.List; 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.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; @Entity(name="Wife") @Table(name="k_wife") public class Wife { private Long id; private String name; private UserCard userCard; private List<Pet> pets; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToOne( targetEntity = com.tibco.hibernate.po.UserCard.class, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinColumn(name = "UserCard_id") @ForeignKey(name = "Wife_TO_USERCARD_FK") public UserCard getUserCard() { return userCard; } public void setUserCard(UserCard userCard) { this.userCard = userCard; } @OneToMany ( targetEntity=com.tibco.hibernate.po.Pet.class, fetch=FetchType.LAZY, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinTable(name="k_wife_pet", joinColumns = @JoinColumn(name = "WIFE_ID"), inverseJoinColumns = @JoinColumn(name = "PET_ID")) @ForeignKey(name = "k_wife_pet_FK", inverseName = "k_wife_pet_FK_R") public List<Pet> getPets() { return pets; } public void setPets(List<Pet> pets) { this.pets = pets; } }
package com.tibco.hibernate.po; import java.util.List; 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.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; @Entity(name="Pet") @Table(name="k_pet") public class Pet { private Long id; private String name; private List<Property> properties; @Column @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany ( targetEntity=com.tibco.hibernate.po.Property.class, fetch=FetchType.LAZY, cascade = { CascadeType.ALL }) @Cascade( { org.hibernate.annotations.CascadeType.ALL } ) @JoinTable(name="k_pet_property", joinColumns = @JoinColumn(name = "EVENT_ID"), inverseJoinColumns = @JoinColumn(name = "PROPERTY_ID")) @ForeignKey(name = "k_pet_property_FK", inverseName = "k_pet_property_FK_R") public List<Property> getProperties() { return properties; } public void setProperties(List<Property> properties) { this.properties = properties; } }
贴出persistence.xml配置:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="com.tibco.hibernate.po"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>com.tibco.hibernate.po.Event</class> <class>com.tibco.hibernate.po.Friend</class> <class>com.tibco.hibernate.po.Pet</class> <class>com.tibco.hibernate.po.Property</class> <class>com.tibco.hibernate.po.User</class> <class>com.tibco.hibernate.po.UserCard</class> <class>com.tibco.hibernate.po.Wife</class> <properties> </properties> </persistence-unit> </persistence>
数据库配置信息:
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect #connection hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver hibernate.connection.username=IPC113 hibernate.connection.password=bpm hibernate.connection.url=jdbc:oracle:thin:@//192.168.68.120:1521/orcl #pool hibernate.c3p0.min_size=1 hibernate.c3p0.max_size=20 hibernate.c3p0.timeout=1800 hibernate.c3p0.max_statements=50
在J2SE下使用JPA需要EntityManager对Persistent context中的实体与数据库同步,EntityManager由EntityManagerFactory产生,给出产生EntityManagerFactory的工具类:
package com.tibco.hibernate.jpa; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class JPAUtil { public static final String POJO_PACKAGE = "com.tibco.hibernate.po"; public static EntityManagerFactory createEMF(String dbproperties) throws IOException { Properties persistenceProperties = loadProperties(dbproperties); return Persistence.createEntityManagerFactory(POJO_PACKAGE, persistenceProperties); } public static Properties loadProperties(String dbproperties) throws IOException { Properties persistenceProperties = loadFromResource(dbproperties+".properties"); return persistenceProperties; } private static Properties loadFromResource(String resourceName) throws IOException { Properties p = new Properties(); InputStream is = new FileInputStream(new File(resourceName)); try { p.load(is); } finally { try { if (is != null) is.close(); } catch (IOException ignored) { } } return p; } }
先在向数据库中插入一条数据:
public class JPAClient { public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = getUser(); em.persist(user); t.commit(); em.close(); emf.close(); } private static boolean isProxyProperty(Object obj) throws Throwable { String name = obj.getClass().getName(); return name.contains("_$$_javassist_") || name.contains("org.hibernate.collection.PersistentBag"); } private static User getUser() { List<Event> events = getEventList(); List<Friend> friends = getFriendList(); UserCard userCard = new UserCard(); userCard.setCardNumber("user usercard number"); Wife wife = getWife(); User user = new User(); user.setName("Kylin Soong"); user.setEvents(events); user.setEvents(events); user.setFriends(friends); user.setIsMale(Boolean.TRUE); user.setUserCard(userCard); user.setCreatedDate(Calendar.getInstance()); user.setWife(wife); return user; } private static Wife getWife() { UserCard userCard = new UserCard(); userCard.setCardNumber("Wife usercard number"); List<Pet> pets = getPetList(); Wife wife = new Wife(); wife.setName("Bitch Soong"); wife.setUserCard(userCard); wife.setPets(pets); return wife; } private static List<Pet> getPetList() { List<Pet> pets = new ArrayList<Pet>(); Pet p1 = new Pet(); p1.setName("dog 1"); p1.setProperties(getPropertyList(p1.getName())); Pet p2 = new Pet(); p2.setName("dog 2"); p2.setProperties(getPropertyList(p2.getName())); pets.add(p2); pets.add(p1); return pets; } private static List<Friend> getFriendList() { List<Friend> friends = new ArrayList<Friend>(); Friend f1 = new Friend(); f1.setName("friend1"); UserCard uc1 = new UserCard(); uc1.setCardNumber("friend1-usercard-number"); f1.setUserCard(uc1); Friend f2 = new Friend(); f2.setName("friend2"); UserCard uc2 = new UserCard(); uc2.setCardNumber("friend2-usercard-number"); f2.setUserCard(uc2); friends.add(f1); friends.add(f2); return friends; } private static List<Event> getEventList() { List<Event> events = new ArrayList<Event>(); Event e = null; e = new Event(); e.setName("Cool"); e.setProperties(getPropertyList(e.getName())); events.add(e); e = new Event(); e.setName("Hot"); e.setProperties(getPropertyList(e.getName())); events.add(e); e = new Event(); e.setName("Cold"); e.setProperties(getPropertyList(e.getName())); events.add(e); return events; } private static List<Property> getPropertyList(String name) { List<Property> props = new ArrayList<Property>(); Property p1 = new Property(); p1.setName(name + " property 1"); Property p2 = new Property(); p2.setName(name + " property 2"); props.add(p1); props.add(p2); return props; } }
这时一条数据插入到数据库,
到此词例子结束,接下来的一些测试全基于此例子