How to inject EntityManager into Spring Integration bean? - java

Edit: I've update the post to reflect the questions in the comments below, but in summary, all of them are done but issue still exists
I'm trying to find a way to inject a Spring-managed EntityManager into my bean that handles the database update portion of a Spring Integration workflow.
For some reason, I keep getting a NullPointerException when trying to refer to the EM instance.
My setup is as follows:
#Component
public class BranchDeploymentUpdater {
#PersistenceContext(unitName = "MyPU")
private EntityManager em;
public File handleUpdate(File input) {
.....
String query = "some query";
TypedQuery<MyClass> typedQuery = em.CreateQuery(query, MyClass.class);
.....
}
}
My persistence.xml has been configured as follows:
<persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.2.169:3306/MYDB" />
<property name="javax.persistence.jdbc.user" value="user" />
<property name="javax.persistence.jdbc.password" value="P#ssw0rd" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<!-- Connection Pooling -->
<property name="hibernate.connection.provider_class"
value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
<property name="hibernate.c3p0.max_size" value="100" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.acquire_increment" value="5" />
<property name="hibernate.c3p0.idle_test_period" value="500" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.timeout" value="10000" />
</properties>
</persistence-unit>
My component scan is declared at the springapp-servlet.xml document as follows and the class using EM is confirmed to be in the package declared:
<context:component-scan base-package="com.myapp.webapp.controller, com.myapp.integration" />
The NPE would occur at the em.CreateQuerystatement.
In this same project, I also have a MVC webapp which I'm injecting the EM into the controller class using the exact same way and it works.
Can anybody give any pointers to where I may be getting it wrong?
Currently, I'm working around this by instantiating a new EM every time the bean gets invoked but this is causing an out-of-connection error with MySQL if I pump in too many transactions.
Please note that I'm not using Spring Integration's DB adapters as I already have the JPA code for handling the database layer and would like to keep that layer.
Thanks
Wong

Thanks for all the comments. I was able to finally get it working by injecting an EntityManagerFactory instead, following the example provided in http://docs.spring.io/spring/docs/2.5.x/reference/orm.html#orm-jpa-tx
I think one key thing that I had left out previously is the line:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
This really takes a load of my mind as I was having a helluva time with race conditions in the DB instantiating my own EMs.

Related

Hibernate Setup on Webservice Intellij

I am trying to setup a REST API using Hibernate as my ORM Mapper. As IDE I am using IntelliJ. The project folder structure looks like this:
projectstructure
I setup the project with Glassfish like this instructions
The REST-API part works fine so I won't bother pasting all of that in here. To test the Hibernate functionality I wrote this class:
public class ArtistRepository {
public static void testHibernate(){
EntityManagerFactory factory = Persistence.createEntityManagerFactory("emf");
EntityManager manager = factory.createEntityManager();
Artist green = new Artist();
green.setName("TEST");
manager.getTransaction().begin();
manager.persist(green);
manager.getTransaction().commit();
}
}
The persistence.xml looks like this:
<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="emf">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/database?autoReconnect=true" />
<property name="hibernate.connection.username" value="*****" />
<property name="hibernate.connection.password" value="*****" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="10" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="300" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</properties>
</persistence-unit>
</persistence>
When I request a REST resource using that method I get the following error:
<p>
<b>exception</b>
<pre>javax.servlet.ServletException: javax.persistence.PersistenceException: No Persistence provider for EntityManager named emf</pre>
</p>
<p>
<b>root cause</b>
<pre>javax.persistence.PersistenceException: No Persistence provider for EntityManager named emf</pre>
</p>
<p>
<b>note</b>
<u>The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 5.0 logs.</u>
</p>
So obviousley the persistence.xml is in the wrong directory, but I have no clue where to put it.

UnknownServiceException from hibernate [duplicate]

This question already has an answer here:
UnknownServiceException: Unknown service requested (Hibernate/Spring)
(1 answer)
Closed 7 years ago.
I'm using Spring 4 to set up my stuff that I'll need for using Hibernate 4. I have a SessionFactory autowired into my DAO layer. When I call sessionFactory.getCurrentSession() I get the error:
Exception in thread "MyImporterThread" org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.engine.jdbc.connections.spi.ConnectionProvider]
I've looked at many search results from Google (including a bunch from StackOverflow) on this exception, however none of them has struck me as the solution to my issue.
Here's my configuration:
spring-beans.xml:
<context:property-placeholder location="file:spring.properties" />
<context:component-scan base-package="com.company.scraping" />
<!-- Data Source -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver.class}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Session Factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.company.scraping" />
<property name="configLocation">
<value>file:scraping.db.hibernate.cfg.xml</value>
</property>
</bean>
<!-- Transaction Stuff -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- beans that are transactional or autowired -->
<bean id="scrapingDao" class="com.company.scraping.dao.ReportsScrapingDaoImpl" />
<bean id="scrapingService" class="com.company.scraping.service.ReportsScrapingServiceImpl" />
spring.properties:
jdbc.driver.class=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:#server:1521:testdb01
jdbc.user=user
jdbc.password=password
scraping.db.hibernate.cfg.xml:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:oracle:thin:#server:1521:testdb01</property>
<property name="connection.username">user</property>
<property name="connection.password">password</property>
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.autocommit">true</property>
<property name="hibernate.generate_statistics">false</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="hibernate.show_sql">false</property>
</session-factory>
</hibernate-configuration>
Since this is not a web application, I use ApplicationContext context = new FileSystemXmlApplicationContext(args[0]) to initialize Spring.
My service class is autowired (not shown in the config because I have to type all this out), and contains an autowired instance of the DAO. This is what the DAO looks like:
#org.springframework.stereotype.Repository
#org.springframework.transaction.annotation.Transactional
public class ReportsScrapingDaoImpl implements ReportsScrapingDao
{
#Autowired
#Qualifier("sessionFactory")
private SessionFactory sessionFactory;
#Override
#Transaction(readOnly = true)
public List<Stuff> getAll()
{
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Stuff.class);
... (more code)
}
}
The code bombs out when sessionFactory.getCurrentSession() is called. I've tried using sessionFactory.openSession() as well, but it gave the same results. I'm not sure what's going on here.
I did a last-ditch search and this turned up. Eclipse outputs a compiler warning, complaining that there may be a resource leak because the ApplicationContext is never closed. I added a line at the very end of my main method (after all the Threads had been started) to close the ApplicationContext. Once I got rid of the line that closes the ApplicationContext, the problem went away.
Moral of the story is that your ApplicationContext should not be closed until you no longer need anything from it--so you should probably never close it.

Best way to create schema in embedded HSQL database

I'm currently using the following setup to create a schema in an embedded database before running my tests against it
In my application context
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:createSchema.sql" />
</jdbc:embedded-database>
createSchema.sql
create schema ST_TEST AUTHORIZATION DBA;
hibernate properties
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.default_schema" value="ST_TEST"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
</properties>
My question is is this the best way to do this. Or can i use a different schema name in my properties? or set the schema name in the jdbc:embedded-database element
By default HSQL creates a schema called PUBLIC. source: HSQL documentation
Seeing as the schema name is never seen in the tests (named queries/entity manager to do the interactions) you can change the hibernate properties to use this PUBLIC schema
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.default_schema" value="PUBLIC"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
</properties>
OR
just leave out the default_schema from the properties list and it uses PUBLIC anyway
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
</properties>
You can use this code in your Base Testing class, and call it using #BeforeClass annotation (for Junit). I do it like this.
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
builder = builder.setType(EmbeddedDatabaseType.HSQL).addScript(
"createSchema.sql");
builder.setName("MyDatabase");
EmbeddedDatabase db = builder.build();

name attribute doesn't seem to work in Field

As I am trying to map Entity to tables using JPA (Hibernate implementation) I found something confusing
when i use annotation on getter, things are OK
#Column(name = "main_battery_voltage", precision = 2)
public float getMainBatteryVoltage() {
return mainBatteryVoltage;
}
but When I try the same thing on field, field name is used and attribute
#Column(name = "main_battery_voltage", precision = 2)
private float mainBatteryVoltage;
System ignores name attribute, runs with column name mainBatteryVoltage in DB and consequently failed task.
I am using MySQL and this is the persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="SolarPersistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.cs.solar.db.entity.User</class>
<class>com.cs.solar.db.entity.Lamp</class>
<class>com.cs.solar.db.entity.Project</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!--<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>-->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/SOLAR"/>
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="admin" />
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.max_fetch_depth" value="3"/>
</properties>
</persistence-unit>
<persistence-unit name="TestSolar" />
</persistence>
Although it works now, I am curious what cause this problem, thank
You can find a short explanation here:
Hibernate Annotation Placement Question
The point is:
"the access type used by Hibernate will be field or property. The EJB3 spec requires that you declare annotations on the element type that will be accessed, i.e. the getter method if you use property access, the field if you use field access. Mixing EJB3 annotations in both fields and methods should be avoided. Hibernate will guess the access type..."

Hibernate > CLOB > Oracle :(

I am trying to write to an Oracle clob field a value over 4000 characters. This seams to be a common issue but non of the solutions seem to work. So I pray for help from here.
Down and dirty info:
Using Oracle 9.2.0.8.0
Hibernate3 implementing pojo's with annotations
Tomcat 6.0.16
Oracle 10.2.x drivers
C3P0 connction pool provider
In my persistence.xml I have:
<persistence-unit name="DWEB" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.connection.password" value="###" />
<property name="hibernate.connection.username" value="###" />
<property name="hibernate.default_schema" value="schema" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test_period" value="3000" />
<property name="show_sql" value="true" />
<property name="format_sql" value="true" />
<property name="use_sql_comments" value="true" />
<property name="SetBigStringTryClob" value="true"/>
<property name="hibernate.jdbc.batch_size" value="0"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:#server.ss.com:1521:DDD"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
</properties>
</persistence-unit>
The getter and setter looks like:
#Lob
#Column(name="COMMENT_DOC")
public String getDocument(){
return get("Document");
}
public void setDocument(String s){
put("Document",s);
}
The exception I am getting is:
SEVERE: Servlet.service() for servlet SW threw exception
java.sql.SQLException: Io exception: Software caused connection abort: socket write error
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:334)
at oracle.jdbc.ttc7.TTC7Protocol.handleIOException(TTC7Protocol.java:3678)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1999)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1144)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2152)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2035)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2876)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:609)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2275)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2688)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:304)
at org.sw.website.actions.content.AddComment.performAction(AddComment.java:60)
...
If I need to give more info pleas ask. Everything works until the dreaded limit is exceeded.
Thanks to non sequitor for all the help. I have this working and figure I will put all the pieces here for future reference. Regardless of all the claims about upgrading the drivers and everything would work, non of that worked for me. In the end I had to implement a 'org.hibernate.usertype.UserType' I named it the same as all the examples on the web StringClobType. Save for some imports I used the example from Using Clobs/Blobs with Oracle and Hibernate. As far as I am concerned ignore the "beware" claim.
There was one change I had to make to get merges to work. Some of the methods were not implemented in the provided code sample. Eclipse fixed it for me by stubbing them out. Cool, but the replace method needs to be actually implemented or all merges will overwrite the data with a null. Here is my implementation:
public Object replace(Object newValue, Object existingValue, Object arg2)throws HibernateException {
return newValue;
}
I will not duplicate the class implementation here go to the above link to see it. I used the code in the third gray box. Then at the top of the pojo class I wanted to use it in I added the following after the imports
...
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDefs;
import org.hibernate.annotations.TypeDef;
#TypeDefs({
#TypeDef(
name="clob",
typeClass = foo.StringClobType.class
)
})
#Entity
#Table(name="EA_COMMENTS")
public class Comment extends SWDataObject implements JSONString, Serializable {
...
}
Then to use the new UserType I added the annotation to my getter:
#Type(type="clob")
#Column(name="COMMENT_DOC")
public String getDocument(){
return get("Document");
}
I did not need the #Lob annotation.
In my persistence.xml the persistence-unit declaration ended looking like:
<persistence-unit name="###" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.connection.password" value="###" />
<property name="hibernate.connection.username" value="###" />
<property name="hibernate.connection.url" value="jdbc:oracle:thin:#server.something.com:1521:###"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.default_schema" value="###" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="100" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />
<property name="hibernate.c3p0.idle_test period" value="3000" />
<property name="hibernate.c3p0.idle_connection_test_period" value="300" />
<property name="show_sql" value="false" />
<property name="format_sql" value="false" />
<property name="use_sql_comments" value="false" />
<property name="hibernate.jdbc.batch_size" value="0"/>
</properties>
</persistence-unit>
The SetBigStringTryClob never worked for me and was not needed for this final implementation.
My lesson learned is in the end it is probably better to join then to fight. It would of saved me three days.
I think your problem might be that you are using Oracle 9i but Hibernate dialect is 10g. Make sure your driver,db version and dialect are all in sync because there is a 9i dialect as well org.hibernate.dialect.Oracle9iDialect
It should be:
<property name="hibernate.connection.SetBigStringTryClob">true</property>
<property name="hibernate.jdbc.batch_size">0</property>
And not:
<property name="SetBigStringTryClob">true</property>
And use the right dialect for your database (org.hibernate.dialect.Oracle9iDialect).
Also make sure that you are using the latest Oracle 10g Release 2 thin driver (10.2.0.4) or later.
We had a similar problem in the past, with LONG columns instead of CLOBs. The problem was the JDBC driver, the one we use now and works fine is

Categories