将 MariaDB 与 Hibernate Filter 一起使用时如何获取 AssertionFailure 'Table not found' 的根本原因?
How to get root cause of AssertionFailure 'Table not found' when using MariaDB with Hibernate Filter?
我正在使用以下测试设置评估 Hibernate Filter 功能 与各种数据库:
- Spring 引导启动器 1.5.3.RELEASE
- 休眠 5.2.10.Final
- Spring Data Envers 1.1.3.RELEASE -> Spring Data JPA 1.11.3.RELEASE
- mariadb-java-客户端 1.5.9
- HikariCP 2.6.1
- MariaDB 10.1.22(docker 容器)
数据库模式是使用 Flyway 设置的并且工作正常,所以 table 就在那里。
现在我有一个 实体 class 'User' 具有自定义 table 名称和活动字段过滤器:
@Entity
@Table(name = "\"users\"")
@FilterDef(name = "activeUsers", parameters = @ParamDef(name = "active", type = "boolean"))
@Filter(name = "activeUsers", condition = "\"active\" = :active")
public class User {
@Id
private Long id;
private boolean active;
// getters/setters (not shown)
}
此外,还提供了一个自定义存储库以允许使用过滤器:
public interface RepositoryExtended<T> {
Iterable<T> findAll(boolean active);
}
public class UserRepositoryImpl implements RepositoryExtended<User> {
@Autowired
private UserRepository userRepository;
@Override
public Iterable<User> findAll(boolean active) {
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(entityManagerFactory);
EntityManager entityManager = holder.getEntityManager();
Filter hibernateFilter = entityManager.unwrap(Session.class).enableFilter("activeUsers").setParameter("active", active);
hibernateFilter.validate();
Iterable<User> users = userRepository.findAll();
entityManager.unwrap(Session.class).disableFilter("activeUsers");
return users;
}
}
最终 UserRepository 基于 Spring Data JPA CrudRepository 和上面的自定义存储库:
public interface UserRepository extends CrudRepository<User, Long>, RepositoryExtended<User> {
}
现在测试设置:
@RunWith(SpringRunner.class)
@Transactional
@Rollback
@ContextConfiguration(classes = { DBConfig.class })
public class UserRepositoryTests {
@PersistenceContext
private EntityManager em;
@Autowired
UserRepository repository;
@Before
public void setUp() {
user = new User();
user.setActive(true);
user = repository.save(user);
user2 = new User();
user2.setActive(true);
user2 = repository.save(user2);
em.flush();
em.clear();
}
@Test
public void filteredQueries() {
assertEquals(2, repository.count());
assertTrue(repository.findAll().iterator().hasNext());
Iterable<User> findAllActive = repository.findAll(true); // THIS FAILS
assertTrue(findAllActive.iterator().hasNext());
}
}
使用 JDBC 和 Hibernate/JPA 设置:
mariadb.db.driver=org.mariadb.jdbc.Driver
mariadb.db.url=jdbc:mariadb://127.0.0.1:3306/PRORK
mariadb.db.username=root
mariadb.db.password=root
hibernate.dialect=org.hibernate.dialect.MariaDB53Dialect
hibernate.globally_quoted_identifiers=true
hibernate.hbm2ddl.auto=validate
hibernate.format_sql=true
hibernate.show_sql=true
hibernate.default_schema=PRORK
在 bean 配置中使用:
@Configuration
@EnableTransactionManagement
public class DBConfig {
@Bean(destroyMethod = "close")
public DataSource dataSource(Environment env) {
HikariConfig dataSourceConfig = new HikariConfig();
dataSourceConfig.setDriverClassName("org.mariadb.jdbc.Driver");
dataSourceConfig.setJdbcUrl("jdbc:mariadb://127.0.0.1:3306/PRORK");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("root");
return new HikariDataSource(dataSourceConfig);
}
@Bean
public Properties jpaProperties() {
Properties jpaProperties = new Properties();
jpaProperties.put(hibernate.dialect, "org.hibernate.dialect.MariaDB53Dialect");
jpaProperties.put(hibernate.hbm2ddl.auto,"validate");
jpaProperties.put(hibernate.show_sql,"true");
jpaProperties.put(hibernate.format_sql,"true");
jpaProperties.put(hibernate.globally_quoted_identifiers,"true");
jpaProperties.put(hibernate.default_schema, "PRORK");
return jpaProperties;
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("test.prork");
entityManagerFactoryBean.setJpaProperties(jpaProperties());
return entityManagerFactoryBean;
}
@Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
运行 以下堆栈跟踪中的测试结果:
org.hibernate.AssertionFailure: Table `PRORK`.`users` not found
at org.hibernate.persister.entity.AbstractEntityPersister.getTableId(AbstractEntityPersister.java:5231)
at org.hibernate.internal.DynamicFilterAliasGenerator.getAlias(DynamicFilterAliasGenerator.java:31)
at org.hibernate.internal.FilterHelper.render(FilterHelper.java:109)
at org.hibernate.internal.FilterHelper.render(FilterHelper.java:96)
at org.hibernate.persister.entity.AbstractEntityPersister.filterFragment(AbstractEntityPersister.java:3641)
at org.hibernate.engine.internal.JoinSequence.toJoinFragment(JoinSequence.java:201)
at org.hibernate.engine.internal.JoinSequence.toJoinFragment(JoinSequence.java:187)
at org.hibernate.hql.internal.ast.util.JoinProcessor.addJoinNodes(JoinProcessor.java:164)
at org.hibernate.hql.internal.ast.util.JoinProcessor.processJoins(JoinProcessor.java:158)
at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:785)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:677)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:313)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:261)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:266)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:546)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:655)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3318)
at org.hibernate.query.criteria.internal.CriteriaQueryImpl.buildCompiledQuery(CriteriaQueryImpl.java:318)
at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:127)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3611)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy116.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:656)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:633)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:329)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy120.findAll(Unknown Source)
at test.prork.persistence.UserRepositoryImpl.findAll(UserRepositoryImpl.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:479)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy120.findAll(Unknown Source)
at test.prork.persistence.AbstractUserRepositoryTests.filteredQueries(AbstractUserRepositoryTests.java:199)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=17=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:147)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:129)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.StoppableExecutorImpl.run(StoppableExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
相同的测试对 H2、PostgreSQL 和 Oracle DB 没有问题,只有 MariaDB 失败了。另请注意,没有 Hibernate 过滤器的 findAll() 方法工作得很好,count 方法也是如此。其他一些未显示的基本 CrudRepository 方法测试也适用于所有四个数据库系统。
我应用过滤器的方法是否有问题,而对于其他数据库系统,它只是偶然工作?
对于带有 Hibernate 过滤器的 MariaDB,是否有任何设置错误或特殊设置需要牢记?
setup/code中有两个问题:
首先 MySQL/MariaDB 没有架构,所以删除
hibernate.default_schema
设置 到 摆脱 AssertionFailure 因为他们使用目录而不是架构。无论如何应该由 JDBC 连接给出。 This Hibernate JIRA ticket gave me the necessary hint,虽然有更多票据指向 directly/indirectly 这个原因。
第二个 MariaDB 使用过滤器仍然会失败(可能 MySQL 也是如此,没有测试它)。这是 因为 Filter 条件中的引号是 JPA 样式,但只有 hibernate legacy quotes(即使用 backtips) 现在似乎可以工作。 完全没有引号也不起作用。
实体现在看起来像:
@Entity
@Table(name = "\"users\"")
@FilterDef(name = "activeUsers", parameters = @ParamDef(name = "active", type = "boolean"))
@Filter(name = "activeUsers", condition = "`active` = :active")
public class User {
@Id
private Long id;
private boolean active;
// getters/setters (not shown)
}
A last tip as it helped me identifying the second issue: take a close
look at the Hibernate SQL queries generated from HQL, especially regarding quotes etc.
更新: 我打开了一个 ticket in the Hibernate JIRA 因为它可能是一个 Hibernate(MariaDB 方言)问题。
这不是错误,@Filter 条件值是直接传递给数据库的 SQL 表达式。
Mariadb 似乎支持两种类型的引号,除非 sql_mode = "ANSI_QUOTES" https://mariadb.com/resources/blog/quotes
我正在使用以下测试设置评估 Hibernate Filter 功能 与各种数据库:
- Spring 引导启动器 1.5.3.RELEASE
- 休眠 5.2.10.Final
- Spring Data Envers 1.1.3.RELEASE -> Spring Data JPA 1.11.3.RELEASE
- mariadb-java-客户端 1.5.9
- HikariCP 2.6.1
- MariaDB 10.1.22(docker 容器)
数据库模式是使用 Flyway 设置的并且工作正常,所以 table 就在那里。
现在我有一个 实体 class 'User' 具有自定义 table 名称和活动字段过滤器:
@Entity
@Table(name = "\"users\"")
@FilterDef(name = "activeUsers", parameters = @ParamDef(name = "active", type = "boolean"))
@Filter(name = "activeUsers", condition = "\"active\" = :active")
public class User {
@Id
private Long id;
private boolean active;
// getters/setters (not shown)
}
此外,还提供了一个自定义存储库以允许使用过滤器:
public interface RepositoryExtended<T> {
Iterable<T> findAll(boolean active);
}
public class UserRepositoryImpl implements RepositoryExtended<User> {
@Autowired
private UserRepository userRepository;
@Override
public Iterable<User> findAll(boolean active) {
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(entityManagerFactory);
EntityManager entityManager = holder.getEntityManager();
Filter hibernateFilter = entityManager.unwrap(Session.class).enableFilter("activeUsers").setParameter("active", active);
hibernateFilter.validate();
Iterable<User> users = userRepository.findAll();
entityManager.unwrap(Session.class).disableFilter("activeUsers");
return users;
}
}
最终 UserRepository 基于 Spring Data JPA CrudRepository 和上面的自定义存储库:
public interface UserRepository extends CrudRepository<User, Long>, RepositoryExtended<User> {
}
现在测试设置:
@RunWith(SpringRunner.class)
@Transactional
@Rollback
@ContextConfiguration(classes = { DBConfig.class })
public class UserRepositoryTests {
@PersistenceContext
private EntityManager em;
@Autowired
UserRepository repository;
@Before
public void setUp() {
user = new User();
user.setActive(true);
user = repository.save(user);
user2 = new User();
user2.setActive(true);
user2 = repository.save(user2);
em.flush();
em.clear();
}
@Test
public void filteredQueries() {
assertEquals(2, repository.count());
assertTrue(repository.findAll().iterator().hasNext());
Iterable<User> findAllActive = repository.findAll(true); // THIS FAILS
assertTrue(findAllActive.iterator().hasNext());
}
}
使用 JDBC 和 Hibernate/JPA 设置:
mariadb.db.driver=org.mariadb.jdbc.Driver
mariadb.db.url=jdbc:mariadb://127.0.0.1:3306/PRORK
mariadb.db.username=root
mariadb.db.password=root
hibernate.dialect=org.hibernate.dialect.MariaDB53Dialect
hibernate.globally_quoted_identifiers=true
hibernate.hbm2ddl.auto=validate
hibernate.format_sql=true
hibernate.show_sql=true
hibernate.default_schema=PRORK
在 bean 配置中使用:
@Configuration
@EnableTransactionManagement
public class DBConfig {
@Bean(destroyMethod = "close")
public DataSource dataSource(Environment env) {
HikariConfig dataSourceConfig = new HikariConfig();
dataSourceConfig.setDriverClassName("org.mariadb.jdbc.Driver");
dataSourceConfig.setJdbcUrl("jdbc:mariadb://127.0.0.1:3306/PRORK");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("root");
return new HikariDataSource(dataSourceConfig);
}
@Bean
public Properties jpaProperties() {
Properties jpaProperties = new Properties();
jpaProperties.put(hibernate.dialect, "org.hibernate.dialect.MariaDB53Dialect");
jpaProperties.put(hibernate.hbm2ddl.auto,"validate");
jpaProperties.put(hibernate.show_sql,"true");
jpaProperties.put(hibernate.format_sql,"true");
jpaProperties.put(hibernate.globally_quoted_identifiers,"true");
jpaProperties.put(hibernate.default_schema, "PRORK");
return jpaProperties;
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("test.prork");
entityManagerFactoryBean.setJpaProperties(jpaProperties());
return entityManagerFactoryBean;
}
@Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
运行 以下堆栈跟踪中的测试结果:
org.hibernate.AssertionFailure: Table `PRORK`.`users` not found
at org.hibernate.persister.entity.AbstractEntityPersister.getTableId(AbstractEntityPersister.java:5231)
at org.hibernate.internal.DynamicFilterAliasGenerator.getAlias(DynamicFilterAliasGenerator.java:31)
at org.hibernate.internal.FilterHelper.render(FilterHelper.java:109)
at org.hibernate.internal.FilterHelper.render(FilterHelper.java:96)
at org.hibernate.persister.entity.AbstractEntityPersister.filterFragment(AbstractEntityPersister.java:3641)
at org.hibernate.engine.internal.JoinSequence.toJoinFragment(JoinSequence.java:201)
at org.hibernate.engine.internal.JoinSequence.toJoinFragment(JoinSequence.java:187)
at org.hibernate.hql.internal.ast.util.JoinProcessor.addJoinNodes(JoinProcessor.java:164)
at org.hibernate.hql.internal.ast.util.JoinProcessor.processJoins(JoinProcessor.java:158)
at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:785)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:677)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:313)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:261)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:266)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:546)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:655)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3318)
at org.hibernate.query.criteria.internal.CriteriaQueryImpl.buildCompiledQuery(CriteriaQueryImpl.java:318)
at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:127)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3611)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy116.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:656)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:633)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:329)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy120.findAll(Unknown Source)
at test.prork.persistence.UserRepositoryImpl.findAll(UserRepositoryImpl.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:479)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy120.findAll(Unknown Source)
at test.prork.persistence.AbstractUserRepositoryTests.filteredQueries(AbstractUserRepositoryTests.java:199)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=17=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:147)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:129)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.StoppableExecutorImpl.run(StoppableExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
相同的测试对 H2、PostgreSQL 和 Oracle DB 没有问题,只有 MariaDB 失败了。另请注意,没有 Hibernate 过滤器的 findAll() 方法工作得很好,count 方法也是如此。其他一些未显示的基本 CrudRepository 方法测试也适用于所有四个数据库系统。
我应用过滤器的方法是否有问题,而对于其他数据库系统,它只是偶然工作?
对于带有 Hibernate 过滤器的 MariaDB,是否有任何设置错误或特殊设置需要牢记?
setup/code中有两个问题:
首先 MySQL/MariaDB 没有架构,所以删除
hibernate.default_schema
设置 到 摆脱 AssertionFailure 因为他们使用目录而不是架构。无论如何应该由 JDBC 连接给出。 This Hibernate JIRA ticket gave me the necessary hint,虽然有更多票据指向 directly/indirectly 这个原因。
第二个 MariaDB 使用过滤器仍然会失败(可能 MySQL 也是如此,没有测试它)。这是 因为 Filter 条件中的引号是 JPA 样式,但只有 hibernate legacy quotes(即使用 backtips) 现在似乎可以工作。 完全没有引号也不起作用。
实体现在看起来像:
@Entity
@Table(name = "\"users\"")
@FilterDef(name = "activeUsers", parameters = @ParamDef(name = "active", type = "boolean"))
@Filter(name = "activeUsers", condition = "`active` = :active")
public class User {
@Id
private Long id;
private boolean active;
// getters/setters (not shown)
}
A last tip as it helped me identifying the second issue: take a close look at the Hibernate SQL queries generated from HQL, especially regarding quotes etc.
更新: 我打开了一个 ticket in the Hibernate JIRA 因为它可能是一个 Hibernate(MariaDB 方言)问题。
这不是错误,@Filter 条件值是直接传递给数据库的 SQL 表达式。
Mariadb 似乎支持两种类型的引号,除非 sql_mode = "ANSI_QUOTES" https://mariadb.com/resources/blog/quotes