.HsqlException: user lacks privilege or object not found - java

First: I'm probably just making a stupid mistake.
I'm working on converting an old project of mine from Spring XML to Javaconfig. The database is an in-memory HSQLDB database. Unfortunately, it's giving me this error:
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
(stacktrace)
Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: PUBLIC.T_AUTHORITY
(stacktrace)
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: PUBLIC.T_AUTHORITY
Below are my PersistenceConfig.java and my SQL script:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "org.jason.application.repository.jpa",
entityManagerFactoryRef = "entityManagerFactoryBean")
public class ApplicationPersistenceConfig {
#Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(emf);
return jpaTransactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPersistenceUnitName("default");
entityManagerFactory.setDataSource(dataSource);
entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactory.setJpaDialect(new HibernateJpaDialect());
entityManagerFactory.setPackagesToScan("org.jason.application.repository.model");
entityManagerFactory.setJpaPropertyMap(hibernateJpaProperties());
return entityManagerFactory;
}
#Bean
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:mem:testdb");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
private Map<String, ?> hibernateJpaProperties() {
HashMap<String, String> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.import_files", "insert-data.sql");
properties.put("hibernate.hbm2ddl.auto", "create-drop");
properties.put("hibernate.show_sql", "false");
properties.put("hibernate.format_sql", "false");
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
properties.put("hibernate.c3p0.min_size", "2");
properties.put("hibernate.c3p0.max_size", "5");
properties.put("hibernate.c3p0.timeout", "300"); // 5mins
return properties;
}
}
and
CREATE TABLE PUBLIC.T_USER (
USERID INTEGER NOT NULL PRIMARY KEY,
USERNAME VARCHAR_IGNORECASE(50) NOT NULL,
PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,
ENABLED BOOLEAN NOT NULL,
CREATE UNIQUE INDEX IX_USERNAME ON T_USER(USERNAME);
CREATE TABLE PUBLIC.T_AUTHORITY (
AUTHORITYID INTEGER NOT NULL PRIMARY KEY,
USERID INTEGER NOT NULL,
-- USERNAME VARCHAR_IGNORECASE(50) NOT NULL,
AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,
CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERID) REFERENCES USERS(USERID));
CREATE UNIQUE INDEX IX_AUTH_USERNAME ON T_AUTHORITY (USERID,AUTHORITY);
INSERT INTO T_USER(USERNAME, PASSWORD, ENABLED) VALUES (1, 'jason','password', true);
INSERT INTO T_AUTHORITY(AUTHORITYID, USERID, AUTHORITY) VALUES (1, 1, "ROLE_ADMIN");
Can anyone see whatever stupid mistake I made?
Jason

It was a dumb mistake, just like I thought.
The following two hibernate properties are incompatible with one another:
properties.put("hibernate.hbm2ddl.import_files", "insert-data.sql");
properties.put("hibernate.hbm2ddl.auto", "create-drop");
Both have the effect of creating the schema.

Related

JPA: 2 databases: one "update", the other "create"

I want to use two database schemas: one with static data (which cannot be changed), the other with dynamic data (which will change constantly during the execution of the Spring application).
In application.properties I have prescribed the following:
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/XXXXXX
spring.datasource.username=root
spring.datasource.password=root
spring.second-datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/YYYYYY
spring.second-datasource.username=root
spring.second-datasource.password=root
But what should I do now with the spring.jpa.hibernate.ddl-auto parameter?
For one scheme I want to install:
spring.jpa.hibernate.ddl-auto=create
And for the other (where the data is always static):
spring.jpa.hibernate.ddl-auto=update
or
spring.jpa.hibernate.ddl-auto=none
You have an issue that you need two different datasources. You should define them as 2 different beans and autowire them seperately. For clarity it's advisable to also use 2 different properties files.
You can create a Configuration class and use specific properties file to populate fields like so:
#Configuration
#PropertySource("classpath:db.properties")
public class Config {
#Value("${db.driverClassName}")
String driverClassName;
#Value("${db.url}")
String url;
#Value("${db.username}")
String username;
#Value("${db.password}")
String password;
#Bean("datasourceId")
public DataSource dataSource() {
var dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
{ "com.foo.bar" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "create-drop");
return hibernateProperties;
}
}

Spring boot environnement variable like Laravel

Here is the application.properties of my Spring Boot 2.5 :
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}
spring.datasource.username=${MYSQL_USER:root}
spring.datasource.password=${MYSQL_PASSWORD:root}
I migrated my application from Spring MVC 4.3 and I don't use JPA on the latest version of Spring Boot.
So I configured a #Beandatasource like this:
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getRequiredProperty("spring.datasource.url"));
dataSource.setUsername(env.getRequiredProperty("spring.datasource.username"));
dataSource.setPassword(env.getRequiredProperty("spring.datasource.password"));
return dataSource;
}
However, this does not work because instead of having the value of the environment variable, I have the name of the environment variable, i.e. ${MYSQL_USER:root} for example.
My question is what is Spring's recommended way here to set up environment variables much like Laravel's .env in my datasource() and also in the application.properties if I decide to use JPA later on?
The reason and the important point: I don't want to push my credentials on git
EDIT :
HibernateUtil :
static {
try {
Properties applicationProps = new Properties();
File file = ResourceUtils.getFile("classpath:application.properties");
InputStream input = new FileInputStream(file);
applicationProps.load(input);
Properties properties = new ApplicationConf().hibernateProperties();
// Configure datasource
properties.setProperty("hibernate.connection.driver_class", applicationProps.getProperty("spring.datasource.driver-class-name"));
properties.setProperty("hibernate.connection.url", applicationProps.getProperty("spring.datasource.url"));
properties.setProperty("hibernate.connection.username", applicationProps.getProperty("spring.datasource.username"));
properties.setProperty("hibernate.connection.password", applicationProps.getProperty("spring.datasource.password"));
properties.setProperty("hibernate.current_session_context_class", "thread");
properties.setProperty("hibernate.jdbc.batch_size", Integer.toString(BATCH_SIZE));
// Override some properties
properties.setProperty("hibernate.format_sql", "false");
properties.setProperty("hibernate.show_sql", "false");
} catch {}
...
}
Best regards,
You can use the #Value annotation to pull the properties and also their defaults.
#Value("${spring.datasource.username}")
private String userName;
#Bean
public DataSource dataSource() {
...
dataSource.setUsername(userName);
...
return dataSource;
}
You can also omit the default from the application.properties file and specify a default value for the property using Value annotation -
#Value("${spring.datasource.username:root}")
private String userName;
#Bean
public DataSource dataSource() {
...
dataSource.setUsername(userName);
...
return dataSource;
}
Or can even be injected in the method-
#Bean
public DataSource dataSource(#Value("${spring.datasource.username:root}") String userName) {
...
dataSource.setUsername(userName);
...
return dataSource;
}

JPA with Spring Embebed Database not records found

Starting from a program that was connected to a mysql database, using spring, JPA and JDBC, I am trying to configure that application to use the H2 database in embedded mode.
With MYSQL everything works fine, but with H2 not.
I can not get H2 to return any records, although the records are there so if I do the same query through JDBC, if I see them.
The configuration that I have is the following:
#Configuration
#EnableJpaRepositories("yages.yagesserver")
#EnableTransactionManagement
public class JpaConfig {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.setName("yagesh2")
.ignoreFailedDrops(true)
.addScript("db/sql/create-db.sql")
.addScript("db/sql/insert-data.sql")
.generateUniqueName(false)
.build();
return db;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) throws NamingException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[]{"yages.yagesserver", "yages.yagesserver.dao"});
em.setPersistenceUnitName("yages-server");
em.setJpaVendorAdapter(jpaVendorAdapter());
em.afterPropertiesSet();
return em;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(false);
jpaVendorAdapter.setDatabase(Database.H2);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
So if I write this code:
String s="SELECT cal_ano,cal_mes,cal_fecini,cal_fecfin from calendario where cal_ano=? and cal_mes = ?";
List<Calendario> cal =
jdbc.query(s, new Object[] { ano,mes},
(rs, rowNum) -> new Calendario(
rs.getInt("cal_ano"),rs.getInt("cal_mes"),rs.getDate("cal_fecini"),rs.getDate("cal_fecfin"))
);
System.out.println("getDatosSemana. Size "+cal.size()+ "Fecha Inicio: "+cal.get(0).getFechaInicio());
Optional<Calendario> calOpc = calendarioRepositorio.getCalendario(new CalendarioKey(ano - 1, mes));
System.out.println("getDatosSemana. Optional is present: "+calOpc.isPresent());
When I use JDBC I see that in the calendar table if the record exists, but when using JPA, it does not seem to find anything.
This is the output in my console:
getDatosSemana. Size 1Fecha Inicio: 2018-01-28
Hibernate: select calendario0_.cal_ano as cal_ano1_0_0_, calendario0_.cal_mes as cal_mes2_0_0_, calendario0_.cal_fecfin as cal_fecf3_0_0_, calendario0_.cal_fecini as cal_feci4_0_0_ from calendario calendario0_ where calendario0_.cal_ano=? and calendario0_.cal_mes=?
getDatosSemana. Optional is present: false
Of course I have the DAO classes and my repository that extends from a CrudRepository.
Any suggestions, please?
I'm sorry. I have found the error.
It was a failure foolishness. I called the JPA function with the parameters of year and month reversed.
Sometimes you do not see the obvious.

How to use pagination on queries in Hibernate with Java based configuration

This is my hibernate configuration:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(final DataSource dataSource,
final Environment env)
{
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("...");
final Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
jpaProperties.put("hibernate.hbm2ddl.auto", env.getRequiredProperty("hibernate.hbm2ddl.auto"));
jpaProperties.put("hibernate.ejb.naming_strategy", env.getRequiredProperty("hibernate.ejb.naming_strategy"));
jpaProperties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
jpaProperties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
Now I want to make a query in HQL (using #Query(value = "query")) with standard pagination settings like offset and limit. I know about query.setMaxResults() and query.setFirstResult(), but for that I need a Session (or do I?), but I didn't use sessions to configure Hibernate.
Can I use annotations only to specify the offset and limit to queries? Is there a way to use HQL to programmatically simulate query.setMaxResults() and query.setFirstResult()?
Following code may help you.
public Page<Product> findAll(Pageable pageable){
//custom page
PageRequest customPageable = new PageRequest(pageable.getPageNumber(), 100);
return productRepository.findAll(customPageable);
}

Hibernate Second-Level Cache using EhCache

I want to configure Second-Level cache in hibernate. I find out official documentation of EhCache and did it. But i got exception:
Caused by: org.hibernate.cache.NoCacheRegionFactoryAvailableException: Second-level cache is used in the application, but property hibernate.cache.region.factory_class is not given; please either disable second level cache or set correct region factory using the hibernate.cache.region.factory_class setting and make sure the second level cache provider (hibernate-infinispan, e.g.) is available on the classpath.
at org.hibernate.cache.internal.NoCachingRegionFactory.buildEntityRegion(NoCachingRegionFactory.java:83) ~[NoCachingRegionFactory.class:4.3.3.Final]
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:364) ~[SessionFactoryImpl.class:4.3.3.Final]
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857) ~[Configuration.class:4.3.3.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) ~[EntityManagerFactoryBuilderImpl$4.class:4.3.4.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843) ~[EntityManagerFactoryBuilderImpl$4.class:4.3.4.Final]
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:397) ~[ClassLoaderServiceImpl.class:4.3.3.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842) ~[EntityManagerFactoryBuilderImpl.class:4.3.4.Final]
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:150) ~[HibernatePersistenceProvider.class:4.3.4.Final]
It is not full exception message, but main info.
Below configuration of my web application:
private Properties hibernateProperties() {
return new Properties() {{
setProperty("hibernate.connection.characterEncoding", "UTF-8");
setProperty("hibernate.connection.charSet", "UTF-8");
setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect");
setProperty("hibernate.show_sql", "true");
setProperty("hibernate.format_sql", "true");
setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
setProperty("hibernate.enable_lazy_load_no_trans", "true");
setProperty("hibernate.cache.use_second_level_cache", "true");
setProperty("hibernate.cache.use_query_cache", "true");
setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
/*setProperty("net.sf.ehcache.configurationResourceName", env.getProperty("net.sf.ehcache.configurationResourceName"));*/
}};
}
#Bean
LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("com.smartestgift.*");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
And EntityManager configuration. I don't think thats the main problem here, but i will show it code:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan("com.smartestgift.*");
//let Hibernate know which database we're using.
//note that this is vendor specific, not JPA
Map opts = emf.getJpaPropertyMap();
opts.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(va);
return emf;
}
I can't understand what's the problem. Why hibernate can't see that property?
UPDATED:
M. Denium - thank you! You were right, i delete entity manager and refactor sessionFactory method, now it look like this:
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("com.smartestgift.*");
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.connection.characterEncoding", "UTF-8");
hibernateProperties.put("hibernate.connection.charSet", "UTF-8");
hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect");
hibernateProperties.put("hibernate.show_sql", "true");
hibernateProperties.put("hibernate.format_sql", "true");
//hibernateProperties.put("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.put("hibernate.enable_lazy_load_no_trans", "true");
// second level cache
hibernateProperties.put("hibernate.cache.use_second_level_cache", "true");
hibernateProperties.put("hibernate.cache.use_query_cache", "true");
hibernateProperties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
//hibernateProperties.put("net.sf.ehcache.configurationResourceName", env.getProperty("net.sf.ehcache.configurationResourceName"));
// testing
hibernateProperties.put("hibernate.bytecode.use_reflection_optimizer", false);
hibernateProperties.put("hibernate.check_nullability", false);
hibernateProperties.put("hibernate.search.autoregister_listeners", false);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
try {
sessionFactoryBean.afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return sessionFactoryBean.getObject();
}
But now i got new problem, i dont know how implement OpenEntityManagerInViewInterceptor, because before deleting entity manager i have next code:
OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor();
interceptor.setEntityManagerFactory(entityManagerFactory().getObject());
But now i have not entityManagerFactory and i dont know how to make this interceptor now...

Categories