我想测试一种通过在循环中调用 DAO 将数据插入表的服务方法。服务方法被注释为
@Transactional(propagation = Propagation.REQUIRES_NEW)
Run Code Online (Sandbox Code Playgroud)
单元测试调用服务方法并用
@Transactional
Run Code Online (Sandbox Code Playgroud)
现在我想告诉事务,它始终应该在最后进行回滚。我不想在测试运行后手动清理数据库。
@Rollback 和 EntityManager.getTransaction().setRollbackOnly() 不起作用。我认为原因是注释和 setRollbackOnly() 仅应用于由测试方法创建的事务,而不应用于由服务方法创建的事务。
有谁知道如何解决这个问题?
@Transactional
public MyEntity getEntity(long id) {
return dao.findOne(id);
//or select and update as well
}
Run Code Online (Sandbox Code Playgroud)
每次调用事务方法时:我会从休眠中获取任何缓存的实体吗(第一次除外)?或者我总是会从数据库中获取新的实体?
这很重要,因为我将有两个独立的应用程序共享同一个数据库,并且我想确保 hibernate 不会返回任何缓存的实体,而另一个应用程序可能已经在后台更新了数据库中的同一个实体。
我有一个 JDBC 批量更新操作可能需要很长时间,因此我使用事务超时来处理这个。
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW,timeout=10)
public void saveAllUsingBatch(List<KillPrintModel> list){
PreparedStatmentMapper ps= new HibernateDao.PreparedStatmentMapper<KillPrintModel>() {
@Override
public void prepareStatement(PreparedStatement ps, KillPrintModel t)
throws SQLException {
ps.setString(1, t.getOffice());
ps.setString(2, t.getAccount());
ps.setDate(3, new java.sql.Date(t.getUpdatedOn().getTime()));
}
};
String sql = String.format("INSERT INTO dbo.%s (%s,%s,%s) VALUES (?,?,?)",KillPrintModel.TABLE_NAME,KillPrintModel.FIELD_Office,KillPrintModel.FIELD_Account,KillPrintModel.FIELD_UpdatedOn);
this.jdbcBatchOperation(list, sql, ps);
}
Run Code Online (Sandbox Code Playgroud)
即使我的事务时间超过 10 秒,此方法也会持续一分钟以上(并成功返回)。当超时为 0 时它工作正常。
是不是因为我的线程一旦开始执行就一直处于运行状态?
我有一种方法的服务:
@Service
public class DefaultTestService implements TestService {
private static final Logger LOGGER = Logger.getLogger(DefaultTestService.class);
@Autowired
private TestRepository testRepository;
@Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE)
@Override
public void incrementAndGet(Long testModelId) {
LOGGER.debug("Transaction is active: " + TransactionSynchronizationManager.isActualTransactionActive());
final TestModel tm = testRepository.findOne(testModelId);
if (tm != null) {
LOGGER.debug("Updated " + testModelId + " from value: " + tm.getValue());
tm.setValue(tm.getValue() + 1);
testRepository.save(tm);
} else {
LOGGER.debug("Saved with id: " + testModelId);
final TestModel ntm = new TestModel();
ntm.setId(testModelId);
testRepository.save(ntm);
} …Run Code Online (Sandbox Code Playgroud) @Transactional在集成测试期间,我需要忽略以下注释。
@Service
public class MyClass {
@Transactional(propagation = Propagation.NEVER)
public void doSomething() {
// do something that once in production can not be inside a transaction (reasons are omitted)
}
}
Run Code Online (Sandbox Code Playgroud)
问题是我所有的测试都是在默认回滚的事务中执行的。@Transactional(propagation = Propagation.NEVER)当此方法在测试 ( @ActiveProfiles("test"))范围内运行时,我怎么能忽略它的注释,允许它在事务内执行?
@Transactional在Spring中使用注解方法时,注解方法的返回是否与底层数据库事务的成功提交同步?
(这是假设事务在返回后实际上会提交,这可能不是这种情况,具体取决于所选的传播方法。)
如果等待提交不是默认行为,有没有办法通过配置或其他方式启用它?
我的问题的动机是我想实现一个可靠的“存储和转发”类型的端点,它只在调用的影响被提交到稳定存储后才向客户端返回响应。这可能@Transactional吗?
在我的Spring应用程序中,我有一个带有org.springframework.transaction.annotation.Transactional注释的类。
是否可以丢弃此类的特定单个方法的事务而无需@Transactional从类级别的声明中删除?如果是这样,请举一个例子
这并不完全像标题所说的那样,但接近。考虑这些 Spring bean:
@Bean
class BeanA {
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = EvilException.class)
public void methodA() {
/* ... some actions */
if (condition) {
throw new EvilException();
}
}
}
@Bean
class BeanB {
@Autowired private BeanA beanA;
final int MAX_TRIES = 3;
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// prepare to call Bean A
try {
beanA.methodA();
/* maybe do some more things */
}
catch (EvilException e) {
/* recover from evil */
}
}
} …Run Code Online (Sandbox Code Playgroud) 对于这个基于spring-boot-starter-data-jpa依赖和H2内存数据库的实验项目,我定义了一个User具有两个字段(id和firstName)的实体,并UsersRepository通过扩展CrudRepository接口声明了一个。
现在,考虑一个简单的控制器,它提供两个端点:/print-user读取同一用户两次,间隔打印其名字,并/update-user用于在两次读取之间更改用户的名字。请注意,我特意设置了Isolation.READ_COMMITTEDlevel 并期望在第一次事务过程中,通过相同 id 检索两次的用户将具有不同的名称。但是相反,第一笔交易打印出两次相同的值。为了更清楚,这是完整的操作序列:
jeremy的名字设置为Jeremy。/print-userwhich 打印出来Jeremy并进入睡眠状态。/update-user从另一个会话调用,它将jeremy的名字更改为Bob.jeremy用户时,Jeremy即使名字已经更改为他的名字,它也会再次打印出来Bob(如果我们打开数据库控制台,它现在确实存储为Bob,不是Jeremy)。似乎在这里设置隔离级别没有任何影响,我很好奇为什么会这样。
@RestController
@RequestMapping
public class UsersController {
private final UsersRepository usersRepository;
@Autowired
public UsersController(UsersRepository usersRepository) {
this.usersRepository = usersRepository;
}
@GetMapping("/print-user")
@ResponseStatus(HttpStatus.OK)
@Transactional (isolation = Isolation.READ_COMMITTED) …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Kotlin 的 Arrow 库Either对象来处理项目中的异常。
到目前为止,我的经验还不错,但我正在努力寻找一种方法来处理事务Either,特别是回滚。在 Spring 中抛出 aRuntimeException是导致事务回滚的可靠方法。但是,通过使用Either不会引发异常,因此不会触发回滚。
您可以将此视为一个多方面的问题:
Either适合真实Exception处理?不是替代控制流,我的意思是程序流需要停止的真正错误情况。transactionManager编程方式使用- 你能避免这种情况吗?Either?spring ×9
java ×7
transactions ×2
arrow-kt ×1
hibernate ×1
jdbc ×1
jpa ×1
junit ×1
kotlin ×1
spring-boot ×1
spring-data ×1