hibernate-添加到 Set 会导致 InvocableTargetException
迈出使用 hibernate 和 postgres 的第一步,我为实体类创建了旧式 xml 配置,并创建了一些 dao 实现,如(Manning Java Persistence with Hib)书中提到的,并创建了一个 HibernateUtil 类来创建 SessionFactory。为了测试这些,我创建了一些实体并试图通过 dao 来保存。
在此代码中,Customer 类具有一组“订单”。为了配置它,我创建了 hbm.xml 文件,如下所示。
在 demo() 方法中,我创建了实体实例并调用 saveOrUpdate () 通过 dao。 它成功运行并在 db 中创建两个客户和一个订单。但是,当我尝试将订单添加到客户时,它会导致 RuntimeException 并回滚事务。 当我尝试调试应用程序时,我发现
org.hibernate.context.ThreadLocalSessionContext.TransactionProtectionWrapper.invoke() ---> lang.reflect.Method.invoke() ---> java.lang.reflect.InitationTargetException
我很困惑为什么会发生这种情况。如果我不调用 addOrdersToCustomers(),则不会发生此错误。 如果我不调用该方法,那不是意味着 Customer 对象没有订单集吗?在数据库中,Order 表有一个 FK customer_id,由于 createOrders() 方法设置了 Customer,因此它已成功设置为客户的 id但是,这并不会使 Customer 的 Set Orders 字段被更新。
知道如何纠正这个问题吗? 谢谢,
Jim
public class Main {
CustomerDao custdao;
OrderDao orderdao;
Customer mark,jon;
Order order1,order2,order3;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
public void demo()throws ParseException{
custdao = Daofactory.getCustomerDao();
orderdao = Daofactory.getOrderDao();
createCustomers();
createOrders();
//addOrdersToCustomers();//uncommenting this causes RuntimeException
updateEntities();
}
private void updateEntities() {
Transaction tx = null;
Session session = HibernateUtil.getCurrentSession();
logger.info("got session:"+session);
try{
tx = session.beginTransaction();
logger.info("got transaxion:"+tx);
custdao.saveOrUpdateCustomer(mark);
custdao.saveOrUpdateCustomer(jon);
orderdao.saveOrUpdateOrder(order1);
tx.commit();
}catch(Exception e){
tx.rollback();
}
}
private void addOrdersToCustomers() {
mark.getOrders().add(order1);
}
private void createCustomers() {
mark = new Customer();
mark.setName("mark");
mark.setEmailAddress("mark@home");
mark.setAddress("121,3rd avenue");
mark.setCity("San Diego");
mark.setState("CA");
mark.setCountry("U.S.A");
jon = new Customer();
jon.setName("jon");
jon.setEmailAddress("jon@home");
jon.setAddress("1121 vpura");
jon.setCity("bangalore");
jon.setState("karnataka");
jon.setCountry("india");
}
private void createOrders() throws ParseException {
order1 = new Order();
order1.setCustomer(mark);
order1.setOrderNumber(Long.parseLong("111111111"));
order1.setOrderDate(sdf.parse("2001/01/02"));
...
}
...
public static void main(String[] args) throws ParseException {
new Main().demo();
}
}
映射如下,
public class Customer {
private Long customer_id;
...
private Set<Order> orders;
public Customer() {
super();
orders = new HashSet<Order>();
}
...
}
<hibernate-mapping package="org.me.hibernatestore">
<class name="Customer" table="CUSTOMER">
<id column="CUSTOMER_ID" name="customer_id" type="java.lang.Long">
<generator class="native"/>
</id>
...
<set name="orders" table="ORDERS" lazy="false" cascade="delete-orphan">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>
Order.java
public class Order {
private Long order_id;
...
private Customer customer;
...
}
Order.hbm.xml
...
<class name="Order" table="ORDERS">
<id name="order_id" column="ORDER_ID" type="long">
<generator class="native"/>
</id>
...
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="false" />
...
dao 实现有一个基类
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T,ID>{
private Class<T> persistentClass;
private Session session;
public BaseDaoImpl() {
this.persistentClass = (Class<T>)(((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
public Session getSession() {
if (session == null){
return HibernateUtil.getCurrentSession();
}
return session;
}
...
}
HibernateUtil.java
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
}catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getCurrentSession(){
Session session = sessionFactory.getCurrentSession(); l
return session;
}
Taking my first steps with hibernate and postgres ,I created old style xml configurations for my entity classes and created some dao implementations as mentioned in( Manning Java Persistence with Hib) book and created a HibernateUtil class to create SessionFactory .To test these ,I created some entities and tried to save through dao .
In this code,Customer class has a set of 'Order's .To configure this I created the hbm.xml files as given below..
In the demo() method ,I created the entity instances and called saveOrUpdate() through dao.
It runs successfully and creates the two customers and an order in db .However,when I try to add the order to a customer,it causes RuntimeException and rolls back the transaction.
When I tried to debug the app,I found that
org.hibernate.context.ThreadLocalSessionContext.TransactionProtectionWrapper.invoke() ---> lang.reflect.Method.invoke() ---> java.lang.reflect.InvocationTargetException
I am confused why this occurs.This error wont occur if I don't call addOrdersToCustomers().
If I don't call that method,would it not mean the Customer object has no Set of orders?In the db,the Order table has a FK customer_id which is successfully set to the id of customer since createOrders() method sets the Customer field of Order to the customer instance.But,that doesn't make the Set orders field of Customer to be updated.
Any idea how to correct this?
thanks,
Jim
public class Main {
CustomerDao custdao;
OrderDao orderdao;
Customer mark,jon;
Order order1,order2,order3;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
public void demo()throws ParseException{
custdao = Daofactory.getCustomerDao();
orderdao = Daofactory.getOrderDao();
createCustomers();
createOrders();
//addOrdersToCustomers();//uncommenting this causes RuntimeException
updateEntities();
}
private void updateEntities() {
Transaction tx = null;
Session session = HibernateUtil.getCurrentSession();
logger.info("got session:"+session);
try{
tx = session.beginTransaction();
logger.info("got transaxion:"+tx);
custdao.saveOrUpdateCustomer(mark);
custdao.saveOrUpdateCustomer(jon);
orderdao.saveOrUpdateOrder(order1);
tx.commit();
}catch(Exception e){
tx.rollback();
}
}
private void addOrdersToCustomers() {
mark.getOrders().add(order1);
}
private void createCustomers() {
mark = new Customer();
mark.setName("mark");
mark.setEmailAddress("mark@home");
mark.setAddress("121,3rd avenue");
mark.setCity("San Diego");
mark.setState("CA");
mark.setCountry("U.S.A");
jon = new Customer();
jon.setName("jon");
jon.setEmailAddress("jon@home");
jon.setAddress("1121 vpura");
jon.setCity("bangalore");
jon.setState("karnataka");
jon.setCountry("india");
}
private void createOrders() throws ParseException {
order1 = new Order();
order1.setCustomer(mark);
order1.setOrderNumber(Long.parseLong("111111111"));
order1.setOrderDate(sdf.parse("2001/01/02"));
...
}
...
public static void main(String[] args) throws ParseException {
new Main().demo();
}
}
The mappings are as follows,
public class Customer {
private Long customer_id;
...
private Set<Order> orders;
public Customer() {
super();
orders = new HashSet<Order>();
}
...
}
<hibernate-mapping package="org.me.hibernatestore">
<class name="Customer" table="CUSTOMER">
<id column="CUSTOMER_ID" name="customer_id" type="java.lang.Long">
<generator class="native"/>
</id>
...
<set name="orders" table="ORDERS" lazy="false" cascade="delete-orphan">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>
Order.java
public class Order {
private Long order_id;
...
private Customer customer;
...
}
Order.hbm.xml
...
<class name="Order" table="ORDERS">
<id name="order_id" column="ORDER_ID" type="long">
<generator class="native"/>
</id>
...
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="false" />
...
The dao implementations have a base class
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T,ID>{
private Class<T> persistentClass;
private Session session;
public BaseDaoImpl() {
this.persistentClass = (Class<T>)(((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
public Session getSession() {
if (session == null){
return HibernateUtil.getCurrentSession();
}
return session;
}
...
}
HibernateUtil.java
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
}catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getCurrentSession(){
Session session = sessionFactory.getCurrentSession(); l
return session;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的堆栈跟踪清楚地表明了原因 - 您正在尝试使用对瞬态对象的引用来保存对象。您要么需要在添加的
Order
对象上调用save()
,然后再在Customer
上调用它,或者您需要添加一个(至少)将级联保留在Customer
类中设置的orders
上。在您的 xml 情况下,这将更正为
Your stacktrace clearly indicates the reason -- you're trying to save an object with a reference to a transient object. You either need to call
save()
on your addedOrder
object before calling it on yourCustomer
, or you need to add an (at least) persist cascade on theorders
set in yourCustomer
class. In your xml case this would be correctingto