I am doing unit testing and I expect that all data committed to the MySQL database will be rolled back... but this isn't the case. The data is being committed, even though my log was showing that the rollback was happening. I've been wrestling with this for a couple days so my setup has changed quite a bit, here's my current setup.
LoginDAOTest.java:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"file:web/WEB-INF/applicationContext-test.xml", "file:web/WEB-INF/dispatcher-servlet-test.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class UserServiceTest {
private UserService userService;
#Test
public void should_return_true_when_user_is_logged_in ()
throws Exception
{
String[] usernames = {"a","b","c","d"};
for (String username : usernames)
{
userService.logUserIn(username);
assertThat(userService.isUserLoggedIn(username), is(equalTo(true)));
}
}
ApplicationContext-Text.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/******"/>
<property name="username" value="*****"/>
<property name="password" value="*****"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="userService" class="Service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
<bean id="userDAO" class="DAO.UserDAO">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>/himapping/User.hbm.xml</value>
<value>/himapping/setup.hbm.xml</value>
<value>/himapping/UserHistory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
</beans>
I have been reading about the issue, and I've already checked to ensure that the MySQL database tables are setup to use InnoDB. Also I have been able to successfully implement rolling back of transactions outside of my testing suite. So this must be some sort of incorrect setup on my part.
Any help would be greatly appreciated :)
The problem turned out to be that the connection was auto-committing BEFORE the transaction could be rolled back. I had to change my dataSource bean to include a defaultAutoCommit property:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="Ecosim07"/>
<property name="defaultAutoCommit" value="false" />
</bean>
For me defaultAutoCommit and #Transactional didn't help. I had to change db type to InnoDB
Another way to fix your problem:
Instead of using:
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
, which creates a MyISAM table by default, hence not supporting transactions
Try using
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
, which creates InnoDB tables, and thus supports transactions.
This must be used
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#TestExecutionListeners({ TransactionalTestExecutionListener.class })
#Transactional
TransactionalTestExecutionListener contains isRollback() which rollbacks the
transaction after the test method.
I hope I am right and that this is a simple one. You are missing the #Transactional annotation on your test class. This means that the test method itself isn't run in a transaction and thus there is nothing to roll back. Hope this helps.
Related
![out put from cf logs app-name --recent
]1I have developed a spring/hibernate-MySQL in backend based application. I have tested the application in the local machine successfully. But when I uploaded the app into IBM bluemix, there is exceptions everywhere when I am accessing service-->Dao methods. It says org.hibernate.exception.SQLGrammarException stating the message like " SELECT command denied to user 'username#75.126.83.16'. Interstingly, when I put a normal JSP without Hibernate/spring Dao but by using the same connection string, that works.
Here is the spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="pojos" />
<bean id="adminService" class="pojos.AdminService">
<property name="adminDao" ref="adminDao" />
</bean>
.. Other Service class bean's info....
<bean id="adminDao" class="pojos.AdminDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="fieldOfficerDao" class="pojos.FieldOfficerDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="questionMasterDao" class="pojos.QuestionMasterDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
.. Other Dao class bean's info....
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>pojos/Admin.hbm.xml </value>
... And other hbm files...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://192.155.247.251:3307/<DB-Name>" />
<property name="username" value="<DB-User-Name>" />
<property name="password" value="<DB-Password>" />
</bean>
<bean id="dbUtil"
class="pojos.DbUtil"
init-method="initialize">
<property name="dataSource" ref="dataSource" />
</bean>
I just removed catalog attribute from class tag of each .hbm.xml files. That attribute is optional and it contains schema name of mysQL.
Previously it was
<class name="pojos.Admin" table="admin" catalog="merca">
But Now It is
<class name="pojos.Admin" table="admin">
I am trying application in tomcat 8.0, but I get the error
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: No suitable driver found for jdbc:mysql://ip:3306/DURGA_DEV?characterEncoding=UTF-8
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:630) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:727) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:737) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:787) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]
I am using the
Tomcat 8.0.21
Spring 4.1.6
Mysql Conector : mysql-connector-java-5.1.27.jar
My context.xml file is given below.
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<bean id="datasourceProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:META-INF/config/datasource.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<bean id="batchUpdateDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</value>
</property>
<property name="url">
<value>${jdbc.components.url.DURGA}</value>
</property>
<property name="username">
<value>${jdbc.components.userName.DURGA}</value>
</property>
<property name="password">
<value>${jdbc.components.password.DURGA}</value>
</property>
</bean>
<bean id="batchJDBCTemplate" class="com.nri.durga.maf.batch.MafBatchJdbcTemplate">
<constructor-arg
type="org.springframework.jdbc.datasource.DriverManagerDataSource"
ref="batchUpdateDataSource" />
</bean>
<bean id="GLOBAL"
class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
p:URL="${jdbc.components.url.GLOBAL}"
p:user="${jdbc.components.userName.GLOBAL}"
p:password="${jdbc.components.password.GLOBAL}">
</bean>
<bean id="DURGA"
class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
p:URL="${jdbc.components.url.DURGA}"
p:user="${jdbc.components.userName.DURGA}"
p:password="${jdbc.components.password.DURGA}">
</bean>
<bean id="global-tm" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="global-em" />
<property name="dataSource" ref="GLOBAL" />
</bean>
<bean id="durga-tm" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="durga-em" />
<property name="dataSource" ref="DURGA" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="${jpa.hibernate.dialectClass}" />
</bean>
<bean id="global-em" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="com.nrift.finch.*.model, com.nrift.finch.*.domain"
p:dataSource-ref="GLOBAL"
p:jpaVendorAdapter-ref="jpaVendorAdapter" />
<bean id="durga-em" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="com.nri.durga.*.model, com.nri.durga.*.domain"
p:dataSource-ref="DURGA"
p:jpaVendorAdapter-ref="jpaVendorAdapter" />
</beans>
datasource.properties
jdbc.components.all=GLOBAL
# Setting for GLOBAL component
jdbc.components.url.GLOBAL=jdbc:mysql://ip:3306/DURGA_DEV
jdbc.components.userName.GLOBAL=usr
jdbc.components.password.GLOBAL=pswd
jdbc.components.minLimit.GLOBAL=1
jdbc.components.maxLimit.GLOBAL=200
jdbc.components.initialLimit.GLOBAL=1
jdbc.components.queryTimeout.GLOBAL=0
# Setting for DURGA component
jdbc.components.url.DURGA=jdbc:mysql://ip:3306/DURGA_DEV
jdbc.components.userName.DURGA=usr
jdbc.components.password.DURGA=pswd
jdbc.components.minLimit.DURGA=1
jdbc.components.maxLimit.DURGA=200
jdbc.components.initialLimit.DURGA=1
jdbc.components.queryTimeout.DURGA=0
# Datasource properties Mysql
jdbc.database.driverClass=com.mysql.jdbc.Driver
jpa.hibernate.dialectClass=org.hibernate.dialect.MySQL5Dialect
This means that your mysql driver jar is not in the classpath. Make sure that it is in "$CATALINA_HOME/lib"
I head a similar problem when deploying my application and starting Tomcat from Eclipse.
After building the war and copying it manually to the webapps folder it was working.
My setup is very much as described in this question:
java.sql.SQLException: No suitable driver
The Driver class was in Tomcat's lib folder, but it seems, my config.xml was not loaded, when deployed from Eclipse into wtpwebapps.
I have a test like the following
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/testDataSpringContext.xml" })
#Transactional
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class })
public class AgenceDAOTest {
#Autowired
private AgenceDAO mAgenceDAO;
#Test
#DatabaseSetup(value = "/META-INF/db-test/sampleData.xml", type = DatabaseOperation.REFRESH)
public void listAgences() {
List<AgenceVO> vListeAgences = mAgenceDAO.getAgences();
Assert.notNull(vListeAgences);
Assert.notEmpty(vListeAgences);
List<AgenceVO> vListeAgencesTrouvees = ListUtils.select(vListeAgences, new Predicate<AgenceVO>() {
public boolean evaluate(AgenceVO pAgenceVO) {
return pAgenceVO.getLibelle().startsWith("TEST_");
}
});
Assert.notNull(vListeAgencesTrouvees);
Assert.notEmpty(vListeAgencesTrouvees);
Assert.isTrue(vListeAgencesTrouvees.size() == 1);
}
}
Everything seems ok because in the log I see the following:
[TransactionalTestExecutionListener: startNewTransaction];Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager#39d325]; rollback [true]
[DbUnitTestExecutionListener: setupOrTeardown];Executing Setup of #DatabaseTest using REFRESH on /META-INF/db-test/sampleData.xml
[AbstractTableMetaData: getDataTypeFactory];Potential problem found: The configured data type factory 'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database 'Oracle' (e.g. some datatypes may not be supported properly). In rare cases you might see this message because the list of supported database products is incomplete (list=[derby]). If so please request a java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory, ensure that you override getValidDbProducts() to specify the supported database products.
[SQL: logStatement];select this_.AGC_ID as AGC1_0_0_, this_.AGC_CP as AGC2_0_0_, this_.AGC_ADR1 as AGC3_0_0_, this_.AGC_COMMUNE as AGC4_0_0_, this_.AGC_ADR2 as AGC5_0_0_, this_.AGC_LIBELLE as AGC6_0_0_, this_.AGC_MAIL as AGC7_0_0_, this_.AGC_NOM as AGC8_0_0_, this_.AGC_TEL as AGC9_0_0_ from FTN_AGENCE_AGC this_
[DbUnitTestExecutionListener: verifyExpected];Skipping #DatabaseTest expectation due to test exception class java.lang.IllegalArgumentException
[TransactionalTestExecutionListener: endTransaction];Rolled back transaction after test execution for test context [[TestContext#cdd54e testClass = AgenceDAOTest, locations = array<String>['classpath:META-INF/spring/testDataSpringContext.xml'], testInstance = com.edf.ftn.data.admin.AgenceDAOTest#16f2067, testMethod = listAgences#AgenceDAOTest, testException = java.lang.IllegalArgumentException: [Assertion failed] - this collection must not be empty: it must contain at least 1 element]]
The dbunit dataset is loaded after the transaction is created, so dataset data should be visible in select, but it is not visible. When the select is executed records in the dataset are not retrieved.
To verify if the dataset is being loaded I've tried to insert a duplicate key and an exception is launched, so I supose that de dataset is loaded correctly.
The datasource and transactionmanager configuration is:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#${ip}:${port}:${schema}" />
<property name="username" value="${user}" />
<property name="password" value="${pass}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
The DAO is not configured as transactional, because in the application it isn't. But I have also tried to make it transactional, and the result is the same.
I do not understand why in this line:
List<AgenceVO> vListeAgences = mAgenceDAO.getAgences();
The dataset is not visible.
Solution found
I fixed the problem by using TransactionAwareDataSourceProxy
Finally I've got the following configuration for datasource:
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#${ip}:${port}:${schema}" />
<property name="username" value="${user}" />
<property name="password" value="${pass}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dbcpDataSource" />
</bean>
<bean id="futunoaTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
I am trying to build an application using both MySQL and neo4j.
Currently I succeed on saving an entity in both of the databases, but when I try to create a rollback only MySQL changes are rollbacked.
I'm not sure if the mode="proxy" configuration for the transactions can even work for neo4j, can someone approve/deny?
I'm using the #Transactional annotation over the relevant method, and I initiate a rollback by throwing a RuntimeException, which as I mentioned causes a rollback on MySQL.
My Configurations:
<neo4j:config graphDatabaseService="graphDatabaseService" entityManagerFactory="entityManagerFactory"/>
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg index="0" value="http://localhost:7474/db/data"/>
</bean>
<context:annotation-config/>
<context:component-scan base-package="...">
<neo4j:repositories base-package="..."/>
<jpa:repositories base-package="..."
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="hibernatePersistenceUnit"/>
<property name="packagesToScan" value="..."/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
</property>
</bean>
<!-- Database -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/..."/>
<property name="lookupOnStartup" value="true"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.data.transaction.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="transactionManagerMysql"/>
<ref bean="transactionManagerNeo4j"/>
</list>
</constructor-arg>
</bean>
<bean id="transactionManagerMysql" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManagerNeo4j" class="org.springframework.data.neo4j.config.JtaTransactionManagerFactoryBean">
<constructor-arg ref="graphDatabaseService" />
</bean>
I tried different configurations but to no effect. The error remained the same. Here the desired config taken from BoneCPs web site:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire-candidate="" autowire="autodetect">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.connection.provider_class">com.jolbox.bonecp.provider.BoneCPConnectionProvider</prop>
<prop key="hibernate.connection.driver_class">org.postgresql.Driver</prop>
<prop key="hibernate.connection.url">jdbc:postgresql:MyDB</prop>
<prop key="hibernate.connection.username">postgres</prop>
<prop key="hibernate.connection.password">123456</prop>
<prop key="bonecp.idleMaxAge">240</prop>
<prop key="bonecp.idleConnectionTestPeriod">60</prop>
<prop key="bonecp.partitionCount">1</prop>
<prop key="bonecp.acquireIncrement">5</prop>
<prop key="bonecp.maxConnectionsPerPartition">60</prop>
<prop key="bonecp.minConnectionsPerPartition">5</prop>
<prop key="bonecp.statementsCacheSize">50</prop>
<prop key="bonecp.releaseHelperThreads">2</prop>
</props>
</property>
</bean>
<!--<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" /> -->
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
And code containing autowired session factory:
#Repository
public abstract class AbstractHibernateDAO< T extends Serializable> {
private final Class< T> clazz;
#Autowired
SessionFactory sessionFactory;
public AbstractHibernateDAO(final Class< T> clazzToSet){
this.clazz = clazzToSet;
}
public T getById(final Long id) {
Preconditions.checkArgument(id != null);
return (T) this.getCurrentSession().get(this.clazz, id);
}
public List< T> getAll() {
return this.getCurrentSession()
.createQuery("from " + this.clazz.getName()).list();
}
public void create(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().persist(entity);
}
public void update(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().merge(entity);
}
public void delete(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().delete(entity);
}
public void deleteById(final Long entityId) {
final T entity = this.getById(entityId);
Preconditions.checkState(entity != null);
this.delete(entity);
}
protected final Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
}
When trying to create a new entity (last line of snippet) I get an error:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
I'm getting a NullPointerException:
java.lang.NullPointerException
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
at org.bitbucket.myName.moleculedatabaseframework.App.main(App.java:32)
------------------------------------------------------------------------
Maybe I missunderstood what autowired means? I thought that that property will be set automatically. So I tried following:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
SessionFactory sessionfactory = (SessionFactory)context.getBean("sessionFactory");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
structureDAO.setSessionFactory(sessionfactory);
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
This leads to following error:
Exception in thread "main" org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
I looked at tons of tutorials but they all omit what seems the basic stuff to get things running, eg. ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); does not appear in any spring + hibernate tutorials. Can someone point me at a complete tutorial one that assumes I'm completely dumb and tells me every step required and has an application that actually runs when repeating the code? (yes getting pretty frustrated now. To be honest if I went plain jdbc I would have been up and running hours ago)
Now,how can I get this running? How does autowired work?
EDIT:
THE SOLUTION AS FOUND THROUGH THE HELP OF "Accepted Answer":
The new Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire="autodetect">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Spring bean configuration. Tell Spring to bounce off BoneCP -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<ref local="mainDataSource" />
</property>
</bean>
<!-- BoneCP configuration -->
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="org.postgresql.Driver" />
<property name="jdbcUrl" value="jdbc:postgresql:MolDB" />
<property name="username" value="postgres"/>
<property name="password" value="123456"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="60"/>
<property name="minConnectionsPerPartition" value="20"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="10"/>
<property name="statementsCacheSize" value="50"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<context:annotation-config />
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
I had to add
<context:annotation-config />
to the file and declare the annoted entity classes in sessionFactory configuration:
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
The I had to uncomment the transaction Manager part and because of that change the data source configuration as the one I used did not work (DataSource is required).
I also had to add
#Repository
#Transactional
public abstract class AbstractHibernateDAO< T extends Serializable> {
//code...
}
to AbstractHibernateDAO. I'm considering to write a blog post and make a link here. For anyone completley new to Spring and hibernate that would be very useful.
Do you have something like this in your spring xml?
<context:annotation-config />
<context:component-scan base-package="base.package" />
This scans for the classes that contains Annotations.