0

每次我想对休眠执行一些操作时,我的应用程序中都有以下代码:

Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(obj); //or delete, update etc.
session.getTransaction().commit();
session.close();

这当然不是一个好的做法。访问休眠状态而不是出现这种情况的最佳方法是什么?我应该使用一些包含执行相同工作的静态方法的“Util”类吗?也许单身更好?我还需要将此代码包装在线程或 SwingWorker 中,以免在访问数据库时冻结我的 GUI。

4

3 回答 3

0

是的,该代码非常糟糕。

  1. 它为每个数据库访问打开一个事务。这是低效的,并且可能是不正确的(通常,整个动作组需要是原子的。例如考虑

    public void buy(String accountId) {
        Account account = load(accountId);
        account.balance -= 100;
        save(account);
    }
    

    如果加载和保存在他们自己的交易中,并且某些邪恶的用户同时购买了 2 件物品,则可能会发生以下情况:

    • 线程 1 读取余额 (=1000)
    • 线程 2 读取余额 (=1000)
    • 线程 1 写入余额 (=900)
    • 线程 2 写入余额 (=900)

    所以用户买了两次,但只付了一次;-)

  2. 如果 save() 抛出异常,它不会完成事务。事实上,交易将无限期保持开放,包括它持有的所有锁......

诸如此类的复杂性是大多数人以声明方式划分事务而不是重新发明方轮的原因,例如使用SpringEJB

于 2012-09-10T01:39:50.927 回答
0

我认为解决方法是根据 accountId 获取 renentranlock

@Service
public class AccountService {
    private Map<String, ReentrantLock> locks = new HashMap<Long, ReentrantLock>();

    private void unlock(String id) {
        ReentrantLock lock = locks.get(id);
        if (lock != null && lock.isLocked()) {
            lock.unlock();
        }
    }

    private void lock(String id) {
        ReentrantLock lock;
        synchronized (locks) {
            lock = locks.get(id);
            if (lock == null) {
                lock = new ReentrantLock();
                locks.put(id, lock);
            }
        }
        lock.lock();
    }

public void buy(String accountId) {
    this.lock(accountId);
    try{
       Account account = load(accountId);
       account.balance -= 100;
       save(account);
    }finally{
      this.unlock(accountId);
    }
   }
}

如果整个应用程序都需要此功能,那么围绕服务方面编写可能是明智之举。

于 2012-09-10T05:52:59.947 回答
0

我强烈建议从 Hibernate 站点阅读这篇文章。

对于任何想在 Hibernate 中使用会话和事务的最佳方式的人来说,这篇文章都是必读的。

基本上,最好的设计模式取决于您选择的事务管理策略(jdbc、jta)和应用事务的模式(程序化/声明性)

正如meriton 已经指出的那样,为代码中的每个方法打开和关闭事务(假设将有几个这样的方法按顺序工作以形成原子操作)是一种反模式。这也将在文章中更详细地讨论。

于 2012-09-10T10:55:00.230 回答