【问题标题】:Spring boot session.enableFilter cause AssertionFailure: table not foundSpring boot session.enableFilter 导致 AssertionFailure: table not found
【发布时间】:2017-09-23 17:17:17
【问题描述】:

我正在尝试使用 spring boot 和 entitymanager 来访问 mysql db。但是如果我使用 session.enableFilter 它会导致奇怪的异常。在互联网上尝试了很多搜索,但都没有帮助。

DataSourceContext.java

@Configuration
@EnableTransactionManagement
public class DataSourceContext {
    public final static String DB_PREFIX = "P_";

    @Autowired
    Environment env;

    @Bean
    @Qualifier("dataSource")
    public DataSource dataSource(Properties hibernateProperties) {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUsername(env.getProperty("jdbc.username"));
        ds.setPassword(env.getProperty("jdbc.password"));
        ds.setUrl(env.getProperty("jdbc.url"));
        ds.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        ds.setConnectionProperties(hibernateProperties);
        return ds;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource") DataSource dataSource, Properties hibernateProperties) {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan("com.example.model");
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibernateProperties);
        em.setPersistenceUnitName("persistanceUnit");
        em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        em.afterPropertiesSet();

        return em;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(entityManagerFactory);
        return tm;
    }

    @Bean
    public Properties hibernateProperties() {
        final Properties properties = new Properties();

        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.default_schema", env.getProperty("hibernate.default_schema"));

        return properties;
    }
}

Aentity.java

@Entity
@Table(name = DataSourceContext.DB_PREFIX + "AENTITY")
@FilterDef(name = "statusFilter", defaultCondition = "STATUS = :status ", parameters = @ParamDef(name = "status", type = "string"))
@Filters({@Filter(name = "statusFilter", condition = "STATUS = :status")})
public class Aentity implements Serializable {
    private Long id;
    private EntityStatus status;
    private Date createdDate;
    private Date updatedDate;
    private Date deletedDate;
    private Long version;

    // getters and setter with column annotations.
}

Adao.java

@Transactional(rollbackFor = Exception.class)
@Repository
public class Adao {

    @PersistenceContext
    protected EntityManager em;

    public EntityManager getEm() {
        /* exception lines */
        em.unwrap(Session.class)
            .enableFilter("statusFilter")
            .setParameter("status", EntityStatus.ACTIVE.name());

        return em;
    }

    public List<Aentity> findAll() {
        List resultList = getEm().createQuery("select distinct aentity from Aentity aentity")
                .getResultList();

        return resultList;
    }
}

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

日志;

----unrelated logs----
2017-04-26 13:32:36.145  INFO 60417 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2017-04-26 13:32:36.187 ERROR 60417 --- [           main] org.hibernate.AssertionFailure           : HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: Table myschema.P_AENTITY not found
----unrelated logs----

----some logs----
Caused by: org.hibernate.AssertionFailure: Table myschema.P_AENTITY not found
    at org.hibernate.persister.entity.AbstractEntityPersister.getTableId(AbstractEntityPersister.java:5181) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.DynamicFilterAliasGenerator.getAlias(DynamicFilterAliasGenerator.java:31) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.FilterHelper.render(FilterHelper.java:109) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.FilterHelper.render(FilterHelper.java:96) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.filterFragment(AbstractEntityPersister.java:3587) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.internal.JoinSequence.toJoinFragment(JoinSequence.java:175) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.util.JoinProcessor.addJoinNodes(JoinProcessor.java:147) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.util.JoinProcessor.processJoins(JoinProcessor.java:141) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:694) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:673) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:309) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:257) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:302) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:240) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1894) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:291) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.8.RELEASE.jar:4.3.8.RELEASE]
    at com.sun.proxy.$Proxy80.createQuery(Unknown Source) ~[na:na]
    at com.example.dao.Adao.findAll(Adao.java:27) ~[classes/:na]
    at com.example.dao.Adao$$FastClassBySpringCGLIB$$c40f7d5e.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.8.RELEASE.jar:4.3.8.RELEASE]
----some logs----

如果我删除 Adao.java 类中的启用过滤器,那么它工作正常。

另一种情况是如果我使用SessionFactory而不是entitymanager,结果是一样的。

我该如何解决这个问题?

【问题讨论】:

    标签: java mysql maven spring-boot entitymanager


    【解决方案1】:

    首先你能检查一下你的休眠配置是否有这些属性:

    hibernate.dialect=org.hibernate.dialect.MySQLDialect  //you should use mysql dialect from pom I see that you use mysql
    #hibernate.default_schema=myCustomName                //commented out in case you want use default schema, else you can use this property to create your custom schema
    hibernate.show_sql=true                               //this will help so see what queries are executed
    hibernate.format_sql=true                             //this will print formatted sql
    hibernate.hbm2ddl.auto=create                         //this will generate database tables if they don't exist in DB, also you can change to "update" this property then database will get updates.
    

    第二件事我怀疑引号可能有问题,它们是 JPA 样式但在休眠尝试中没有(是否有理由在过滤器中将 STATUS 设为大写?):

    @Entity
    @Table(name = DataSourceContext.DB_PREFIX + "AENTITY")
    @FilterDef(name = "statusFilter", defaultCondition = "`status` = :status ", parameters = @ParamDef(name = "status", type = "string"))
    @Filter(name = "statusFilter", condition = "`status` = :status")
    public class Aentity implements Serializable {
        private Long id;
        private EntityStatus status;
        private Date createdDate;
        private Date updatedDate;
        private Date deletedDate;
        private Long version;
    
        // getters and setter with column annotations.
    }
    

    【讨论】:

      【解决方案2】:

      基本上,DynamicFilterAliasGenerator 存在一个问题,它不尊重hibernate.default_schema(它知道有表P_AENTITY,但由于它没有关于默认方案的信息,因此无法比较运行时表名称@987654324 @ 与它拥有的那个)。

      因此,如果您需要快速修复,只需从休眠配置中删除 hibernate.default_schema 并在 jdbc.url 上中继即可。 所以不要有这样的东西

      properties.put("hibernate.default_schema", "myschema");
      

      在 JDBC URL 中有这样的架构

      DriverManagerDataSource ds = new DriverManagerDataSource();
      ....
      ds.setUrl("jdbc:mysql://localhost:3306/myschema");
      ....
      

      【讨论】:

      • 感谢您的回答,成功了。如果它是快速修复,那么这种情况的真正解决方法是什么?
      • 真正的解决方案是查看 hibetnate 资源,在那里解决问题,创建 PR 并帮助社区))
      猜你喜欢
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 2015-10-19
      • 2018-04-07
      • 2018-12-10
      • 1970-01-01
      相关资源
      最近更新 更多