JPA update query: cache not properly invalidated - jpa

Why doesn't it work:
#Test
public void test() {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test-pu");
EntityManager entityManager = entityManagerFactory.createEntityManager();
String id = "id";
long value = 1234L;
entityManager.getTransaction().begin();
FancyEntity fancyEntity = new FancyEntity(id);
entityManager.persist(fancyEntity);
int updateCount = entityManager.createQuery("update FancyEntity item set item.value = ?2 where item.id = ?1").setParameter(1, id).setParameter(2, value).executeUpdate();
assertEquals(1, updateCount);
FancyEntity checkResult = entityManager.find(FancyEntity.class, id);
assertEquals(1234L, checkResult.getValue()); // <- this assert fails
entityManager.getTransaction().commit();
}
with
#Entity
public class FancyEntity {
#Id
private String id;
#Column
private long value;
public FancyEntity(String id) {
this.id = id;
this.value = 0;
}
public FancyEntity() {
}
public long getValue() {
return value;
}
}
and
<persistence-unit name="test-pu"
transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.fancypackage.FancyEntity</class>
<properties>
<property name="eclipselink.logging.level" value="SEVERE"/>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem;sql.enforce_strict_size=true;hsqldb.tx=mvcc" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
</properties>
</persistence-unit>
Result is
java.lang.AssertionError:
Expected :1234
Actual :0
It seems there is some cache that is not invalidated by the update query. checkResult and fancyEntity are the same object. Forcing the refresh using entityManager.refresh(checkResult). The weirdest thing is that a select is issued for retrieving checkResult (seen in the eclipselink log), still its result is not taken into account. Same behavior using MySQL rather than HSQL.
Any hint on what could be wrong ?

That is a bulk update statement, As the JPQL language reference notes:
The persistence context is not synchronized with the result of the
bulk update or delete. Caution should be used when executing bulk
update or delete operations because they may result in inconsistencies
between the database and the entities in the active persistence
context. In general, bulk update and delete operations should only be
performed within a separate transaction or at the beginning of a
transaction (before entities have been accessed whose state might be
affected by such operations).
https://docs.oracle.com/html/E24396_01/ejb3_langref.html#ejb3_langref_bulk_ops)
So the behaviour you are seeing makes perfect sense.

Related

Transactional CDI bean not committing record to database

I am trying to build a simple REST service, using JAX-RS, that will perform the standard CRUD operations on a database table. I am able to successfully query for records, but I cannot insert new ones. I do not get any errors and when I step through the code in debug mode everything looks good. I am using a transactional CDI bean running in a Glassfish 4.1 container.
It feels like it's just never committing the transaction. I'm pretty new to Java EE, but my understanding is that since the bean is transactional the container should handle the commit for me. Anyone know why it is not?
#Path("/recipes")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class RecipeResource {
#Inject
RecipesService recipesService;
#GET
public List<Recipe> getRecipes() {
return recipesService.getAllRecipes();
}
#POST
public void addRecipse(Recipe recipe) {
recipesService.addRecipe(recipe);
}
}
public class RecipesService {
#PersistenceContext(unitName="PANTRYDB", type=PersistenceContextType.TRANSACTION)
EntityManager em;
public RecipesService () {
}
public List<Recipe> getAllRecipes () {
List<Recipe> recipes = null;
try {
TypedQuery<Recipe> typedQuery = em.createQuery("select r from Recipe r", Recipe.class);
recipes = typedQuery.getResultList();
} catch (Exception e) {
System.out.println(e);
}
return recipes;
}
#Transactional
//This is the method that seems to not commit it's transaction
//The Recipe object is populated correctly, and the persist() doesn't
//throw any errors
public void addRecipe(Recipe recipe) {
try {
em.persist(recipe);
} catch (Exception e) {
System.out.println(e);
}
}
}
#Entity
#Table(name="RECIPES", schema="COOKBOOK")
public class Recipe {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column
private String name;
#Column(name="CREATED_DATE")
private Calendar createdDate;
#Column(name="LAST_MADE_DATE")
private Calendar lastMadeDate;
#Column
private String description;
#Column
private String notes;
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Calendar getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Calendar createdDate) {
this.createdDate = createdDate;
}
public Calendar getLastMadeDate() {
return lastMadeDate;
}
public void setLastMadeDate(Calendar lastMadeDate) {
this.lastMadeDate = lastMadeDate;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
#Override
public String toString() {
return name;
}
}
Persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" 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">
<persistence-unit name="PANTRYDB" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.domain.Recipe</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:/Users/development/eclipse/ws_playground/databases/pantry_db/PANTRYDB" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
</persistence-unit>
</persistence>
I tried your application on a weblogic 12.2.1 and it successfully inserted in database and i do not have any problem with transaction.
Here is my code.
RecipeResource class (I modified the #Path to call it via web browser and also instanciated the Recipe manually):
#Path("/recipes")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class RecipeResource {
#Inject
RecipesService recipesService;
#GET
#Path("get")
public List<Recipe> getRecipes() {
return recipesService.getAllRecipes();
}
#GET
#Path("add")
public String addRecipse() {
Recipe recipe = new Recipe();
recipe.setDescription("desc");
recipesService.addRecipe(recipe);
return "OK";
}
}
The Recipe class is same as yours except that i commented the schema :
#Entity
#Table(name="RECIPES") //, schema="COOKBOOK")
public class Recipe {
}
My persistence.xml (I'm using in-memory database):
<?xml version="1.0" encoding="UTF-8"?>
<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="PANTRYDB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/__default</jta-data-source>
<class>org.jvi.webservice.transactional.db.Recipe</class>
<properties>
<!--<property name="eclipselink.ddl-generation" value="create-tables"/>-->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.cache.shared.default" value="false"/>
</properties>
</persistence-unit>
So your problem might come from the Application Server.
Did you try to deploy your webapp on another server?
When you are using JTA transaction management, responsibility for creating and managing database connections is provided by application server, not your application.
Basically, you have to configure your data source in your GlassFish server instance, not directly in persistence.xml via properties:
Configure connection pool and datasource JNDI name in your GlassFish server instance
Link data source configuration in your persistence.xml via <jta-data-source> element
Please check this answer for further details:
https://stackoverflow.com/a/9137741/1980178
Are you sure you are not mixing two frameworks. RecipeResource has a #Path annotation which is from the JavaEE framework, and the #Transactional annotation is from the Spring framework, I think you should replace it with #TransactionAttribute which is the equivalent JavaEE anotation.
Have a look here for details between transaction in Spring an JavaEE

Transaction doesn't work in aspectj

I have the aspect(see below) which should log actions(create, update, delete) in db. Depends on action logging happens in a preProcess or postProcess method. I shouldn't log anything if some fail happens through these actions. I.e. if create didn't happened, then there is no need to logging it.
I tried to tested it. I throw RunTimeException in the join point and expect that there is no new log in db. Unfortunately, new log is saved in spite of exception in the join point.
Aspect:
#Component
#Aspect
public class LoggingAspect {
#Autowired
private ApplicationContext appContext;
#Autowired
private LoggingService loggingService;
#Around("#annotation(Loggable)")
#Transactional
public void saveActionMessage(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Loggable m = ms.getMethod().getAnnotation(Loggable.class);
LoggingStrategy strategy = appContext.getBean(m.strategy());
Object argument = joinPoint.getArgs()[0];
strategy.preProcess(argument);
joinPoint.proceed();
strategy.postProcess(argument);
}
}
TestApplicationConfig:
<context:spring-configured/>
<import resource="applicationConfig-common.xml"/>
<import resource="applicationConfig-security.xml"/>
<aop:aspectj-autoproxy/>
<util:map id="testValues">
<entry key="com.exadel.mbox.test.testSvnFile" value="${svnFolder.configPath}${svnRoot.file[0].fileName}"/>
<entry key="com.exadel.mbox.test.testCommonRepositoryPath" value="${svnRoot.commonRepositoryPath}"/>
<entry key="com.exadel.mbox.test.testMailFile" value="${mailingList.configPath}"/>
</util:map>
<context:component-scan base-package="com.exadel.report.common" />
<!-- Jpa Repositories -->
<jpa:repositories base-package="com.exadel.report.common.dao" />
<tx:annotation-driven proxy-target-class="true"
transaction-manager="txManager" mode="aspectj"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Data Source -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Entity Manager -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
</bean>
</property>
<property name="persistenceUnitName" value="exviewer-test"/>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
[Update]
LoggingStrategy:
public interface LoggingStrategy {
public void preProcess(Object obj);
public void postProcess(Object obj);
}
BaseLoggingStrategy:
public class BaseLoggingStrategy implements LoggingStrategy {
#Override
public void preProcess(Object obj) {}
#Override
public void postProcess(Object obj) {}
}
UpdateProcessStrategy:
#Service
public class UpdateProcessStrategy extends BaseLoggingStrategy {
#Autowired
private LoggingService loggingService;
#Autowired
private UserService userService;
#Autowired
DeviceService deviceService;
private Device currentDevice;
#Override
#Transactional
public void preProcess(Object obj) {
currentDevice = (Device) obj;
Device previousDevice = deviceService.getById(currentDevice.getId());
String deviceDataBeforeUpdate = deviceService.getDeviceDetailsInJSON(previousDevice);
String deviceDataAfterUpdate = deviceService.getDeviceDetailsInJSON(currentDevice);
String login = userService.getCurrentUser().getLogin();
String actionMessage = LoggingMessages.DEVICE_UPDATE.name();
loggingService.save(
new Logging(
login,
actionMessage,
deviceDataBeforeUpdate,
deviceDataAfterUpdate,
new Date())
);
}
#Override
public void postProcess(Object obj) {}
}
Class intercepted by aspcet:
#Service
public class DeviceService {
#Loggable(value = LoggingMessages.DEVICE_CREATE, strategy = CreateProcessStrategy.class)
#Transactional
public void create(Device device) {
createOrUpdate(device);
}
#Loggable(value = LoggingMessages.DEVICE_UPDATE, strategy = UpdateProcessStrategy.class)
#Transactional
public void update(Device device) {
createOrUpdate(device);
}
private void createOrUpdate(Device device) {
deviceRepository.save(device);
}
#Loggable(value = LoggingMessages.DEVICE_REMOVE, strategy = RemoveProcessStrategy.class)
public void remove(Long deviceId) {
deviceRepository.delete(deviceId);
}
}
Loggable annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Loggable {
LoggingMessages value();
Class<? extends LoggingStrategy> strategy();
}
Log for update action contains:
id, created_dtm, action(DEVICE_UPDATE), device_data_before_action_on_the_device(in json format), device_data_after_action_on_the_device(in json format), created_by.
Disclaimer: Actually I am not a Spring expert, maybe someone else can help you out here. My field of expertise it AspectJ, which is how I found your question.
Anyway, you have two issues here:
#Transactional annotation on your aspect's advice LoggingAspect.saveActionMessage(..). Actually I have no idea if this works at all (I found no example using #Transactional on an aspect method/advice on the web, but maybe I searched in the wrong way) because declarative transaction handling in Spring is implemented via proxy-based technology, just like Spring AOP. Read the chapter 12 about transaction management in the Spring manual for further details, especially chapter 12.5.1. I am pretty sure you will find a way to do what you want there.
Nested transactions, because e.g. UpdateProcessStrategy.preProcess(..) is called by the very advice which is meant to be transactional, but is declared #Transactional too. So you have a transaction within a transaction. How Spring handles this, I have no idea, but maybe this tutorial about Spring transaction propagation contains enlightening details.
The Spring manual lists several means to implement transactional behaviour: programmatically, declaratively via annotations, XML-based <tx:advice> stuff and so forth. I don't know which way is the best for you, I merely wanted to provide some general hints.

EclipseLink JPA Primary Key with Custom Default Value

I have a table in my SQL Server database where the primary key field is defined with NEWID() as the default value. The expectation is client need not pass the primary key field value and the SQL server will handle it.
While defining my model class at JPA I have to define this ID field with a generation type. I tried IDENTITY, TABLE and SEQUENCE Generator. Unfortunately I am getting an error as
Exception Description: Error preallocating sequence numbers.
The sequence table information is not complete..
My Persistence. XML is as below
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="LOB_Webservice" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.xyz.lob.model.jpa.OrderDetail</class>
<class>com.xyz.lob.model.jpa.OrderHeader</class>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="jboss.as.jpa.providerModule" value="org.eclipse.persistence"/>
<property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://localhost:1433;databaseName=LOB_INT" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="*******" />
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.sharedCache.mode" value="None"/>
<property name="eclipselink.jdbc.cache-statements" value="false" />
<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.logging.exceptions" value="true"/>
<property name="eclipselink.weaving" value="static"/>
</properties>
</persistence-unit>
My Model class is as below
#Entity
public class OrderHeader implements Serializable {
#Id
#Basic(optional = false)
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="OrderId")
private String orderId;
...
}
Hi #Joe2013 Not sure if is still an issue but when using Table Generators AND you did not specified for Eclipse Link to generate the schema based on your object model, you must manually create the table AND also insert the rows for the corresponding generators and their initial values.
Otherwise it will not work and you will get the error you mentioned.
I have provided custom and default Sequence ID Generator examples as below.
Use Custom Sequence ID Generator (EclipseLink only)
Define Custom Sequence class
package org.phstudy.sequence;
public class MyNewIDSequence extends Sequence implements SessionCustomizer {
private static final long serialVersionUID = -6308907478094680131L;
public MyNewIDSequence() {
super();
}
public MyNewIDSequence(String name) {
super(name);
}
public void customize(Session session) throws Exception {
MyNewIDSequence sequence = new MyNewIDSequence("mynewid");
session.getLogin().addSequence(sequence);
}
#Override
public Object getGeneratedValue(Accessor accessor, AbstractSession writeSession, String seqName) {
DataReadQuery query = new DataReadQuery("select NEWID()");
query.setResultType(DataReadQuery.VALUE);
return writeSession.executeQuery(query);
}
#Override
public Vector getGeneratedVector(Accessor accessor, AbstractSession writeSession, String seqName, int size) {
return null;
}
#Override
public void onConnect() { }
#Override
public void onDisconnect() { }
#Override
public boolean shouldAcquireValueAfterInsert() {
return false;
}
#Override
public boolean shouldUsePreallocation() {
return false;
}
#Override
public boolean shouldUseTransaction() {
return false;
}
}
Register custom sequence in persistence.xml
<persistence ...>
<persistence-unit ...>
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
...
<property name="eclipselink.session.customizer" value="org.phstudy.sequence.MyNewIDSequence"/>
...
</persistence-unit>
</persistence>
Add Sequence Annotation with custom sequence name
#Entity
public class CustomSequence {
#Id
#GeneratedValue(generator = "mynewid")
private String id;
...
}
Use Default Sequence ID Generator (JPA, EclipseLink, Hibernate)
Please enable automatic schema generation or create table for storing ID manually when using Table, Sequence or IDENTITY ID Generation.
opt#1. Enable automatic schema generation
<persistence ...>
<persistence-unit ...>
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
...
<property name="eclipselink.ddl-generation" value="create-tables"/>
...
</persistence-unit>
</persistence>
opt#2. Create table for storing ID manually
Define Sequence in your entity
#SequenceGenerator(name="Emp_Gen", sequenceName="Emp_Seq")
#Id #GeneratedValue(generator="Emp_Gen")
private int getId;
SQL script to create sequence
CREATE SEQUENCE Emp_Seq
MINVALUE 1
START WITH 1
INCREMENT BY 50 //allocation size

Internal Exception: java.sql.SQLException: Invalid state, the Connection object is closed

I have a JSF application that uses Eclipse Persistence Services - 2.1.1.v20100817-r8050, and I sometimes get the following error:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.1.v20100817-r8050): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid state, the Connection object is closed.
Error Code: 0
Call: SELECT XXXXX FROM XXXXX
bind => [/Home/Footer/]
Query: ReadAllQuery(name="WWW.find" referenceClass=WWW sql="SELECT XXXXX FROM XXXXX")
I have no idea what is causing it. The exception is thrown in the following function on the "return q.getResultList();" line.
public List<WWW> find(String url) {
}
EntityManager em = getEntityManager();
try {
Query q = em.createNamedQuery("WWW.find");
q.setParameter("url", url);
return q.getResultList();
} finally {
em.close();
}
}
We have SQL Server 2005 and the database isn't down. This is more of a recent thing to consistently happen. Below is the properties that we set in the persistence.xml file. Any comments on what should change in this?
<properties>
<property name="javax.persistence.jdbc.password" value="password"/>
<property name="javax.persistence.jdbc.user" value="user"/>
<property name="javax.persistence.jdbc.driver" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:jtds:sqlserver://SERVER:1433/DB"/>
<property name="eclipselink.ddl-generation" value="none"/>
<property name="eclipselink.jdbc.timeout" value="20"/>
<property name="eclipselink.jdbc.connections.wait-timeout" value="20"/>
<property name="javax.persistence.query.timeout" value="20"/>
<property name="eclipselink.allow-zero-id" value="true"/>
</properties>
Here is my edited class
public class WWWJpaController {
public WWWWJpaController() {
emf = Persistence.createEntityManagerFactory("properties");
}
public WWWWJpaController(String unitName) {
emf = Persistence.createEntityManagerFactory(unitName);
}
private EntityManagerFactory emf = null;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public List<WWW> find(String url) {
EntityManager em = getEntityManager();
try {
Query q = em.createNamedQuery("WWW.find");
q.setParameter("url", url);
return q.getResultList();
}finally{
em.close();
}
}
}
My guess is your database connection has timed out, or your database is down.
You may need to retry the query, or re-connect your session.
How have you configured your connection pooling and what database are you using?
Maybe your aplication server is not able to reconnect to the database, as BalusC pointed out in his comment, this happens every time the backup's done.
You can make your server reconnect as pointed in this link for Jboss

Simple local JPA2HBase App with DataNucleus

I want to build a minimalistic local app that reads/writes HBase via JPA2 without orm.xml and without maven2.
Thereby I use Eclipse with the DataNucleus Plugin whose Enhancer is enabled for the project.
Inspired by
http://matthiaswessendorf.wordpress.com/2010/03/17/apache-hadoop-hbase-plays-nice-with-jpa/
I got the following Entities:
#Entity
#Table(name="account_table")
public class Account
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;
String firstName = null;
String lastName = null;
int level = 0;
#Embedded
Login login = null;
public Account() { }
public Account(String firstName, String lastName, int level, Login login) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.level = level;
this.login = login;
}
and
#Embeddable
public class Login
{
private String login = null;
private String password = null;
public Login() {
// TODO Auto-generated constructor stub
}
public Login(String login, String password) {
super();
this.login = login;
this.password = password;
}
}
The src/META-INF/persistence.xml
<persistence
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="hbase-addressbook"
transaction-type="RESOURCE_LOCAL">
<class>de.syrtec.jpa2hbase.entities.Login</class>
<class>de.syrtec.jpa2hbase.entities.Account</class>
<properties>
<property name="datanucleus.ConnectionURL" value="hbase" />
<property name="datanucleus.ConnectionUserName" value="" />
<property name="datanucleus.ConnectionPassword" value="" />
<property name="datanucleus.autoCreateSchema" value="true" />
<property name="datanucleus.validateTables" value="false" />
<property name="datanucleus.Optimistic" value="false" />
<property name="datanucleus.validateConstraints" value="false" />
</properties>
</persistence-unit>
</persistence>
the DAO:
public class TestDAO {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hbase-addressbook");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
Account a1 = new Account("myPre", "mySur", 1, new Login("a", "b"));
tx = em.getTransaction();
tx.begin();
em.persist(a1);
tx.commit();
}
}
But when first line of the test DAO is executed...
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hbase-addressbook");
..I get:
11/09/01 06:57:05 INFO DataNucleus.MetaData: Class "de.syrtec.jpa2hbase.entities.Account" has been specified with JPA annotations so using those.
11/09/01 06:57:05 INFO DataNucleus.MetaData: Class "de.syrtec.jpa2hbase.entities.Login" has been specified with JPA annotations so using those.
Exception in thread "main" javax.persistence.PersistenceException: Explicit persistence provider error(s) occurred for "hbase-addressbook" after trying the following discovered implementations: org.datanucleus.api.jpa.PersistenceProviderImpl from provider: org.datanucleus.api.jpa.PersistenceProviderImpl
at javax.persistence.Persistence.createPersistenceException(Persistence.java:242)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:184)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:70)
at de.syrtec.jpa2hbase.start.TestDAO.main(TestDAO.java:15)
Caused by: org.datanucleus.exceptions.NucleusUserException: Errors were encountered when loading the MetaData for the persistence-unit "hbase-addressbook". See the nested exceptions for details
at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:879)
at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialiseNucleusContext(JPAEntityManagerFactory.java:745)
at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:422)
at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:150)
... 2 more
Caused by: org.datanucleus.exceptions.ClassNotResolvedException: Class "−
de.syrtec.jpa2hbase.entities.Login" was not found in the CLASSPATH. Please check your specification and your CLASSPATH.
at org.datanucleus.JDOClassLoaderResolver.classForName(JDOClassLoaderResolver.java:247)
at org.datanucleus.JDOClassLoaderResolver.classForName(JDOClassLoaderResolver.java:412)
at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:859)
... 6 more
Before I ran the DAO I triggered class enhancing by datanucleus succesfully:
DataNucleus Enhancer (version 3.0.0.release) : Enhancement of classes
DataNucleus Enhancer completed with success for 2 classes. Timings : input=623 ms, enhance=101 ms, total=724 ms. Consult the log for full details
Although I don't understand that enhancing isn't triggered automatically (referring to the logs) despite of having auto-enhancement for the project activated..
Does anybody know why my entities aren't found?
And that minus sign in persistence.xml ?