刚刚关于@Cacheable 标签的测试用例,陷入一个很简单的陷阱!
<< SchoolRepository.java >>
<code>
@CacheConfig( cacheNames = "school" )
public interface SchoolRepository extends JpaRepository<School, Long>
{
@Cacheable
School findByName( String name );
School findByNameAndTotalStudents( String name, Integer totalCount );
@Query( "from School s where s.name=:name" )
School findSchool( @Param( "name" ) String name );
@Modifying
@Query( "update School s set s.totalStudents = ?2 where s.name = ?1" )
int updateSchool( String name, int total );
}
</code>
<< SchoolTest.java >>
<code>
@Test
@Transactional
@Rollback( true )
public void schoolCacheTest()
{
schoolRepository.save( new School( "AAA", 10 ) );
School sch1 = schoolRepository.findByName( "AAA" );
System.out.println( "The first query -> " + sch1.getTotalStudents() );
schoolRepository.updateSchool( "AAA", 1 );
School sch2 = schoolRepository.findByName( "AAA" );
System.out.println( "The second query -> " + sch2.getTotalStudents() );
}
</code>
@Cacheable 本身测试没有任何问题,schoolRepository.findByName
没有第二次打印查询SQL,后面突发奇想的想测试一下更新之后数据的结果, 加入了schoolRepository.updateSchool
,去掉了@Cacheable,发现数据还是没有更新。
而后细想起来@Transactional,这么偌大的一个事务,导致更新的数据还未commit,肯定是这样。
但是 schoolRepository.save
怎么能插入数据呢!
马上去看JPA源码:
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
save方法自带@Transactional,继承上层方法的事务进行提交,导致插入可以,更新数据无法提交导致查询的为旧数据。OK,进一步验证,将updateSchool方法加入事务。
<code>
@Transactional
@Modifying
@Query( "update School s set s.totalStudents = ?2 where s.name = ?1" )
int updateByName(String name, Integer total);
</code>
测试结果:
Paste_Image.png
网友评论