Hibernate之增删查改常见错误

增:

1、当一个对象有id值,如果数据库有这个id,你在create时执行的是保存操作,没有这个id,执行新建操作

 2、use与coupon之间有一个中间表usercoupon,下面这种添加usercoupon的方式会使与user对应的usercoupon的创建时间都会刷新,就像新建一样

user.getCoupons().add(coupon);
userService.save(user);

 所以下面这种方式好一点

                    UserCoupon uc=new UserCoupon();
                    uc.setCoupon(coupon);
                    uc.setUser(user);
                    userCouponService.create(uc);

查:在一次查询类别表Type的所有对象,查询花了很长时间,发现不仅查了Type,还将type的set<SubType>属性赋值,即又查了SubType表

,SubType的set<Store>,Store的set<Coupon>........做了很多无用功,但是虽然配置了openSessionInViewFilter,但是这些set都是lazy加载啊

调试发现

(1)执行下面方法只查询了Type表

@Override
    public List<T> listAll() {
        // TODO Auto-generated method stub
        String hql="from Type type  where type.deleted=false ";
        return list(hql, null);
    }

(2)执行到以下代码时,开始疯狂查询和加载response.setObject(list);

List<Type> list = typeService.listAll();
response=new Response(0);
response.setObject(list);

原因:在setObject(list)的过程中,元素Type的set属性被初始化,并且从表填充数据

(3)解决方法一

                List<Type> list = typeService.listAll();
        response=new Response(0);
        for(int i=0;i<list.size();i++){
            list.get(i).setSubs(null);
        }
        response.setObject(list);

 解决方法二:只从查询结果区部分需要用到的字段,然后拼成一个新的对象返回

coupons=couponService.list("select new Coupon(coupon.id,coupon.name) from Coupon coupon where coupon.store.id=:id Order by name", map);

 条件是有相应的构造函数(加了这个,还会org.hibernate.InstantiationException: No default constructor for entity:)

所以还加个无参构造函数

    public Coupon(int id,String name) {
        super();
        this.name = name;
        this.setId(id);
    }

改:修改优惠券coupon类

/**
 * @author JL 优惠券实体类
 */
@Entity
@Table(name = "tb_coupon")
public class Coupon extends BaseBean{

    /**
     * 编码
     */
    private String code;
    /**
     * 优惠券名称
     */
    private String name;
   /**
     * 优惠券所属商家
     */
    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
            CascadeType.REFRESH }, fetch = FetchType.LAZY)    
    @JoinColumn(name = "store_id")
    private Store store;
    
    @ManyToMany(mappedBy="coupons",fetch = FetchType.LAZY,cascade=CascadeType.ALL)
    private List<User> users=new ArrayList<User>();

    @OneToOne
    @PrimaryKeyJoinColumn
    private CouponAd ad;

}

Store关于coupon的配置

    @OneToMany(mappedBy = "store", fetch = FetchType.LAZY)
    private Set<Coupon> coupons = new HashSet<Coupon>();

表单文件jsp需要传入一个coupon的各个属性,包括外键:coupon.store.id

保存修改的代码

        couponService.save(coupon);

注意:

(1)如果成员store有值,却没有提交coupon.store.id,则保存后store为null

(2)如果成员store本身为null,你提交了coupon.store.id希望自动给他赋上store的值,那么save会报错:

transient 瞬时态
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: com.life.hibernate.bean.Store; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.life.hibernate.bean.Store

这时需要

        coupon.setStore(storeService.find(Store.class, coupon.getStore().getId()));
        couponService.save(coupon);

 (3)如果coupon.id的值没有传过去,很严重,这时不是保存,而是新建一条记录

Done

原文地址:https://www.cnblogs.com/xingyyy/p/3907001.html