对数据库中没有版本列的集合进行乐观锁定

时间:2015-07-31 11:52:06

标签: java hibernate jpa-2.1

假设有一个具有一些属性和一个集合(oneToMany映射)的可持久化类。让我们假设最初只有一个带有id的记录,并且最初没有保存集合。

让我们说有一个线程T1加载相同的记录,当这个线程运行时,还有另一个线程T2加载并更新没有其他属性,除了将一个集合对象添加到同一记录(只有一个到避免混淆)。 现在T1尝试通过修改记录的数量来保存实体,并且在测试用例中我发现它能够在没有任何StaleStateException的情况下执行它。

我想在长对话中找到一种方法,扩展持久化上下文而不在数据库中添加版本,你是否可以强制hibernate检查关联?我几乎可以肯定没有这样的解决方案!但我很有希望......请提出任何解决方案!

放置一些粗鲁的代码......这让我坚持下去。

  Person per = new Person();
    per.setLdt(LocalDateTime.MIN);
    per.setName("Raju");
    per.setPassportNo("Passport123");

    Relations re = new Relations("Raju", "Kavitha", "mother");
    List<Relations> Rlist = new ArrayList<Relations>();
    Rlist.add(re);
    per.setRels(Rlist);

    Belongings b = new Belongings("Bag", 600, LocalDateTime.MIN);
    List<Belongings> blist = new ArrayList<Belongings>();
    blist.add(b);
    per.setBels(blist);

    Session ss = sessFactory.openSession();
    Transaction tx = ss.beginTransaction();

    ss.save(per);
    tx.commit();
    ss.close();
    Thread t1;
    t1 = new Thread(new Runnable() {
        public void run() {
            System.out.println("Thread T1 Started");
            Session session = sessFactory.openSession();
            Transaction tx = session.beginTransaction();

            Person p = (Person) session.load(Person.class, "Raju");
//                p.setPassportNo("passT1");
                p.getAddresses();p.getRels();
                System.out.println("Thread T1 Paused");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Running.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("Thread T1 Playing again");

            session.save(p);
            tx.commit();
            session.close();

            System.out.println("Thread T1 Ended");
        }
    });

    Thread t2 = new Thread(new Runnable() {

        public void run() {
            System.out.println("Thread T2 Started");
            Session session = sessFactory.openSession();
            Transaction tx = session.beginTransaction();
            Person p = (Person) session.load(Person.class, "Raju");
            p.getPassportNo();
            p.getRels();p.getBels();
            Address a = new Address("123", "Lothkunta", "RangaReddy");
            List<Address> listA = new ArrayList<Address>();
            listA.add(a);
            p.setAddresses(listA);
            p.setPassportNo("passT2");
            session.save(p);
            tx.commit();
            session.close();
            System.out.println("Thread T2 Ended");
        }
    });
    System.out.println("Starting Threads***********************");
    System.out.println("Starting Threads***********************");
    System.out.println("Starting Threads***********************");

    t1.start();
    t2.start();
    try {
        t1.join();
    } catch (InterruptedException ex) {
        Logger.getLogger(Running.class.getName()).log(Level.SEVERE, null, ex);
    }
    try {
        t2.join();
    } catch (InterruptedException ex) {
        Logger.getLogger(Running.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.exit(0);
}

班级人员在这里/ ...

@Entity
@Table(name = "PERSON")
@org.hibernate.annotations.OptimisticLocking(type = OptimisticLockType.ALL)
@DynamicUpdate(true)
public class Person implements Serializable {

@Id

String name;
String passportNo;

LocalDateTime ldt;

@OneToMany(cascade = CascadeType.ALL)
@Basic(fetch = FetchType.LAZY)
@OptimisticLock(excluded = false)
@ElementCollection
List<Address> addresses;

@Basic(fetch = FetchType.LAZY)
@OneToMany(cascade = CascadeType.ALL)
@OptimisticLock(excluded = false)
@ElementCollection
List<Belongings> bels;

@Basic(fetch = FetchType.LAZY)
@OneToMany(cascade = CascadeType.ALL)
@OptimisticLock(excluded = false)
@ElementCollection
List<Relations> rels;

public String getPassportNo() {
    return passportNo;
}

public List<Address> getAddresses() {
    return addresses;
}

public void setAddresses(List<Address> addresses) {
    this.addresses = addresses;
}

public List<Belongings> getBels() {
    return bels;
}

public void setBels(List<Belongings> bels) {
    this.bels = bels;
}

public List<Relations> getRels() {
    return rels;
}

public void setRels(List<Relations> rels) {
    this.rels = rels;
}

public void setPassportNo(String passportNo) {
    this.passportNo = passportNo;
}

public LocalDateTime getLdt() {
    return ldt;
}

public void setLdt(LocalDateTime ldt) {
    this.ldt = ldt;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

谢谢!

1 个答案:

答案 0 :(得分:0)

不,没有版本字段就没有办法做到这一点。即使使用版本字段,如果要保护集合修改,也必须强制更新父版本;见LockModeType.OPTIMISTIC_FORCE_INCREMENT