my usecase is following:
When creating an application user (EntityManager.persist) I also have to create a DB user and grant him privileges (that's why I need hibernate nativeQuery).
I have a Spring #Transactional method which calls my DAO with both calls:
#Transactional
public Integer createCompany(Company company) throws Exception {
companyDao.createReportUser(ReportUser user);
...
}
My DAO method looks like this:
getEm().persist(companyReportsUser);
getEm().createNativeQuery("CREATE USER user1#localhost IDENTIFIED BY :password").setParameter("password", password).executeUpdate();
getEm().createNativeQuery("GRANT SELECT ON appdb.v_company TO user1#localhost").executeUpdate();
//several grants
Now, as soon as the first line with executeUpdate() is executed I can see persisted companyReportsUser in database along with DB user (user1#localhost).
All the nativeQueries are executed and immediately commited one by one. Since they are commited, they cannot be rolled back.
There is no auto-commit parameter set anywhere in my configuration so I assume it is 'false' as found in Hibernate docs.
I've tested #Transactional behavior without native queries and it works as supposed to (transaction is rolled back when I throw an RuntimeException and no data are inserted to database)
When debugging I've seen that persist operation delays execution when it is invoked in a running transaction.
Native query seems to create and execute a PreparedStatement immediately (at least I didn't find a queue of any kind.
I suppose that I might not get the interaction between hibernate native query and Spring transaction, but I've took my time reading Spring and Hibernate docs regarding transactions and native queries and did not found anything that would help me.
Maybe there is a better way to create a database user and grant privileges than native queries (although I didn't find any)
Below is my application config:
applicationContext.xml
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory">
<ref local="entityManagerFactory" />
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="domainPU" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.user.name}" />
<property name="password" value="${db.user.password}" />
<property name="validationQuery" value="select 1 as dbcp_connection_test" />
<property name="testOnBorrow" value="true" />
</bean>
persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="domainPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.domain.Entity1</class>
....
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.jdbc.batch_size" value="100"></property>
<property name="hibernate.order_inserts" value="true"></property>
<property name="hibernate.order_updates" value="true"></property>
<property name="hibernate.c3p0.min_size" value="5"></property>
<property name="hibernate.c3p0.max_size" value="30"></property>
<property name="hibernate.c3p0.timeout" value="300"></property>
<property name="hibernate.c3p0.max_statements" value="100"></property>
<property name="hibernate.c3p0.idle_test_period" value="${hibernate.c3p0.idle_test_period}"></property>
</properties>
</persistence-unit>
Libraries used:
Hibernate 4.1.6.FINAL
Spring 3.2.2.RELEASE
mysql-connector-java-5.1.21
MySQL 5.5
After digging deeper into how transactions work in MySQL I found an answer:
Problem was in the specific statements inside the native sql query.
From MySQL documentation:
13.3.3 Statements That Cause an Implicit Commit
Data definition language (DDL) statements that define or modify database objects (...CREATE TABLE, DROP DATABASE...)
Statements that implicitly use or modify tables in the mysql database (CREATE USER, DROP USER, and RENAME USER..., GRANT, REVOKE, ...)
...
More details here:
http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html
I've decided to split that action into two parts:
ordinary hibernate statements (inside a transaction),
native query statements
and supply user with a tool/action to reinvoke the second part in case when something goes wrong.
Other solution would be migrating to some other RDBMS that supports transactions around DDL operations.
Related
I have created a project and it worked fine with MySQL.
I need to use SQL Server instead of MySQL, the exception bellow is displayed:
com.sun.faces.mgbean.ManagedBeanCreationException: An error occurred
performing resource injection on managed bean ManageUserBean
Knowing that I made some changes on the file spring.xml like the following, could you please tell me what's missing?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeDAO" class="com.journaldev.spring.jdbc.dao.EmployeeDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="employeeDAOJDBCTemplate" class="com.journaldev.spring.jdbc.dao.EmployeeDAOJDBCTemplateImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://localhost:1433;database=springDBA"/>
<property name="username" value="hello" />
<property name="password" value="world" />
</bean>
</beans>
Any Reply is appreciated.Thanks in advance.
After giving more details about my problem by this thread Incorrect syntax near the keyword 'table' and could not extract ResultSet.
I found the solution: I have to avoid calling an entity like 'User' on SQL-Server while it's considered like a reserved keyword on this database.
There is no error caused by the configuration below. However it is not taken efect in Json converter. I am using MethodInvokingBean instead of MethodInvokingFactoryBean because I read that the second one give me a new instance and I am interested in changing the current instance used by RestTemplate. Anyway, I tried the factory one and it doesn't take effect as well.
Honestly, after some weeks searching for, I am wondering if it is really possible to change the default configuration of MapperObject when it is used by RestTemplate. The default configuration is to ignore the nanoseconds and I am really asking myself how someone else has been using RestTemplate when there is the requirement of nanoseconds. I can fix this by changing from sql.TimeStamp to String but it doesn't seem the best approach. If someone else has faced similiar issue and has been able to use sql.TimeStamp with nanoseconds either by changing Jackson Mapper configuration or other way I will appreciate a lot some tips.
//everything start here
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
_myCllientOfRestService = context.getBean(MyCllientOfRestService.class, request, response);
_myCllientOfRestService.myMethod();
// myCllientOfRestService
Public void myMethod(){
//it is not returning the nano seconds and I am sure the nano seconds is available in rest service return side. MyReturnType object has the sql.TimeStamp variable filled in with nanoseconds in the rest service side but it is lost in client side
_myReturnType = restTemplate.postForObject(urlRestService, myParameters,MyReturnType.class);
}
//applicationContext.xml
<bean id="myCllientOfRestService" class="com.someCompany.mhe.log.handler.MyCllientOfRestService" scope="prototype" lazy-init="true">
<property name="restTemplate" ref="restTemplate2" />
</bean>
<bean id="myMIB"
class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper" />
<property name="targetMethod" value="configure" />
<property name="arguments">
<list>
<value type="com.fasterxml.jackson.databind.SerializationFeature">WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS</value>
<value>true</value>
</list>
</property>
</bean>
<bean id="myMIB2"
class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper" />
<property name="targetMethod" value="configure" />
<property name="arguments">
<list>
<value type="com.fasterxml.jackson.databind.DeserializationFeature">READ_DATE_TIMESTAMPS_AS_NANOSECONDS</value>
<value>true</value>
</list>
</property>
</bean>
<bean id="restTemplate2" class="org.springframework.web.client.RestTemplate" >
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
I am currently working on a system that has been around for a number of years and has gone through a fair amount of transformation. (GWT\Spring\Hibernate). I recently had to merge two entities as part of a change. When I looked at the actual sql tables I noticed that there were a number of orphaned columns that were actually not mapped to the entities and could effectively be dropped. I was wondering if there are any tools out there that would help us to identify and strip out outdated columns which are not actually being linked to our entities.
If you´re Using Spring and hibernate you can use autodetection to create/update database though the entities attributes that you have in your entity.
your hibernate.hbm2ddl.auto setting should be defining that the database is created (options are validate, create, update or create-drop)
Here the Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<persistence-unit name="NewPersistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/Icarus"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hbm2ddl.auto" value="create"/>
</properties>
<class>net.interaxia.icarus.data.models.ServerNode</class>
</persistence-unit>
I am using jpa and spring, and got an error with below code;
#PersistenceContext protected EntityManager entityManager;
entityManager.createQuery("select c from Theatre c");
And take this error.
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Theatre is
not mapped [select c from Theatre c]
In order to solve the problem i use below, but i need any other solution because the project should not know the class and i want to make dynamic programming
<class>Theatre </class> in "PersistenceUnit"
I appreciate any idea
Best Regards
You can use the attribute packagesToScan in your LocalContainerEntityManagerFactoryBean definition (available in Spring 3.1). If you use this approach you don't need to define the persistence.xml anymore. The configuration should be something like this:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.sergialmar.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
I created a basic Spring MVC / JPA / Hibernate app. I am trying to save a UserProfile entity to test if I can actualy persist it, but nothing gets saved and no exception is thrown either.
In the controller method I create a simple UserProfile (which is an #Entity) and I am sending that to a service method. The UserProfileServiceImpl class is annotated with #Service and the addUserProfile(UserProfile profile) method is annotated with #Transactional.
In the service method, all I do is call a DAO method (class annotated with #Repository). In the DAO method all I do is call entityManager.persist(object), with object being the user profile object.
Nothing gets written to the server log and the log level is at INFO.
Nothing appears in the Mysql query log (and I know the query log works)
The entityManager gets properly injected.
The datasource is properly initiated, because when I enter faulty credentials I get SQLExceptions.
I hope you can tell me what's wrong. I'll post some of my code and config files below.
The service method:
// The service method gets called from the controller.
// Its class is annotated with #Service
#Transactional(readOnly = false)
public void addUserProfile(UserProfile userProfile) {
userProfileDao.save(userProfile);
}
The Dao method:
// The save(T object) method is in the GenericDaoJpa class, which is the superclass
// of the UserProfileDaoJPA class that is referenced from the service.
// I have established that the entityManager is there and the object is a
// UserProfile. The #Repository annotation is on the child class UserProfileDaoJpa.
public void save(T object) {
entityManager.persist(object);
}
Main application-context.xml
<context:property-placeholder location="classpath*:**/*.properties"/>
<import resource="spring-jpa.xml"/>
The application-context-web.xml file
<mvc:annotation-driven />
<context:component-scan base-package="nl.codebasesoftware.produx" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
spring-jpa.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${db.driverClassName}"
p:url="${db.url}" p:username="${db.username}" p:password="${db.password}"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
persistence.xml
<persistence-unit name="mysqlPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
<!-- Needed to properly process #PersistenceContext -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
Somehow no SQL is sent to Mysql with this setup, but no exception is thrown either, so I have no idea what's going on. Hope you can help :)
i think you are missing transaction propagation at service. marking readonly=false just set session to auto flush. but setting up proper transaction propogation will make sure start of trnasaction and commit/rollback.
after removing mode="aspectj" it has started working because i think because of as per spring doc
The default mode "proxy" will process annotated beans to be proxied
using Spring's AOP framework (following proxy semantics, as discussed
above, applying to method calls coming in through the proxy only). The
alternative mode "aspectj" will instead weave the affected classes
with Spring's AspectJ transaction aspect (modifying the target class
byte code in order to apply to any kind of method call). AspectJ
weaving requires spring-aspects.jar on the classpath as well as
load-time weaving (or compile-time weaving) enabled. (See the section
entitled Section 6.8.4.5, “Spring configuration” for details on how to
set up load-time weaving.)
and probably you have not configured load time weaving
Ok, I got it. First I thought I found the answer here
Declarative transactions (#Transactional) doesn't work with #Repository in Spring
But after some more testing I found it was not the location of
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
but its contents.
After removing the mode="aspectj" attribute it started working! If anyone would like to comment why that is, please do.
Let me share my full setup with you. This is for Spring 3.1 with Hibernate 4. NOTE: for 'brevity' I only posted the contents of the configuration files, and omitted the outer tags <beans> and <persistence> and the namespace declarations. I removed spring-jpa.xml altogether and moved its contents into application-context.xml.
Contents of web.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<display-name>My Spring MVC web application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:**/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>produxDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:**/application-context-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>produxDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Contents of application-context.xml:
<!-- main setup -->
<context:property-placeholder location="classpath*:**/*.properties"/>
<context:annotation-config/>
<context:component-scan base-package="nl.codebasesoftware.produx.domain" />
<context:component-scan base-package="nl.codebasesoftware.produx.service" />
<context:component-scan base-package="nl.codebasesoftware.produx.dao" />
<!-- Data and JPA setup -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${db.driverClassName}"
p:url="${db.url}" p:username="${db.username}" p:password="${db.password}"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
Contents of application-context-web.xml:
<mvc:annotation-driven />
<context:component-scan base-package="nl.codebasesoftware.produx.controller" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
Contents of webapps/META-INF/persistence.xml
<persistence-unit name="mysqlPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<!-- <property name="hibernate.hbm2ddl.auto" value="create-drop"/> -->
</properties>
</persistence-unit>
<!-- Needed to properly process #PersistenceContext which injects the entity manager -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
Contents of environment.properties:
db.url=jdbc:mysql://localhost:3306/yourDatabaseName
db.driverClassName=com.mysql.jdbc.Driver
db.username=yourUsername
db.password=yourPassword