问:hibernate spring事务是同步的吗?如果不是,我如何更新数据库安全线程?

Q : hibernate spring transaction is synchronized ? If not , how i update db safe thread?

我的问题是第一,hibernate spring事务是同步的吗?

如果我将同时对同一个对象开始两个事务会怎样?

我很乐意向您展示这个例子:

我有一个 Player 对象和一个 Ship 对象

Player

Ship

我有一个类似的方法:

session.beingTrasaction()

// if player have enough gold, start one query to set gold to gold-price, and second query to add new ship

session.getTransaction().commit();

使用安全吗?如果我对同一个玩家在同一时间多次调用这样的算法,它们会连续执行吗?

非常欢迎任何帮助或解释

解决方案:

感谢这里的帮助,我找到了使用 hibernate locking 的解决方案,我选择使用悲观锁,实际上它有点简单。

就我而言,这是我的 实现 :

我添加到 player :

private Long databaseVersion;

@Version
public Long getDatabaseVersion() {
    return databaseVersion;
}
public void setDatabaseVersion(Long databaseVersion) {
        this.databaseVersion = databaseVersion;
}

还有我的道器:

public void buyShip(Player player, Ship ship) {
    Session session = sessionFactory.openSession();
    session.beginTransaction();

    Player p = (Player) session.get(Player.class, player.getId(), LockMode.PESSIMISTIC_WRITE);

    if(p.getGold()>=ship.getPrice()) {
        ship.setPlayer(player);
        addShipToUser(session,ship);

        p.setGold(player.getGold()-ship.getPrice());
        session.update(p);
    }else {
        System.out.println("NOT EN GOLD");
    }


    session.getTransaction().commit();
    session.close();
}

我用 5 个线程检查它,它工作了!我对同一播放器的所有更改将串行执行,而对不同播放器的更改将并行执行!

没有 Spring 交易这样的东西。 Spring 只为开始和 commit/rollback 事务的事务管理提供一致的抽象。

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(
            TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

但是你必须将它注入到管理真实交易的实际实现中。例如,hibernate 事务的抽象是 HibernateTransactionManager 并且您必须注入 Hibernate 的 SessionFactory 来执行实际的 begin/commit/rollback.

此外,如果两个线程执行同一个事务:

session.beingTrasaction()

if (player.gold > 10){
   player.setGold(gold - 10);
   Ship newShip = new Ship();
   player.addShip(newShip);  // I suppose you have cascade insert otherwise you have to save your transient ship
}

session.getTransaction().commit();

事务将以序列化方式提交。然而,您最终可能会得到玩家的黄金数量为负数。

Thread 1                                 Thread 2 
if (player.gold > 10) // true           
                                         if (player.gold > 10) // true
player.gold = gold - 10 // gold=0
                                         player.gold = gold - 10 // gold=-10

您需要 optimistic or pessimistic 锁定。

My question is first, hibernate spring transaction is synchronized ?

"synchronized",你的意思似乎是"thread-safe"。其 Session 接口的 Hibernate 文档说:

It is not intended that implementors be threadsafe. Instead each thread/transaction should obtain its own instance from a SessionFactory.

虽然这并没有肯定地否认任何特定的 Session 实现都可以是线程安全的,但它肯定表明依赖会话来保证线程安全是危险的,更具体地说,序列化事务也是如此。

属于不同 个会话的事务可以运行 并行,您可以依赖底层数据库配置的事务隔离级别。但是请注意,一个实体对象一次只能与一个会话相关联。

Spring Hibernate 使用的事务管理"is the same"。如果我没记错的话,您更关心的是并发性。如果您在 Web 服务器等多线程环境中执行此代码,则每个操作都是 ACID,但您无法知道确切的顺序,结果可能是错误的。

例如,如果两个线程同时更新同一个玩家的"gold"值,提交部分会一个接一个地发生,而不是验证码。

将事务视为全有或全无原子指令 "package",而不是命令队列。

如果您希望一次访问一个线程,您可以使用 synchronized 方法。这样当一个线程访问代码时,任何其他线程都会等待第一个线程在执行它之前离开该方法。这有一个缺点,就是只能在同一个 JVM 中正常工作,所以如果你有多个服务器(或同一个服务器中的多个 JVM 进程),它只会阻塞相同 server/JVM 的线程。

您可以查看一些数据库 lock/versioning 机制,例如 Optimistic Locking(在大多数情况下更可取)或悲观锁定(您实际锁定数据库注册表直到事务完成)。这些是恕我直言,better/easier 并发问题的解决方案。