I have a piece of example code:
public class JpaTest {
private EntityManagerFactory emf;
private void setUp() throws Exception {
emf = Persistence.createEntityManagerFactory("testPU");
}
private void tearDown() {
emf.close();
}
private void save() {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
em.persist(new Event("First event", new Date()));
em.persist(new Event("A follow up event", new Date()));
throw new RuntimeException();
} catch (Exception e) {
if (tx != null) tx.rollback();
} finally {
if (em != null) em.close();
}
}
public static void main(String[] args) throws Exception {
JpaTest test = new JpaTest();
test.setUp();
test.save();
test.tearDown();
}
}
The database is MySQL.
The code persists Event entity into the database and than throws an Exception. I expect tx.rollback() to delete the changes made into the database, but this command never works and the data remains in the table:
The question is why tx.rollback() fails and how to delete changes made in the database if transaction throws an Exception?
UPDATED:
persistence.xml:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="testPU">
<class>exampleForTestingJpa.Event</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url"
value="url here..."/>
<property name="javax.persistence.jdbc.user" value="username here..."/>
<property name="javax.persistence.jdbc.password" value="password here..."/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.connection.autocommit" value="false"/>
</properties>
</persistence-unit>
</persistence>
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>example</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
</dependencies>
</project>
Add this to your persistence.xml
<property name="hibernate.connection.autocommit" value="false"/>
Maybe autocommit is enabled ? MySQL manual states that autocommit is enabled by default.
If thats the problem, you surely will not be the first who stumbled over that ;-)
As other users said, it is probably a auto-commit issue since according to the MySQL documentation :
In InnoDB ...
By default, MySQL starts the session for each new connection with
autocommit enabled, so MySQL does a commit after each SQL statement if
that statement did not return an error. If a statement returns an
error, the commit or rollback behavior depends on the error. See
Section 14.21.4, “InnoDB Error Handling”.
Besides, you should not store the Transaction object in a variable.
At each time you want to invoke a Transaction method, get the Transaction object from the EntityManager.
So replace :
tx = em.getTransaction();
tx.begin();
by :
em.getTransaction().begin();
And replace tx.rollback(); by em.getTransaction().rollback();
The Transaction object stored in the EntityManager may be serialized and so have a new reference during transaction processing.
For example, look at the serialization method of AbstractEntityManagerImpl:
public class org.hibernate.jpa.spi.AbstractEntityManagerImpl{
...
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
tx = new TransactionImpl( this );
}
...
}
The problem with not rolling transaction back was caused by MyISAM. With InnoDB rollback works fine.
Related
I'm currently in the process of updating a large project from Hibernate 5.1 to Hibernate 5.2.17 and I'm running into an issue that I'm struggling to resolve.
We have a suite of tests that are testing our DAOs using the H2 in-memory database, but some tests have started to fail on the updated version of Hibernate.
Some of the tests attempt to delete a null entity from the persistence context and expect the operation to fail with an IllegalArgumentException. With the new version of Hibernate the exception is still thrown as expected, but the transaction is no longer being rolled back and is being left active, and is consequently causing subsequent tests to fail because there's already an active transaction. Stack trace included below:
java.lang.AssertionError: Transaction is still active when it should have been rolled back.
at org.junit.Assert.fail(Assert.java:88)
at hibernatetest.persistence.HibernateTestDAOTest.testDeleteDetachedEntity(HibernateTestDAOTest.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
While investigating I noticed a similar difference in behaviour when attempting to delete a detached entity as well. I have been able to recreate the behaviour in a small, standalone project that can be found here. The project also includes configuration in the pom.xml (commented out) for running against Hibernate 5.0.10, where the tests pass with no issue and the failed transaction is correctly rolled-back.
While I haven't been able to recreate the error deleting a null entity, I have managed to recreate it with a detached entity, and I'm hoping the answer to why this is happening will help guide me to why it's also failing with null in the real code.
Are we doing something wrong here, or is this an issue with Hibernate itself?
Code also included below:
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>HibernateTest</groupId>
<artifactId>HibernateTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.version>3.7.0</maven.compiler.version>
<!-- Uncomment this property to run as Hibernate 5.0.10 -->
<!-- <hibernate.core.version>5.0.10.Final</hibernate.core.version> -->
<!-- Uncomment this property to run as Hibernate 5.2.17 -->
<hibernate.core.version>5.2.17.Final</hibernate.core.version>
<junit.version>4.12</junit.version>
<h2.version>1.4.197</h2.version>
<javaee.api.version>7.0</javaee.api.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.core.version}</version>
</dependency>
<!-- Uncomment these dependencies to run using Hibernate 5.0.10 -->
<!--
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>${hibernate.core.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.core.version}</version>
<scope>test</scope>
</dependency>
-->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${javaee.api.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
HibernateTest.java (entity class):
package hibernatetest.persistence;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
#Entity
#Table(name = "hibernate_test")
public class HibernateTest {
#Id
#Column(name = "id")
#Type(type = "uuid-char")
private UUID id;
public HibernateTest(final UUID id) {
this.id = id;
}
}
HibernateTestDAO.java
package hibernatetest.persistence;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class HibernateTestDAO {
#PersistenceContext(unitName = "hibernate-test")
private EntityManager entityManager;
public void delete(final HibernateTest entity) {
entityManager.remove(entity);
}
}
EntityManagerRule.java (JUnit Rule to provide the entity manager for the tests):
package hibernatetest.persistence;
import java.lang.reflect.Field;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import org.junit.rules.ExternalResource;
public class EntityManagerRule extends ExternalResource {
private EntityManagerFactory emFactory;
private EntityManager em;
#Override
protected void before() {
emFactory = Persistence.createEntityManagerFactory("hibernate-test");
em = emFactory.createEntityManager();
}
#Override
protected void after() {
if (em != null) {
em.close();
}
if (emFactory != null) {
emFactory.close();
}
}
public HibernateTestDAO initDAO() {
final HibernateTestDAO dao = new HibernateTestDAO();
try {
injectEntityManager(dao);
} catch (Exception e) {
e.printStackTrace();
}
return dao;
}
public EntityManager getEntityManager() {
return em;
}
public void persist(final Object entity) {
final EntityTransaction transaction = em.getTransaction();
transaction.begin();
try {
em.persist(entity);
} catch (Exception e) {
transaction.rollback();
throw e;
}
transaction.commit();
}
private void injectEntityManager(final HibernateTestDAO dao) throws Exception {
final Field emField = dao.getClass().getDeclaredField("entityManager");
emField.setAccessible(true);
emField.set(dao, em);
}
}
HibernateTestDAOTest.java:
package hibernatetest.persistence;
import static org.junit.Assert.fail;
import java.util.UUID;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
public class HibernateTestDAOTest {
#Rule
public EntityManagerRule rule = new EntityManagerRule();
private HibernateTestDAO dao;
#Before
public void setup() {
dao = rule.initDAO();
}
#Test
public void testDeleteNullEntity() {
HibernateTest entity = null;
try {
dao.delete(entity);
} catch (IllegalArgumentException e) {
if (rule.getEntityManager().getTransaction().isActive()) {
fail("Transaction is still active when it should have been rolled back.");
}
}
}
#Test
public void testDeleteDetachedEntity() {
HibernateTest entity = new HibernateTest(UUID.randomUUID());
rule.persist(entity);
rule.getEntityManager().detach(entity);
try {
dao.delete(entity);
} catch (IllegalArgumentException e) {
if (rule.getEntityManager().getTransaction().isActive()) {
fail("Transaction is still active when it should have been rolled back.");
}
}
}
}
persistence.xml from src/test/resources/META-INF:
<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_2_0.xsd"
version="2.0">
<persistence-unit name="hibernate-test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>hibernatetest.persistence.HibernateTest</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test;INIT=create schema if not exists test\;runscript from 'classpath:/populate.sql';DB_CLOSE_DELAY=-1;"/>
<property name="javax.persistence.validation.mode" value="none"/>
</properties>
</persistence-unit>
</persistence>
populate.sql from src/test/resources:
CREATE TABLE IF NOT EXISTS hibernate_test (
id UUID NOT NULL
);
Nothing in the spec states that when a call to EntityManager#remove fails that the persistence provider should rollback the existing transaction, that just makes no sense.
If you look at all the examples in the Hibernate test suite, you'll notice this behavior:
EntityManager entityManager = getOrCreateEntityManager();
try {
entityManager.getTransaction().begin();
// do something
entityManager.getTransaction().commit();
}
catch ( Exception e ) {
if ( entityManager != null && entityManager.getTransaction.isActive() ) {
entityManager.getTransaction().rollback();
}
throw e;
}
finally {
if ( entityManager != null ) {
entityManager.close();
}
}
If your tests worked previously and no longer do in the same way, I'm not sure I'd necesssarily say that is a bug as the code which you've supplied above does not conform to what I have shown here with properly handling the rollback in user code unless you have spring or some other framework at play which you haven't illustrated.
But if you feel there is a regression between 5.1 and 5.2, you're welcomed to open a JIRA and report it with your reproducable test use case and we can do further investigation.
One key point to remember is that 5.2.x introduced the merging of the JPA artifact hibernate-entitymanager into hibernate-core proper, so there could be a regression here with that but its extremely unlikely.
I'm using following dependencies to get a dbunit test going
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.4</version>
<scope>test</scope>
</dependency>
The test runs perfectly in inteliJ over and over but when I run the test on command line it fails all the time with foreign key constraint errors on loading the second test in my test class
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<PUBLIC.REGIO id="1" entiteit="1" code="a" naam="regio 1"/>
<PUBLIC.REGIO id="2" entiteit="2" code="b" naam="regio 2"/>
<PUBLIC.REGIO />
</dataset>
<persistence version="1.0" 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">
<persistence-unit name="voertuigbeheer" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>be.delijn.voertuigbeheer.entity.Regio</class>
<class>be.delijn.voertuigbeheer.entity.Stelplaats</class>
<class>be.delijn.voertuigbeheer.entity.VoertuigType</class>
<class>be.delijn.voertuigbeheer.entity.Voertuig</class>
<class>be.delijn.voertuigbeheer.entity.VoertuigEigenschap</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.logging.thread" value="false"/>
<property name="eclipselink.logging.session" value="false"/>
<property name="eclipselink.logging.timestamp" value="false"/>
<property name="eclipselink.logging.exceptions" value="false"/>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:hsql:mem"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
</persistence-unit>
</persistence>
public abstract class AbstractJPATest {
protected static EntityManagerFactory entityManagerFactory;
protected static EntityManager entityManager;
protected static IDatabaseConnection connection;
protected static IDataSet dataset;
#BeforeClass
public static void initEntityManager() throws Exception {
System.out.println("before class running");
entityManagerFactory = Persistence.createEntityManagerFactory("voertuigbeheer");
entityManager = entityManagerFactory.createEntityManager();
ServerSession serverSession = entityManager.unwrap(ServerSession.class);
SchemaManager schemaManager = new SchemaManager(serverSession);
schemaManager.replaceDefaultTables(true, true);
ConnectionPool connectionPool = serverSession.getConnectionPool("default");
Connection dbconn = connectionPool.acquireConnection().getConnection();
connection = new DatabaseConnection(dbconn);
DatabaseConfig config = connection.getConfig();
config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
config.setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
FlatXmlDataSetBuilder flatXmlDataSetBuilder = new FlatXmlDataSetBuilder();
flatXmlDataSetBuilder.setColumnSensing(true);
dataset = flatXmlDataSetBuilder.build(
Thread.currentThread().getContextClassLoader().getResourceAsStream("test-dataset.xml"));
}
#AfterClass
public static void closeEntityManager() {
entityManager.close();
entityManagerFactory.close();
}
#Before
public void cleanDB() throws Exception {
System.out.println("loading");
DatabaseOperation.CLEAN_INSERT.execute(connection, dataset);
setup();
}
public abstract void setup();
}
public class RegioDaoTests extends AbstractJPATest {
private RegioDao regioDao;
#Test
public void getAll() throws Exception {
List<Regio> result = regioDao.getAll();
assertThat(result.size()).isEqualTo(2);
}
#Test
public void getById() throws Exception {
Regio regio = regioDao.getById(2L);
assertThat(regio.getId()).isEqualTo(2);
}
#Override
public void setup() {
regioDao = new RegioDao();
regioDao.setEntityManager(entityManager);
}
}
Caused by: org.hsqldb.HsqlException: integrity constraint violation: unique constraint or index violation; SYS_PK_10234 table: REGIO
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.Constraint.getException(Unknown Source)
at org.hsqldb.index.IndexAVLMemory.insert(Unknown Source)
at org.hsqldb.persist.RowStoreAVL.indexRow(Unknown Source)
at org.hsqldb.TransactionManager2PL.addInsertAction(Unknown Source)
at org.hsqldb.Session.addInsertAction(Unknown Source)
at org.hsqldb.Table.insertSingleRow(Unknown Source)
at org.hsqldb.StatementDML.insertSingleRow(Unknown Source)
at org.hsqldb.StatementInsert.getResult(Unknown Source)
at org.hsqldb.StatementDMQL.execute(Unknown Source)
at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
at org.hsqldb.Session.execute(Unknown Source)
I've tried switching from HSQL to H2 and vice versa both databases give the same problem. However again running the tests in InteliJ work perfectly. It's running in maven that keeps throwing the error. What am I missing here I'm totally lost why it wouldn't work
I found it ... taking a step back and rethinking things found me the sollution maven by default runs test methods in paralell. If you restrict maven to only run classes in paralell I was able to fix it
<build>
<finalName>voertuigbeheer-web</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<parallel>classes</parallel>
</configuration>
</plugin>
</plugins>
</build>
This was a very annoying "feature" to track down !
i am getting this error when I want to run the following code:
package HIndexSaar.HIndex;
public class AppHibernate {
public static void main(String[] args){
HibernateManager mng = new HibernateManager();
mng.addPerson("H H", "Uni Saarland");
mng.addPerson("Bernd Finkbeiner", "Uni Saarland");
mng.addUniversity("Saarland University");
}
}
My HibernateManager class:
package HIndexSaar.HIndex;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateManager {
private static SessionFactory ourSessionFactory;
private static ServiceRegistry serviceRegistry;
public HibernateManager(){
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
ourSessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
/**
* adds a person to the database.
* #param name: the name of the person
* #param affiliation: the university of the person
* #return the created ID
*/
public Integer addPerson(String name, String affiliation){
Transaction tx = null;
Integer personID = null;
try (Session session = ourSessionFactory.openSession()) {
tx = session.beginTransaction();
Person p = new Person(name, affiliation);
personID = (Integer) session.save(p);
tx.commit();
} catch (HibernateException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
}
return personID;
}
/**
* adds a university to the database.
* #param name: the name of the university
* #return the id of the newly created university
* */
public Integer addUniversity(String name){
Transaction trans = null;
Integer uniID = null;
try (Session session = ourSessionFactory.openSession()) {
trans = session.beginTransaction();
University uni = new University(name);
uniID = (Integer) session.save(uni);
trans.commit();
} catch (HibernateException e) {
if (trans != null) {
trans.rollback();
}
e.printStackTrace();
}
return uniID;
}
/**
* adds a publication to the database.
* #param name: the name of the publication
* #param author: the author of the publication
* #return the generated ID
*/
public Integer addPublication(String name, String author){
Transaction trans = null;
Integer pubID = null;
try (Session session = ourSessionFactory.openSession()) {
trans = session.beginTransaction();
Publication p = new Publication(name, author);
pubID = (Integer) session.save(p);
trans.commit();
} catch (HibernateException e) {
if (trans != null) {
trans.rollback();
}
e.printStackTrace();
}
return pubID;
}
}
And my hibernate.cfg.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="HIndex Session">
<!-- Database connection settings -->
<property name="connection.driver:class">org.postgreSQL.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost/HIndex</property>
<property name="hibernate.connection.username">index_user</property>
<property name="hibernate.connection.password">password</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL Dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</property>
<!-- Assume test is the database name -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<!-- Names the annotated entity class -->
<mapping class="HIndexSaar.HIndex.Person"/>
<mapping class="HIndexSaar.HIndex.University"/>
<mapping class="HIndexSaar.HIndex.Publication"/>
</session-factory>
</hibernate-configuration>
And the pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>HIndexSaar</groupId>
<artifactId>HIndex</artifactId>
<version>Version 0.2</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<name>HIndex</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<!-- jsoup HTML parser library # http://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1207</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.0-RC1</version>
</dependency>
</dependencies>
</project>
The error is shown at the "tx.rollback();" line:
catch (HibernateException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
}
I do not use multiple threads anywhere, so what am I missing?
From the docs for ResourceClosedException:
Indicates an attempt was made to use a closed resource (Session,
SessionFactory, etc).
Now, when using "try with resources", the documentation says:
Note: A try-with-resources statement can have catch and finally blocks
just like an ordinary try statement. In a try-with-resources
statement, any catch or finally block is run after the resources
declared have been closed.
So by the time you call rollback() the Session will already have been closed.
The simplest solution here would be to move your existing catch block to an inner try/catch block around the transaction-management code, e.g.:
try (Session session = ourSessionFactory.openSession()) {
try {
tx = session.beginTransaction();
Person p = new Person(name, affiliation);
personID = (Integer) session.save(p);
tx.commit();
}
catch (HibernateException e) {
if (tx != null) {
tx.rollback();
}
}
}
This ensures that the Session only gets closed once you've (at least) requested rollback.
I'm working on REST server and learning EJB\hibernate at the same time. When service call DAO I faced with an issue that it can not find my persistence unit.
#Stateless
public class HotelDAO {
#PersistenceContext(unitName = Constants.PERSISTENCE_UNIT)
private EntityManager em;
public List<HotelsEntity> getAll() {
// TODO complete me
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<HotelsEntity> criteria = builder.createQuery(HotelsEntity.class);
Root<HotelsEntity> root = criteria.from(HotelsEntity.class);
criteria.select(root);
TypedQuery<HotelsEntity> resultQuery = em.createQuery(criteria);
return resultQuery.getResultList();
}
}
In this case I get "Unable to retrieve EntityManagerFactory for unitName persistenceUnit"
Then I try this:
#Stateless
public class HotelDAO {
public List<HotelsEntity> getAll() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistenceUnit");
EntityManager em = emf.createEntityManager();
// TODO complete me
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<HotelsEntity> criteria = builder.createQuery(HotelsEntity.class);
Root<HotelsEntity> root = criteria.from(HotelsEntity.class);
criteria.select(root);
TypedQuery<HotelsEntity> resultQuery = em.createQuery(criteria);
return resultQuery.getResultList();
}
}
In this case I get "No Persistence provider for EntityManager named persistenceUnit".
I checl similar issues at the stackoverflow:
persitence.xml under META-INF
DAO is injected into EJB
provider is mentioned in persistence.xml
I don't use Spring
Do you have any gueses?
<?xml version="1.0" encoding="UTF-8"?>
<persistence-unit name="persistenceUnit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/HospitalityDataSource</jta-data-source>
<class>com.example.model.AmmenitiesEntity</class>
<class>com.example.model.HotelPropertyEntity</class>
<class>com.example.model.HotelsEntity</class>
<class>com.example.model.InventoriesEntity</class>
<class>com.example.model.ReservationEntity</class>
<class>com.example.model.RoomEntity</class>
<class>com.example.model.RoomPropertyEntity</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="dbroot"/>
<property name="hibernate.connection.password" value="password"/>
</properties>
</persistence-unit>
pom.xml
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.5.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.29</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
If I'm not wrong, I think persistence.xml must be in src/main/resources/META-INF/persistence.xml
Message.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
#Entity
#Table(name="MESSAGES")
#Cache(region = "messages", usage = CacheConcurrencyStrategy.READ_WRITE)
public class Message {
Message(){
}
Message(String message){
message_text=message;
}
#Id #GeneratedValue
#Column(name="MESSAGE_ID")
public Long id;
#Column(name="MESSAGE_TEXT")
public String message_text;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMessage_text() {
return message_text;
}
public void setMessage_text(String message_text) {
this.message_text = message_text;
}
}
Ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache eternal="true" maxElementsInMemory="100" overflowToDisk="false" />
<cache name="messages" maxElementsInMemory="10" eternal="true" overflowToDisk="false" />
</ehcache>
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="annotation">
<properties>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:#ebiz-dev-db-esb:1521:esbd"/>
<property name="hibernate.connection.username" value="CUST_INFO"/>
<property name="hibernate.connection.password" value="POUND987"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9Dialect"/>
<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="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />
<property name="hibernate.cache.provider_configuration_file_resource_path" value="ehcache.xml" />
</properties>
</persistence-unit>
</persistence>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>HibernateWithAnnotation</groupId>
<artifactId>HibernateWithAnnotation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HibernateWithAnnotation</name>
<repositories>
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.1-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.5.1-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.5.1-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.6.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
</project>
TestAnnotation class
package com.annotation;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
public class TestAnnotation {
public static void main(String args[]){
EntityManagerFactory factory=Persistence.createEntityManagerFactory("annotation");
EntityManager manager=factory.createEntityManager();
EntityTransaction transaction=manager.getTransaction();
transaction.begin();
manager.persist(new Message("My Entity Test One More Example New"));
transaction.commit();
System.out.println("First time calling Message Object");
getMessage(manager,23);
System.out.println("Second time calling Message Object");
getMessage(manager,23);
factory.close();
}
public static void getMessage(EntityManager manager,long id){
EntityTransaction transaction1=manager.getTransaction();
transaction1.begin();
Query q=manager.createQuery("from Message m where m.id="+id);
Message m=(Message)q.getSingleResult();
System.out.println(m.getMessage_text());
transaction1.commit();
}
}
My problem is: When I run this code from TestAnnotation class via main method I get the following error:
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named annotation
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
at com.annotation.TestAnnotation.main(TestAnnotation.java:10)
Your persistence-unit is incomplete. See the documentation.
Add <class>com.annotation.TestAnnotation</class> to your persistence-unit node in your persistence.xml file before the properties node.
You likely also need transaction-type="RESOURCE_LOCAL" on you persistence-unit node.
For example, my working version uses:
pom.xml:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.5.4-Final</version>
<scope>runtime</scope>
</dependency>
persistenct.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_2_0.xsd"
version="2.0">
<persistence-unit name="MyPU" transaction-type="RESOURCE_LOCAL">
<class>com.myentities.MyEntity</class>
<properties>
<property name="hibernate.cache.use_query_cache" value="false"/>
<property name="hibernate.cache.use_second_level_cache" value="false"/>
<!-- These lines can be used for debugging -->
<!--<property name="show_sql" value="true"/>-->
<!--<property name="format_sql" value="true"/>-->
</properties>
</persistence-unit>
</persistence>
My DAO class:
private EntityManager m_entityManagerFactory;
// initializer (this is costly, do only 1x on post construct)
m_entityManager = createEntityManagerFactory( jdbcDriverName, jdbcURL, dbUserName, dbPassword );
// when needed (less costly, can do 1x or whenever you need the entity manager)
EntityManager entityManager = m_entityManagerFactory.createEntityManager();
private EntityManagerFactory createEntityManagerFactory (
#NotNull final String jdbcDriverName,
#NotNull final String jdbcURL,
#NotNull final String dbUserName,
#NotNull final String dbPassword )
{
final Properties properties = new Properties();
properties.put( "hibernate.connection.driver_class", jdbcDriverName );
properties.put( "hibernate.connection.url", jdbcURL );
properties.put( "hibernate.connection.username", dbUserName );
properties.put( "hibernate.connection.password", dbPassword );
return Persistence.createEntityManagerFactory( "AlertProcessorPU", properties );
}