最近工作中遇到几个与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;
}
}
这时一条数据插入到数据库,
到此词例子结束,接下来的一些测试全基于此例子