我有一些关于在JSP Web应用程序中使用Hibernate的问题.
应该是什么价值hibernate.current_session_context_class?
那么,应该使用以下哪个陈述?为什么?
Session s = HibernateUtil.getSessionFactory().openSession();
Session s = HibernateUtil.getSessionFactory().getCurrentSession()
Run Code Online (Sandbox Code Playgroud)最后,哪一个更好"每个网络应用一个会话"或"每个请求一个会话"?
我有一个关于spring transaction propagation的问题.如果我使用@Transactional(propagation = Propagation.REQUIRED)来注释方法m1.当执行逻辑输入m1时,如果已有事务,则m1将使用该事务.在m1之后,交易怎么样?它结束还是仍然打开?(如果我在另一个方法中调用m1,并且在调用之后还有其他事情要做).
总之,我想知道退出带注释的方法时,交易结束还是仍然开放?
十分感谢.
在REQUIRED传播的情况下,当调用方法本身是transactionnal时,如果它们不同,当前方法是否会覆盖封闭的事务属性(例如rollbackFor)?
插图:
Class A {
@Transactional(propagation = Propagation.REQUIRED,
rollbackFor = { SomeException.class})
void foo() {
try {
b.bar();
} catch (OtherException e) {
// is the transaction marked as rollback-only at this point ?
}
}
}
Class B {
@Transactional(propagation = Propagation.REQUIRED,
rollbackFor = { OtherException.class})
void bar() {
[...]
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
好吧,我想避免琐碎的范围答案,所以我们要清楚,我知道弹簧传播处理.
如果你不是,下面是文档的相关部分,我只想澄清关于我上面例子的第一部分:
PROPAGATION_REQUIRED
当传播设置为PROPAGATION_REQUIRED时,将为应用该设置的每个方法创建逻辑事务范围.每个这样的逻辑事务范围可以单独确定仅回滚状态,外部事务范围在逻辑上独立于内部事务范围.当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些范围将映射到同一物理事务.因此,内部事务范围中的仅回滚标记集确实会影响外部事务实际提交的机会(正如您所期望的那样).
但是,在内部事务作用域设置仅回滚标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务作用域静默触发)是意外的.此时抛出相应的UnexpectedRollbackException.这是预期的行为,因此事务的调用者永远不会被误导,假设在实际上没有执行提交.因此,如果内部事务(外部调用者不知道)以静默方式将事务标记为仅回滚,则外部调用者仍会调用commit.外部调用者需要接收UnexpectedRollbackException以清楚地指示已执行回滚.
我的问题可以改写为:
逻辑事务范围是否包含事务属性?
假设我有一个类似这样的方法的java类(只是一个例子)
@Transactional
public synchronized void onRequest(Request request) {
if (request.shouldAddBook()) {
if (database.getByName(request.getBook().getName()) == null) {
database.add(request.getBook());
} else {
throw new Exception("Cannot add book - book already exist");
}
} else if (request.shouldRemoveBook()) {
if (database.getByName(request.getBook().getName()) != null) {
removeBook();
} else {
throw new Exception("Cannot remove book - book doesn't exist");
}
}
}
Run Code Online (Sandbox Code Playgroud)
假设这本书被删除,然后重新添加了一个新作者或其他小改动,所以这个方法可能会从另一个系统快速调用两次,首先删除Book,然后再添加相同的Book(带有一些新的细节) ).
为了解决这个问题,我们可能会尝试(像我一样)添加上面的@Transactional代码,然后在@Transactional不起作用时也"同步".但奇怪的是,它在第二次通话中失败了
"无法添加书本已经存在".
我花了很多时间试图解决这个问题,所以我想我会分享答案.
我有以下实现。
@Transactional
public void saveAndGenerateResult(Data data) {
saveDataInTableA(data.someAmountForA);
saveDataInTableB(data.someAmountForB);
callAnAggregatedFunction(data);
}
public void saveDataInTableA(DataA a) {
tableARepository.saveAndFlush(a);
}
public void saveDataInTableA(DataB b) {
tableBRepository.saveAndFlush(b);
}
public void callAnAggregatedFunction() {
// Do something based on the data saved from the beginning in Table A and Table B
}
Run Code Online (Sandbox Code Playgroud)
重要的saveAndFlush是使数据立即可供callAnAggregatedFunction函数使用,以获取汇总结果并将其保存到另一个表中。这就是为什么我不使用save据我所知不会立即将事务刷新到数据库中的函数的原因。
但是,我@Transactional在函数上使用了注释saveAndGenerateResult,因为在发生任何故障的情况下,我想回退在该函数中完成的数据库事务,通常通过@Transactional在方法上进行注释可以确保发生任何故障。
在这种特定情况下会发生什么情况?我正在使用saveAndFlush哪种方法将数据立即刷新到数据库表中,并且如果最后一个函数(即callAnAggregatedFunction)无法将数据写入表中,将回退表A和表B中的先前写入操作吗?
我的Web应用程序的数据库基础结构是这样分层的:
有些事务需要相当长的时间,有时一分钟用于一个大事务(目的是将数据缓存到数据库中):从用户到我的Web服务器的HTTP请求可能会开始此事务.然后,我的Web服务器可以向另一个远程第三方服务器查询丢失的数据.收集完所有数据后,事务就会完成,所有收集的数据都将写入数据库.
在这个长时间运行的事务中,用户可能会重新加载我的网站.这导致在单独的线程中为相同的数据开始另一个事务.由于此事务的目的是缓存,因此此操作本质上是幂等的,我不介意进行两次相同的计算.但在这些情况下,我的Web应用程序偶尔会遇到以下错误.
20:12:46.392 container [Thread-24] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 1062, SQLState: 23000
20:12:46.392 container [Thread-24] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Duplicate entry '146845042025054' for key 'PRIMARY'
20:12:46.602 container [Thread-24] INFO o.h.e.j.b.internal.AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements
Exception in thread "Thread-24" org.springframework.dao.DataIntegrityViolationException: Duplicate entry '146845042025054' for key 'PRIMARY'; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Duplicate entry '146845042025054' for key 'PRIMARY'
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104) …Run Code Online (Sandbox Code Playgroud) java ×5
hibernate ×3
spring ×3
transactions ×2
c3p0 ×1
jpa ×1
mysql ×1
spring-boot ×1
synchronized ×1