环境 :
雄猫 6
春季 4
冬眠 4
春季MVC
法典:
我有以下服务层类:
public interface AbhisheskService {
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
@Service("abhishekService")
public class AbhishekServiceImpl implements AbhisheskService {
@Autowired
private AbhishekDao abhishekDao;
@Transactional
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto) {
return getAbs();
}
public List<AbhishekDTO> getAbs(){
Abhishekdetails absDt = this.abhishekDao.get(4L);
return null;
}
}
AbhishekDao是一个标准的DAO层接口,它扩展了GenericDAO超级接口。
public interface AbhishekDao extends GenericDAO<Abhishekdetails, Long>{
public List<Abhishekdetails> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
我的问题是:
findByMatchingCriteria
方法标有@Transactional.
此方法调用另一个方法getAbs
该方法未标记为@Transactional
,并在findByMatchingCriteria(自调用)中调用。
根据我的理解,因为:
1)findByMatchingCriteria
在自身内部调用getAbs
(自调用),getAbs
()方法不应该在事务中运行。由于它在这里绕过了动态创建的代理
2)此外,getAbs没有@Transactional
注释。
3)但是当getAbs
调用this.abhishekDao.get(4L)
一切正常时,会检索到包含ID 4L
的记录。DAO Bean 正在调用它内部的sessionFactory.getCurrentSession()
以从 DB 获取对象。但是为什么会这样呢?因为不应该有任何活跃的交易。
4)为什么上面的代码有效? 很多关于 Spring 事务管理的帖子都指出自调用是行不通的。(甚至是春季文档)。
那为什么上面的设置有效?
我在这里错过了什么吗?
还是我对春季交易的理解不正确?
请回复,因为我在这里感到困惑
它的工作方式是:- AbhishekServiceImpl bean 被包裹在代理中。
-
findByMatchingCriteria
是@Transactional
,所以在调用该方法之前,Spring 从连接池中获取新的数据库连接,并将自动提交设置为 false。 - 事务绑定到线程,因此此线程上的其他方法将使用此连接。
- 执行
findByMatchingCriteria
和getAbs
的方法 findByMatchingCriteria
之后,Spring 调用在连接上提交(如果发生RuntimeException
则回滚)。
所以你的代码在事务中大约findByMatchingCriteria
不会创建事务的情况是,如果您在getAbs
上具有@Transactional,但在findByMatchingCriteria
上没有(反向调用),并且您在服务外部调用findByMatchingCriteria
。但是,如果您只调用服务之外的getAbs
,它将在事务中。
更清晰的例子:
@Service
public class MyServiceImpl implements MyService{
@Autowired
private MyDao myDao;
@Transactional
public List<T> transactionalMethod() {
return this.myDao.get(4L);
}
public List<T> notTransactionalMethod(){
return transactionalMethod();
}
}
在其他一些类中:
@Component
public class SomeClass {
@Autowired
private MyService myService;
public void someMethod(){
myService.transactionalMethod();//will be in transaction. Here actualy you go to the proxy first and then it calls the real method.
myService.notTransactionalMethod();//will not be in transaction and hibernate will throw an error.
//You go to the proxy, but doesent do anything special because the method is not transactional and it calls the real method,
//but here you dont't got trough the proxy so the @Transactional is ignored.
}
}