陷阱一:不要只用readOnly=true
@Transactional(readOnly = true)
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
getTrade() 方法会执行以下哪一种操作?
a. 启动一个事务,获取交易订单,然后提交事务
b. 获取交易订单,但不启动事务
正确的答案是 A。
一个事务会被启动并提交。不要忘了,@Transactional 注释的默认传播模式是 REQUIRED。这意味着事务会在不必要的情况下启动。根据使用的数据库,这会引起不必要的共享锁,可能会使数据库中出现死锁的情况。此外,启动和停止事务将消耗不必要的处理时间和资源。总的来说,在使用基于 ORM 的框架时,只读标志基本上毫无用处,在大多数情况下会被忽略。但如果您坚持使用它,请记得将传播模式设置为 SUPPORTS,这样就不会启动事务。
传播规则(propagation=Propagation.NOT_SUPPORTED)
Required:如果上下文中已经有事物,则使用当前事务,若无,则启动一个新事物
Mandatory:上下文比如要有事物,若无事物,这抛出异常
RequiresNew:不管上下文是否有事物,启动一个新的事物
Supports:如果上下文中已经有事物,则使用当前事务,若无,则不启动事物
NotSupported:不管上下文是否有事物,从不启动一个事物
Never:不管上下文是否有事物,从不启动一个事物。如果上下文中有事物,抛出异常
NESTED:如果当前事务存在,则以嵌套事务的方式执行。否则就按照它自己的事务方式执行。
隔离级别(isolation=Isolation.DEFAULT):
ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是ISOLATION_READ_COMMITTED
ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。