Hibernate Second-Level Cache using EhCache - java

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...

Related

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);
}

How to use getCurrentSession in Hibernate?

Configuration hibernate
Properties prop= new Properties();
prop.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
prop.setProperty("hibernate.connection.url", url);
prop.setProperty("hibernate.connection.username", user);
prop.setProperty("hibernate.connection.password", password);
concreteSessionFactory = new AnnotationConfiguration()
.addPackage("Main.*")
.addProperties(prop)
.addAnnotatedClass(DeviceDataSet.class)
.buildSessionFactory();
public SessionFactory sessionFactory() {
return concreteSessionFactory;
}
I use
public long insertNewJournalNote(JournalDataSet journalDataSet) {
Session session = sessionFactory.openSession();
MySqlDAO dao = new MySqlDAO(session);
return dao.insertNewJournalNote(journalDataSet);
}
With getCurrentSession, I get:
Exception in thread "main" org.hibernate.HibernateException: No CurrentSessionContext configured
Maybe this line could solve your problem:
prop.setProperty("hibernate.current_session_context_class", thread);

Spring Hibernate H2 Junit testing - how to load schema on start

I am trying to develop tests for my application (I found out about the tests very late...) and I am stuck and the basic configuration. I have googled through many examples and none of them satisfied me and frankly left me a bit confused.
What I am trying to achieve is to load an import.sql on start of the test (which is a dump file from existing MySQL schema) and load it into H2 database.
Here is the hibernate config file:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "kamienica.feature" })
public class HibernateTestConfiguration {
#Autowired
ApplicationContext applicationContext;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "kamienica" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;"
+ "INIT=CREATE SCHEMA IF NOT EXISTS kamienica;DB_CLOSE_ON_EXIT=FALSE");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.hbm2ddl.auto", "update");
// this is where I tried to load script the first time:
// properties.put("hibernate.hbm2ddl.import_files", "kamienica.sql");
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
Everytime I start a test I get a message that:
org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata INFO:
HHH000262: Table not found: apartment
And I get empty/null values when trying to retrieve anything
I have tried to load sql file in the hibernate config (via hibernate properties) as well as in superclass which all my test classes are planned to extend:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { HibernateTestConfiguration.class })
public class BaseTest {
private EmbeddedDatabase db;
#Autowired
private SessionFactory sessionFactory;
//second attempt to load sql file
#Before
public void setUp() throws Exception {
db = new EmbeddedDatabaseBuilder().addScript("import.sql").build();
}
#After
public void tearDown() throws Exception {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
How can I load sql file and prepare the H2 database to perform the tests?
I hope this spring boot approach will help you. First create a resources directory (classpath for springboot)in the src/test directory at the root of your project.
In this directory, you will start placing your fixture SQL data files named say data.sql .
Then, create a application.properties file on the same level (same directory see screenshot). This file should be populated as shown here:
spring.datasource.url = jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
#spring.datasource.url: jdbc:mysql://localhost:3306/yourDB
#spring.datasource.username = root
#spring.datasource.password =
# Hibernate
hibernate.show_sql: true
#hibernate.dialect: org.hibernate.dialect.MySQL5Dialec
spring.jpa.hibernate.ddl-auto=none
Screenshot:
Now your tester method.
#RunWith(SpringJUnit4ClassRunner.class)
....
#Autowired
private DataSource ds; //your application.properties
#Autowired
private WebApplicationContext context;
private static boolean loadDataFixtures = true;
private MockMvc mockMvc;
....
#Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
#Before
public void loadDataFixtures() {
if (loadDataFixtures) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(context.getResource("classpath:/data.sql"));
DatabasePopulatorUtils.execute(populator, ds);
loadDataFixtures = false;
}
}
#Test
public void yourmethod() {
assertEquals(3, repository.count()); //example
}
Without any output or the complete stacktrace, the only I can suggest you is:
You aren't showing any #Test method. How are you getting that error?
Is your file import.sql in src/test/resources folder? (note the test path)
Is your sql script well formated? Have you tried to run once exported? Could you post the part of the sql script wich creates the apartment table ?
If all are true, maybe the problem is not about loading the sql but how it's used, or the content of the script, or the name of the tables, etc...
After a long 'investigation' I have concluded that the problem was hidden somewhere in he DBUnit, TestNG setup.
I decided to keep it simple and switched to JUnit tests.
In case others might have similar problems here is the config file that works for me:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "kamienica.feature" })
public class JUnitConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "kamienica" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:kamienica;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.hbm2ddl.auto", "create");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
All is needed now is to insert import.sql file in the resources folder.
I also found out that each insert statements must be in one line no matter how long it is, otherwise it won't be loaded.
Finally a simple test class:
#ContextConfiguration(classes = { JUnitConfig.class })
#RunWith(SpringJUnit4ClassRunner.class)
public class ApartmentServiceTest extends AbstractServiceTest{
#Autowired
ApartmentService service;
#Test
public void getList() {
List<Apartment> list = service.getList();
System.out.println(list.toString());
assertEquals(5, list.size());
}
}

Hibernate package scan in JavaConfig

I'm trying to configure Spring and Hibernate without xml. Here's my SessionFactory bean. When I add annotated class to configuration - it works properly. I want to do it automatically, but adding a package to configuration doesnt helps for some reason, I get "Identificator is not mapped" error
#Bean
public SessionFactory sessionFactory(){
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.connection.driver_class",ds_driver);
hibernateProperties.put("hibernate.connection.url",ds_url);
hibernateProperties.put("hibernate.connection.username",ds_username);
hibernateProperties.put("hibernate.connection.password",ds_password);
hibernateProperties.put("hibernate.show_sql", false);
hibernateProperties.put("connection.pool_size", 1);
hibernateProperties.put("current_session_context_class", "thread");
hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
configuration.addPackage("app.entity"); // **doesnt work**
configuration.addAnnotatedClass(Identificator.class); // **works fine**
configuration.addProperties(hibernateProperties);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
The #addPackage() method reads the package-level metadata, and not the classes in the package. Unfortunately the Configuration class does not provide methods the achive what you want, you have to pass all classes to #addAnnotatedClass().
A possible (but not sure if recommendable) solution would be using another solution to find the required class descriptors, build a list from them, and then pass them in a loop to #addAnnotatedClass(). I am quite sure, that Spring has solutions for this.
public SessionFactory getSessionFactory() {
if (sessionFactory == null) {
Configuration configuration = new Configuration()
.configure(getMappedValue("Universal", "qb_hibernate"))
.setProperty("hibernate.connection.autocommit", "true")
.setProperty("connection.pool_size", "20000")
.setProperty("hibernate.dialect", getMappedValue("Universal", "dialect"))
.setProperty("hibernate.connection.driver_class", getMappedValue("Universal", "driver_class"))
.setProperty("hibernate.connection.url", getMappedValue("Universal", "url"))
.setProperty("hibernate.connection.username", getMappedValue("Universal", "userName"))
.setProperty("hibernate.connection.password", getMappedValue("Universal", "password"))
.setProperty("hibernate.show_sql", "false")
.setProperty("hibernate.current_session_context_class", "thread")
.setProperty("hibernate.query.factory_class", "org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory");
ServiceRegistry serviceRegistry
= new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
LocalSessionFactoryBuilder builder
= new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("zw.co.techno.xxxxx.model").buildSettings(serviceRegistry);
// builds a session factory from the service registry
// sessionFactory = configuration.buildSessionFactory(serviceRegistry);
sessionFactory = builder.buildSessionFactory();
}
return sessionFactory;
}

New to HSQLDB working with Spring Application with JavaConfig

I am New to HSQLDB and working with Spring Application with JavaConfig. I want my example to setup a in memory database(HSQLDB) and insert one row.
I think I have my stuff all in order but I don't know where to create the database and the tables.
Below is my main.app code
public class MainApp
{
private static final Logger LOGGER = getLogger(MainApp.class);
#Autowired
protected MessageService mService;
public static void main(String[] args)
{
ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
HelloWorld helloWorld = context.getBean(HelloWorld.class);
LOGGER.debug("Message from HelloWorld Bean: " + helloWorld.getMessage());
/**
* I removed the following line... we are now using log4j
*/
//System.out.println(helloWorld.getMessage());
helloWorld.setMessage("I am in Staten Island, New York");
/**
* I removed the following line... we are now using log4j
*/
//System.out.println(helloWorld.getMessage());
LOGGER.debug("Message from HelloWorld Bean: " + helloWorld.getMessage());
}
and here is my DatabaseConfig.class
public class DatabaseConfig
{
private static final Logger LOGGER = getLogger(DatabaseConfig.class);
#Autowired
Environment env;
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
#Bean
public SessionFactory sessionFactory()
{
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setHibernateProperties(getHibernateProperties());
factoryBean.setPackagesToScan(new String[]{"com.xxxx.model"});
try
{
factoryBean.afterPropertiesSet();
} catch (IOException e)
{
LOGGER.error(e.getMessage());
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return factoryBean.getObject();
}
#Bean
public Properties getHibernateProperties()
{
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.use_sql_comments", env.getProperty("hibernate.use_sql_comments"));
hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.setProperty("javax.persistence.validation.mode", env.getProperty("javax.persistence.validation.mode"));
//Audit History flags
hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", env.getProperty("org.hibernate.envers.store_data_at_delete"));
hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", env.getProperty("org.hibernate.envers.global_with_modified_flag"));
return hibernateProperties;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager()
{
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory());
htm.afterPropertiesSet();
return htm;
}
but I don't know where the database is create and how do I insert my table before my project runs?
You can download the source code at the following:
https://github.com/JohnathanMarkSmith/HelloSpringJavaBasedJavaConfig/issues/1
This has been asked before, take a look at Startup script to create a schema in HSQLDB

Categories