问: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 并发问题的解决方案。
我的问题是第一,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 并发问题的解决方案。