当前位置: 首页 > 知识库问答 >
问题:

一级缓存不使用JPA和Hibernate

壤驷高旻
2023-03-14

我一个新的使用Hibernate缓存(一级,二级和查询缓存)。

我的项目是使用SpringMVC和JPA配置的。

我正在使用下面的JUnit测试用例测试一级缓存。

public class FirstLevelCacheTest
{
    private static final Logger logger = LoggerFactory.getLogger(FirstLevelCacheTest.class);

    @PersistenceContext
    private EntityManager       entityManager;

    @Test
    public void testFirstLevelCacheTest()
    {
        Long clientId = 1L;

        // fetch the client entity from database first time
        Client client1 = entityManager.find(Client.class, clientId);
        logger.debug("Client Name : {}", client1.getName());

        // fetch the client entity again
        client1 = entityManager.find(Client.class, clientId);
        logger.debug("Client Name : {}", client1.getName());
    }
}

我的实体类定义为:

@Entity
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
@Table(name = "client")
public class Client extends BaseModel
{
    // instance variable declaration

    // getter and setter methods for instance variables
}

如果默认情况下启用了一级缓存,则应该执行一次本机查询。但我在执行此查询时得到以下结果:

Hibernate: select client0_.id as id0_0_, client0_.created as created0_0_, client0_.createdBy as createdBy0_0_, client0_.updated as updated0_0_, client0_.updatedBy as updatedBy0_0_, client0_.contactNo as contactNo0_0_, client0_.contactPerson as contactP7_0_0_, client0_.contactPersonEmail as contactP8_0_0_, client0_.contactPersonNo as contactP9_0_0_, client0_.email as email0_0_, client0_.name as name0_0_ from client client0_ where client0_.id=?
[main] DEBUG Client Name : Client1
Hibernate: select client0_.id as id0_0_, client0_.created as created0_0_, client0_.createdBy as createdBy0_0_, client0_.updated as updated0_0_, client0_.updatedBy as updatedBy0_0_, client0_.contactNo as contactNo0_0_, client0_.contactPerson as contactP7_0_0_, client0_.contactPersonEmail as contactP8_0_0_, client0_.contactPersonNo as contactP9_0_0_, client0_.email as email0_0_, client0_.name as name0_0_ from client client0_ where client0_.id=?
[main] DEBUG Client Name : Client1

以下是我的持久性相关配置:

@Configuration
@EnableTransactionManagement
public class PersistanceConfig
{
    // injection

    private String[] PACKAGES_TO_SCAN = new String[] { "com.mypackage1", "com.mypackage2" };

    @Bean
    public DataSource dataSource()
    {
        // dataSource setting 'com.mysql.jdbc.Driver' as a jdbc driver
    }

    private Properties jpaProperties()
    {
        Properties properties = new Properties();

        properties.put(AvailableSettings.DIALECT, hibernateDialect);
        properties.put(AvailableSettings.SHOW_SQL, hibernateShowSql);

        // 2nd level cache
        properties.put("hibernate.cache.use_second_level_cache", true);
        properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");

        return properties;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()
    {
        // entity manager settings using dataSource and jpaProperties
    }

    @Bean
    public JpaTransactionManager transactionManager()
    {
        // transaction manager settings using entityManagerFactory
    }
}

有人能帮我解决一个问题或者我做错了什么吗?

提前感谢!

共有3个答案

长孙星汉
2023-03-14

@Transactional负责处理从会话工厂获取会话对象,从entityManagerFactory一级缓存获取entityManger对象,发生在会话级别或entityManger级别,所以@Tranaction注释在这里非常重要

钱修雅
2023-03-14

我已经在一个简单的命令行应用程序中测试了你的场景,无法重现这个问题。用Hibernate 4.0.1和Hibernate 4.3测试。基本上,我在事务之外提取了两次相同的实体,第二次SQL查询没有执行。重要提示:我一个接一个地调用EntityManager.find(),它们之间没有任何其他操作(如打开一个事务,这将触发另一个SQL选择)。

我向你推荐以下几点:1。确保您还查看了数据库服务器的日志(以确保Hibernate不会记录查询,尽管它不会发送查询)。2.将Hibernate升级到新版本。

另一个注意事项:据我所知,Hibernate不需要使用这样的缓存。

我用过的persistence.xml:

<persistence version="2.0" xmlns="http://xmlns.jcp.org/xml/ns/persistence"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_0.xsd"> 

    <persistence-unit name="my-PU" transaction-type="RESOURCE_LOCAL">

                <!--<provider>org.hibernate.ejb.HibernatePersistence</provider>-->
                <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

                <class>com.package.Entity</class>
                <exclude-unlisted-classes>false</exclude-unlisted-classes>
                <properties>
                        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
                        <property name="hibernate.hbm2ddl.import_files" valu="sql/import-users.sql"/>
                        <property name="hibernate.show_sql" value="true"/>
                        <property name="hibernate.format_sql" value="false"/>
                </properties>
    </persistence-unit>
</persistence>
太叔逸春
2023-03-14

您需要用@Transactional注释测试方法,或者使用SpringTransactionTemboard

即使检索实体不需要事务,在一个实体中分组多个调用也会清楚地指定持久性上下文边界(从何处开始,从何处结束)。

要复制第一级缓存,您需要在整个测试方法中使用相同的工作单元,并且使用@Transactional注释测试将启动一个事务(绑定到当前执行的持久性上下文事务的Spring逻辑事务,该事务与实际的物理数据库事务相关)。

当测试方法结束时,事务通常会回滚,因此不会将任何更改传播到任何后续测试,但在当前执行的测试方法中,您可以看到自己的更改,这是ACID中的隔离属性。

 类似资料:
  • 本文向大家介绍说一下 MyBatis 的一级缓存和二级缓存?相关面试题,主要包含被问及说一下 MyBatis 的一级缓存和二级缓存?时的应答技巧和注意事项,需要的朋友参考一下 一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。当 Session f

  • 1、一级缓存:指的是mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入sqlSession中,再次查询的时候,先去sqlSession中查询,有的话直接拿出,当sqlSession消失时,mybatis的一级缓存也就消失了,当调用sqlSession的修改、添加、删除、commit()、close()等方法时,会清空一级缓存。 2、二级缓存:指的是mybati

  • 一级缓存是session级别的缓存,默认开启,当查询一次数据库时,对查询结果进行缓存,如果之后的查询在一级缓存中存在,则无需再访问数据库; 二级缓存是sessionFactory级别的缓存,需要配置才会开启。当进行sql语句查询时,先查看一级缓存,如果不存在,访问二级缓存,降低数据库访问压力。

  • 让我澄清一下我对二级缓存的理解。在我的web应用程序的基类中有一个查询。几乎每一个操作都会调用此查询(我使用的是Struts,这就是应用程序的设计方式,因此不会真正弄乱它),例如,加载我的主页会调用三个单独的Struts操作,并为每个操作执行此查询。QueryDsl形式的查询看起来像

  • 本文向大家介绍Hibernate中一级缓存和二级缓存之间的区别,包括了Hibernate中一级缓存和二级缓存之间的区别的使用技巧和注意事项,需要的朋友参考一下 Hibernate支持两种类型的缓存,一种是第一级缓存,另一种是第二级缓存。  一级缓存是会话级缓存,它始终与会话级对象关联。这种类型的缓存用于通过缓存对象的状态来最小化Db交互。 那不是在事务中完成每次修改之后更新,而是仅在事务结束时更新

  • 我正在实现一个基于实体属性值的持久化机制。所有数据库访问都是通过Hibernate完成的。我有一个包含节点路径的表,它非常简单,只有一个id和一个路径(字符串)。路径数量很少,大约几千条。 主表有数百万行,我没有重复路径,而是将路径规范化为它们自己的表。以下是我在插入主表时想要的行为 1)检查路径表中是否存在路径(通过实体管理器查询,使用路径值作为参数) 2) 如果不存在,则插入并获取id(通过实