How can I get Hibernate (using JPA) to create MySQL InnoDB tables (instead of MyISAM)? I have found solutions that will work when using Hibernate to generate an SQL file to create the tables, but nothing that works "on the fly".
Can't you specify the Hibernate dialect and use
hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
Edit
From MySQL version > 5.1 this should be
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
to avoid running into this issue Using "TYPE = InnoDB" in MySQL throws exception
Go to this link:
mysql-dialect-refactoring
It clearly says :
Traditionally, MySQL used the non-transactional MyISAM storage engine, and this is the default storage engine for all Dialects that are older than MySQL55Dialect. From MySQL55Dialect onwards, the InnoDB storage engine is used by default.
Put the following in your application.properties (or in your config):
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect
Notice 55 in above. - not just 5.
And you can see it in the console too:
Hibernate: create table users_events (user_id bigint not null, event_id bigint not null) engine=InnoDB
Hibernate: create table users_roles (user_id bigint not null, role_id bigint not null) engine=InnoDB
Hope it helps.
Are you specifying the dialect setting in your hibernate configuration? If not, then Hibernate will attempt to auto-detect the database dialect, and will choose the safest MySQL dialec, which is MySQL 4 MyISAM.
You can give it a specific dialect, by adding this to your hibernate properties:
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
As of Hibernate 5.2.8, the Mysql*InnoDBDialect classes used by the other answers are deprecated. The new solution is to set the following property:
hibernate.dialect.storage_engine = innodb
See http://in.relation.to/2017/02/20/mysql-dialect-refactoring/ for more details.
With spring-boot 2.0.0M7 following did work for me (mysqld 5.7)
spring.jpa.hibernate.use-new-id-generator-mappings: true
spring.jpa.database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
For newer versions, you can use
hibernate.dialect.storage_engine=innodb
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Other options for hibernate.dialect can be MySQL55Dialect or MySQL57Dialect
Just in case of Spring Boot 2
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.dialect.storage_engine=innodb
If you are using Hibernate 5.2.8+, try using the MySQL55Dialect, which according to the link provided by Jules, sets innoDB by default as the storage engine.
I was trying to use hibernate4 with Spring 3.2 and wrap it in JPA.
I ended up creating my own class.... copied the entire contents of the org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter into my own class file and modifying the output of one subroutine to change the MySQL Dialect to MySQL5InnoDBDialect. I guess I could have extended the class.
Anyway...
Modified as:
package com.imk.dao.hibernate;
public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
[ snip snip snip --- use the original code ]
protected Class determineDatabaseDialectClass(Database database) {
switch (database) {
case DB2:
return DB2Dialect.class;
case DERBY:
return DerbyDialect.class;
case H2:
return H2Dialect.class;
case HSQL:
return HSQLDialect.class;
case INFORMIX:
return InformixDialect.class;
case MYSQL:
return MySQL5InnoDBDialect.class;
case ORACLE:
return Oracle9iDialect.class;
case POSTGRESQL:
return PostgreSQLDialect.class;
case SQL_SERVER:
return SQLServerDialect.class;
case SYBASE:
return SybaseDialect.class;
default:
return null;
}
}
}
You might think this is a 'hack', but, I suppose it will work. In the Spring context config, I added:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="MosJPA" />
<property name="jpaVendorAdapter">
<bean class="com.imk.dao.hibernate.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
Then my class is used for the "database" adapter bean. (no component scanning, my classes are listed in META-INF/persistence.xml (the default location))
in case you choose application.yml
spring:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
Here are the properties from my persistence.xml that fixed it. You can use those in Spring or directly in Hibernate, whatever your dev stack:
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.dialect.storage_engine" value="innodb"/>
Oh, boy....sorry guys... more Googling gives another search result:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="MosJPA" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
</bean>
So, you don't need to extend or change a class...should have read the original source code of the original HibernateJpaVendorAdapter a bit further before I answered. That clued me into the "databasePlatform" property...
Related
I'm building Spring+Hibernate Java Application. I wanted to add some integration tests, done in in-memory database.
So, my normal database is Postgresql, and I populate it using .sql scripts run with flyway plugin. ID fields are set to BIGSERIAL. I wanted to use in-memory database, to resemble my original database, and then try to test some classes with it. I managed to configure preety much everything(I hope so), but when I run the test class itself I get error with CREATE TABLE scripts:
Caused by: org.hsqldb.HsqlException: type not found or user lacks privilege: BIGSERIAL
I found out that I should configure HSQLDB, to enable Postgresql compability.
Use SET DATABASE SQL SYNTAX PGS TRUE or the equivalent URL property sql.syntax_pgs=true to enable the PostgreSQL's non-standard features.
I use persistence.xml to define normal and test persistence unit. This is fragment responsible for defining test persistence unit:
<persistence-unit name="testJPA">
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:butterfly;sql.syntax_pgs=true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
Then I use configuration class for tests:
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = {"core.utilities"} )
#EnableTransactionManagement
public class TestsInitializer {
#Bean
public LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("testJPA");
return factoryBean;
}
}
And in testclass itself:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestsInitializer.class }/*, loader = AnnotationConfigContextLoader.class*/)
#Transactional
public class GenreBATest {
#Autowired
private GenreBA genreBA;
#Test
public void testFindAllAccounts() {
//whatever
}
}
I added the required property at the end of URL, found examples of this exact property across the internet, but it does not resolve my problem.
I'm still getting: Message : type not found or user lacks privilege: BIGSERIAL
What am I doing wrong?
Ok, I found out that scripts were run by flyway ignoring all possible syntax commands from persistence.xml. And flyway run with HSQLDB because I used #EnableAutoConfiguration in test configuration class without excludes :) I learned through hard way that Spring Boot already configures Hibernate to create schema based on entities for an in-memory database. So I don't need to use database scripts at all, and they were run by accident.
I'm working on a Java Spring+Hibernate project and we have a Junit setup in order to unit-test our code.
The problem I face right now is that I don't understand why Hibernate (with Spring-boot) creates the database schema 2 times before the tests actually run. The sequence is as follows:
Alter tables drop all foreign keys
Drop tables if exist
Create tables
Alter tables add constraints (like FK)
Alter tables drop all foreign keys
Drop tables if exist
Create tables
Alter tables add constraints
Execute all tests
My questions is, if to be more specific: Why points 3-6 including are executed?
Why simply not to execute 1,2,7,8,9. Why do I want this? Because it takes precious time and I don't understand why do I need this.
Below is my persistence configuration:
<persistence-unit name="localContainerEntityForTest">
<description>Spring JPA LocalContainerEntityManagerFactoryBean</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.implicit_naming_strategy" value="legacy-jpa"/>
<property name = "hibernate.show_sql" value = "true" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/myApp?createDatabaseIfNotExist=true"/>
<property name="javax.persistence.jdbc.user" value="hibernate"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
Also, below are the annotations I use for every unit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = JPAConfigurationTestEnviorement.class)
#WebAppConfiguration
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
I am fairly familiar with Hibernate, but less so with Spring Boot. My guess is that Hibernate is directly responsible for one create-alter-drop cycle and Spring Boot is responsible for the other one. If you are morally opposed to your current setup, then you can try updating your Hibernate XML to the following:
<property name="hibernate.hbm2ddl.auto" value="validate"/>
By choosing the validate option, you are instructing Hibernate to only validate your existing schema and to not create or drop any tables. The trick here is that I'm not sure which of the two cycles you want to remove (nor did you tell us).
Problem found, after starting the process to upgrade the spring boot version and I observed some weird code that was not telling me anything before. The reason was the creation of EntityManagerFactory before defining the LocalContainerEntityManagerBean:
#Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() {
Persistence.createEntityManagerFactory("localContainerEntityForTest");
LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean();
lcemfb.setPersistenceUnitName("localContainerEntityForTest");
lcemfb.setPackagesToScan("com.mybasepackage");
lcemfb.setPersistenceXmlLocation("classpath:/META-INF/persistence.xml");
return lcemfb;
}
After removing the line:
Persistence.createEntityManagerFactory("localContainerEntityForTest");
the cycle disappeared.
I am trying to configure spring-data-neo4j 3.0.1.RELEASE to work with a legacy (2.3.5.RELEASE) database. Therefore, I followed the documentation in order to configure the INDEXED TypeRepresentationStrategy. However, it does not seem to have any effect as I still see the same type of Cypher queries in the log:
Executing cypher query: START `abc`=node:__types__(className="abc") RETURN `abc`
I would have expected to instead query for node.__type__ = "x.y.z.abc". Here is the xml config:
<context:annotation-config/>
<bean id="typeRepresentationStrategyFactory" class="org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory">
<constructor-arg ref="graphDatabase"/>
<constructor-arg value="Indexed"/>
</bean>
<neo4j:config storeDirectory="${app.neo4j.location}" base-package="x.y.z.*" />
<neo4j:repositories base-package="x.y.z.*" />
Seems like the type representation strategy configuration is ignored.
I have created a database named 'movie_db', set default schema to APP.
Then created a sample table named 'USERS'.
My connection to DB is as follows:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="url" value="jdbc:derby://localhost:1527/movie_db"/>
<property name="username" value="root"/>
<property name="password" value="pass"/>
</bean>
Now I want to write some tests and try to execute the following query:
SELECT * FROM USERS;
What I get:
java.sql.SQLSyntaxErrorException: Table/View 'USERS' does not exist.
When I specify exactly the schema I'm using:
SELECT * FROM APP.USERS
everything works fine.
How can I omit schema name in my query?
UPDATE:
Like Bryan said, I've created a user with the name of my default schema and authorize with this login. This is the most simple way to omit schema name in the query. But still if I want to use multiple schemas the only way is to set schema explicitly.
There are basically two ways to control the default schema name:
Issue the SET SCHEMA statement after you have connected to the database.
Login as the user with the same name as the schema you wish to use.
If you haven't issued a SET SCHEMA statement, then Derby will use your username as the schema name.
So if you login as user "APP", and don't issue a SET SCHEMA statement, then your schema name will be APP.
I read the "Spring Security 3 database authentication with Hibernate"! But I don't know how I should implementate it into my project!
In which document I have to set the password/username/drivers/url for the database?
I have different column titles like OPERATOR_ID/USR_ID/PASSWORD
OPERATOR_ID should be the login name, USR_ID the role and the password for the login
Please, maybe you could post an example which implements my questions? Maybe for a checkout or a *.war file?
I dont think there is any configuration as such for doing this. You have to implement the UserDetailsService which has only one method loadUserByUsername to load the user and you have to implement the same to load your user information from your database using hibernate.
See here
You would need to configure a JDBCDaoImpl bean which takes a Datasource as a parameter. How you retrieve the Datasource is up to you, you may grab it from the app server or use something like Spring's DriverManagerDatasource Here is some (pseudo) config
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>your.driver.classname</value></property>
<property name="url"><value>yourDatabaseUrl</value></property>
<property name="username"><value>yourUsername</value></property>
<property name="password"><value>yourPassword</value></property>
</bean>
<bean id="dao" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="DataSource" ref="datasource" />
...
</bean>