I m using glassfish v2 and persistence in a web application.
I m calling persistence codes using a normal java class file inside a web Application
I can select easily using this code: -
#PersistenceUnit
public EntityManagerFactory emf;
EntityManager em;
public List fname (String id) {
String fname = null;
List persons = null;
//private PersistenceManagerFactory persistenceManagerFactory;
try {
emf = Persistence.createEntityManagerFactory("WebApplicationSecurityPU");
em = emf.createEntityManager();
persons = em.createQuery("select r from Roleuser r").getResultList();
int i=0;
for (i=0;i<persons.size(); i++)
System.out.println("Testing n "+ i +" " + persons.get(i));
} catch(Exception e) {
System.out.println("" + e);
}
finally {
if(em != null) {
em.close();
}
}
return persons;
}
I want to update using JTA as the persistence.xml file has
transaction-type="JTA"
When i try using update using this code i get a nullPointerException without any traces in the log
#PersistenceUnit
public EntityManagerFactory emf;
EntityManager em;
Context context;
#Resource
private UserTransaction utx;
public List fname (String id) {
String fname = null;
List persons = null;
try {
emf = Persistence.createEntityManagerFactory("WebApplicationSecurityPU");
utx.begin();
em = emf.createEntityManager();
int m = em.createQuery("update Roleuser r set r.firstName = 'Jignesh I' where r.userID=9").executeUpdate();
utx.commit();
} catch(Exception e) {
System.out.println("" + e);
}
finally {
if(em != null) {
em.close();
}
}
return persons;
}
Any help
Thanks
Pradyut
Perhaps your bean isn't managed - i.e. it's not part of any context (spring, EJB). How are you creating your object?
You really should not call createEntityManager() - inject one using #PersistenceContext
You must be absolutely sure you need JTA before using it.
You seem to be using PersistenceUnit, but then re-assign the etm - I'd suggest drop both and see p2 above.
If you are not using any dependecy injection at all, then drop all the annotations, retain the current code, and type:
em.getTransaction().begin();
...
em.getTransaction().commit();
(and define RESOURCE_LOCAL in your persistence.xml. You really don't need JTA)
well the code should be without any nightmares...(atleast for me in glassfish)
with the persistence.xml having
<persistence-unit name="WebApplicationSecurityPU" transaction-type="RESOURCE_LOCAL">
the code
#PersistenceUnit
public EntityManagerFactory emf;
public EntityManager em;
public EntityManager getEm() {
emf = Persistence.createEntityManagerFactory("WebApplicationSecurityPU");
em = emf.createEntityManager();
return em;
}
public List fname (String id) {
String fname = null;
List persons = null;
try {
System.out.println("test");
em = this.getEm();
em.getTransaction().begin();
int m = em.createQuery("update Roleuser r set r.firstName = 'Jignesh H' where r.userID=9").executeUpdate();
em.getTransaction().commit();
} catch(Exception e) {
System.out.println("" + e);
}
finally {
if(em != null) {
em.close();
}
}
return persons;
}
Any improvements are welcome...(actually needed...)
(How to go about using #PersistenceContext)
Thanks
Pradyut
Your "normal" class is very likely not a managed component i.e. a class whose life cycle is managed by the container (like Servlets, Servlet Filters, JSP tag handlers, JSF Managed Beans, ...) and can't benefit from resource injection1.
So neither the UserTransaction nor the EntityManagerFactory are injected here, hence the NullPointerException.
Honestly, you should try to use a container managed EntityManager, this would make your code less messy. If you cannot get it injected, get it via a JNDI lookup. See the resource below.
1 Have a look at Web Tier to Go With Java EE 5: A Look at Resource Injection for a nice overview of what can be injected, and where.
Resources
How to use EntityManager API in web module
References
JPA 1.0 specification
Section 5.2 "Obtaining an Entity Manager"
Section 5.6 "Container-managed Persistence Contexts"
Related
I need to create an Entity Manager manually to support having multiple datasources. I've realised that by creating it manually (instead of autowiring it as when you have only one single datasource), I actually do need to set all the JPA properties manually too, including what are usually set with default values by Spring. This means all the JPA parameters I specified in application.yaml and what Spring normally set default values for have now to be loaded and set manually.
Is there anyway to create an Entity Manager manually but have it automatically use all the JPA properties in application.yaml?
Here's my code
public LocalContainerEntityManagerFactoryBean entityManager(EntityManagerFactoryBuilder builder, DataSource secondDataSource) {
Map<String, Object> props = new HashMap<>();
// Is there a way to not do this one by one for all of the default JPA properties and what I specified in application.yaml?
props.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
// props.put("prop1", "propvalue1");
// ...
return builder.dataSource(secondDataSource).packages(MyEntity.class).properties(props).build();
}
Let's say, you have a persistence-unit with the name myData
private EntityManager getEntityManager() {
EntityManagerFactory emf = null;
try {
emf = Persistence.createEntityManagerFactory("myData");
} catch (Exception e) {
log.warn("An Error has occurred while creating persistence layer", e);
}
if (emf != null) {
return emf.createEntityManager();
} else {
log.warn("An error has occurred while retrieving Entity Manager from Persistence factory");
return null;
}
}
And use like below
final EntityManager em = getEntityManager();
assert em != null;
EntityTransaction entityTransaction = em.getTransaction();
try {
entityTransaction.begin();
userList.stream().forEach(user -> {
em.merge(RestUtil.convertToDBUser(user));
});
entityTransaction.commit();
log.info("Completed data persistence ");
} catch (RuntimeException e) {
if (entityTransaction.isActive()) {
entityTransaction.rollback();
}
log.warn("An error has occurred while committing JDBC transaction. ", e);
throw e;
} finally {
em.close();
}
I am developing a web application, where, among other things, I need to upload a file to a BLOB column in a mysql table. From what I can see this can be done with JDBC calls (PrepareStatement() etc), but I would like to be able to do this in an EJB class - what I have cobbled together looks like this:
#Stateless
public class ItemsSession {
#PersistenceContext(unitName ="officePU")
private EntityManager em;
private List<Items> itl;
private static final Logger logger=
Logger.getLogger(ItemsSession.class.getName());
...
public String updateDocument(Integer id,InputStream is) throws SQLException{
String msg="";
try{
java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
PreparedStatement pstmt=conn.prepareStatement("UPDATE Documents SET doc = ? WHERE id = ?");
pstmt.setBinaryStream(1, is);
pstmt.setLong(2, id);
pstmt.executeUpdate();
pstmt.close();
}
catch (PersistenceException e){
msg=e.getMessage();
}
return msg;
}
...
}
I have two questions, though:
I would like not to use JDBC directly - is there a way to do this that is 'pure JPA' (edit: not EJB)?
If I have to do it this way, is the PreparedStatement included in the container managed transaction?
Another edit: the code above does the job - I have now tested it. But it isn't pretty, I think.
The first thing you have to do to persist BLOB values the JPA way is you define an entity. The following an example pseodo code:
#Entity
public class Documents {
#Id
private Long id;
#Lob
private byte[] doc;
// .... getters + setters
}
Then you modify your EJB as follows:
#Stateless
public class ItemsSession {
#PersistenceContext(unitName ="officePU")
private EntityManager em;
// ... the rest of your code
public String updateDocument(Integer id,InputStream is) throws SQLException{
String msg = "";
Documents docs = em.find(Documents.class, id); // fetch record from DB
// Assuming your InputStream is a ByteArrayInputStream
byte[] doc = new byte[is.available()]; // create target array
is.read(doc, 0, doc.length); // read bytes into byte array
docs.setDoc(doc); //
return msg; // returning exception message from method call?????
}
...
}
If you don't change the defaults EJB methods are invoked in a transaction by default. So when your method exits, the update should be synchronized with the database.
This answer kann only help you if you read and understand the basics of the JPA. And here is an official tutorial to JPA persistence among other lots of tutorials on the web.
Update
I would like not to use JDBC directly - is there a way to do this that is 'pure JPA'
No.
If I have to do it this way, is the PreparedStatement included in the container managed transaction?
No. But you can use bean managed transaction. If you want to use BMT, the following pseudocode might help you:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class ItemsSession {
#Resource UserTransaction ut;
#Resource DataSource datasource; // you should define datasource on your application server
...
public String updateDocument(Integer id,InputStream is) throws SQLException{
// ...
try (java.sql.Connection conn = datasource.getConnection();
PreparedStatement pstmt=conn.prepareStatement("UPDATE Documents SET doc = ? WHERE id = ?")) {
pstmt.setBinaryStream(1, is);
pstmt.setLong(2, id);
ut.begin();
pstmt.executeUpdate();
ut.commit();
} catch (PersistenceException e){
// ... error handling
}
return ...;
}
...
}
I think you use EJB intergate to with JPA , because you are using this:
#PersistenceContext(unitName ="officePU")
Refernce: http://www.adam-bien.com/roller/abien/entry/ejb_3_persistence_jpa_for
I am trying to write a method that bulk adds entities to the database. Here's my method:
#Transactional
protected void bulkInsert(List<?> entities) {
int batchSize = 25;
AtomicInteger i = new AtomicInteger(0);
try {
em.getTransaction().begin();
entities.parallelStream().forEach(e -> {
em.persist(e);
if ( i.get() > 0 && i.get() % batchSize == 0 ) {
em.flush();
em.clear();
}
i.incrementAndGet();
});
em.getTransaction().commit();
} catch (RuntimeException e) {
LOG.error("Error", e);
} finally {
if (em != null) {
em.close();
}
}
}
But when I run this I get the following error:
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:248) ~[spring-orm-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at com.sun.proxy.$Proxy145.getTransaction(Unknown Source) ~[na:na]
I tried removing the #Transactional annotation and still the same error. I tried using Session by doing Session session = em.unwrap(Session.class); but that still resulted in an error (although different error)
How do I bulk insert objects?
in pure hibernate exists managed- and non-managed environments
Non-managed environment
If an JPA persistence layer runs in a non-managed environment, database >connections are usually handled by Hibernate's pooling mechanism behind the >scenes. The common entity manager and transaction handling idiom looks like > this:
// Non-managed environment idiom
EntityManager em = emf.createEntityManager(); EntityTransaction tx =
null; try {
tx = em.getTransaction();
tx.begin();
// do some work
...
tx.commit(); } catch (RuntimeException e) {
if ( tx != null && tx.isActive() ) tx.rollback();
throw e; // or display error message } finally {
em.close(); }
Using JTA
If you use bean-managed transactions (BMT), the code will
look like this:
// BMT idiom
#Resource public UserTransaction utx;
#Resource public
EntityManagerFactory factory;
public void doBusiness() {
EntityManager em = factory.createEntityManager();
try {
// do some work
...
utx.commit(); } catch (RuntimeException e) {
if (utx != null) utx.rollback();
throw e; // or display error message
} finally {
em.close();
}
With Container Managed Transactions (CMT) in an EJB3 container, transaction >demarcation is done in session bean annotations
or deployment descriptors, not programatically. The EntityManager will
automatically be flushed on transaction completion (and if you have
injected or lookup the EntityManager, it will be also closed
automatically). If an exception occurs during the EntityManager use,
transaction rollback occurs automatically if you don't catch the
exception. Since EntityManager exceptions are RuntimeExceptions they
will rollback the transaction as per the EJB specification (system
exception vs. application exception).
you should follow on of two princeple.
annotation #Transactional it's spring annotaniot not hibernate. if you didn;t configued it (or you did configured spring) doen't work.
PC
An EntityManager is an inexpensive, non-threadsafe object that should
be used once, for a single business process
call em.flush() ,em.clear() might be dangerous .
In my web application, when a new user sign-up i need to create a new database in mysql for him. Example: root => db_root, admin => db_admin, user1 => db_user1 and so on. When the user logs into my app, I need to instance a new entityManager based on his new created database and manipulate data only on that db.
One problem is: how am i supposed to know which entityManager instance i should use for each user request. I thought about creating a
Hashmap<String, EntityManager>
save an attribute entityManagerKey on user's session and retrieve the right entityManager by this key. This approach brings along some troubles such as the right time to destroy a non-used entityManager. Moreover, i think it will take all server memory to work.
Though it's seems to be not a great idea, i did't realize another solution. I'm using JPA/Hibernate and Jersey. Any ideas will be appreciated, except creating only one database.
Thanks!
You can use the EntityManagerFactory and pass it the user and password
Map<String, String> properties = new HashMap<String, String>();
properties.put("javax.persistence.jdbc.user", "admin");
properties.put("javax.persistence.jdbc.password", "admin");
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
"some-jdbc-url", properties);
EntityManager entityManager = emf.createEntityManager();
If you think performance is an issue, you can cache the entityManager. Depending on how much traffic you have on your application and the available resources, you can determine the number of cached connections. I wouldn't bother with caching in the beginning, because creating a DB connection is usually not that time consuming, compared to a web request.
Here is the sample code,
private static final Map<String, EntityManagerFactory> ENTITY_FACTORIES = new HashMap<String, EntityManagerFactory>();
public void onStart() {
this.buildEntityManagerFactories();
}
#Override
public void onStop() {
closeEMFactories();
}
private void closeEMFactories() {
try {
if(ENTITY_FACTORIES.size() > 0) {
for(Entry<String, EntityManagerFactory> entityFactoryMgr : ENTITY_FACTORIES.entrySet()) {
EntityManagerFactory entityManagerFactory = entityFactoryMgr.getValue();
if(entityManagerFactory.isOpen()) {
entityManagerFactory.close();
}
}
isLoaded = false;
}
} catch (Exception e) {
Logger.error("Error while shutting down the datasource plugin", e);
}
}
/**
* Create the entityManagerFactory Bean.
* #return entityManagerFactory Bean
*/
public void buildEntityManagerFactories(String userName) {
buildEMFactory(userName, DEFAULT_PERSISTENCE_UNIT);
}
private void buildEMFactory(String userName, String persistenceUnitName) {
if(!isLoaded) {
try{
ENTITY_FACTORIES.put(userName, Persistence.createEntityManagerFactory(persistenceUnitName, XOAPP_DB_PROPERTIES));
}catch(Exception e) {
Logger.error("Error while building the entity manager factory for the persistence unit :" + persistenceUnitName, e);
}
}
}
public EntityManager em(String persistenceName) {
EntityManagerFactory entityManagerFactory = ENTITY_FACTORIES.get(persistenceName);
if(entityManagerFactory != null) {
return entityManagerFactory.createEntityManager();
}
return null;
}
/**
* Get the entityManagerFactory Bean.
* #return entityManagerFactory Bean
*/
public EntityManagerFactory getEntityManagerFactory(String userName) {
EntityManagerFactory entityManagerFactory = ENTITY_FACTORIES.get(userName);
if(entityManagerFactory == null) {
buildEMFactory(userName);
entityManagerFactory = ENTITY_FACTORIES.get(userName);
}
return entityManagerFactory;
}
I have the following java class to connect and query MySQL database using JPA:
public class UserEntityManager {
private EntityManagerFactory emf;
private EntityManager em;
private EntityTransaction tx;
public UserEntityManager() {
emf = Persistence.createEntityManagerFactory("OmegaThingsPU");
em = emf.createEntityManager();
tx = em.getTransaction();
}
public User getUser(String username, String password) {
Query query = em.createQuery("SELECT u FROM User u "
+ "WHERE u.userUsername = :userUsername "
+ "AND u.userPassword = :userPassword");
query.setParameter("userUsername", username);
query.setParameter("userPassword", password);
User user;
try {
user = (User) query.getSingleResult();
em.close();
emf.close();
return user;
} catch (Exception ex) {
System.out.println("Exception ****************** ");
System.out.println(ex.toString());
em.close();
emf.close();
return null;
}
}
}
I'm always getting this exception:
java.lang.ClassCastException: com.omegathings.persistant.User cannot be cast to com.omegathings.persistant.User
I tried getResultList().get(0), but it didn't work also, what I'm missing here?
UPDATE:
Restarting the glassfish server (Version 4.1) will solve the problem temporary, but then on modifying the code and redeploying the application, I'm getting the exception again.
UPDATE:
It seems that on redeploying the application I'm getting 2 different class loaders as the following:
WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)
WebappClassLoader (delegate=true)
UPDATE:
Printing out the parent of the 2 above classloaders results in the following:
org.glassfish.internal.api.DelegatingClassLoader#5b11b82d
org.glassfish.internal.api.DelegatingClassLoader#5b11b82d
As you can see, at first deployment, the Ids are identical.
Now on the second deployment I got:
org.glassfish.internal.api.DelegatingClassLoader#57c83b1d
org.glassfish.internal.api.DelegatingClassLoader#5b11b82d
Where 2 parents have a different Ids, I'm not sure if this will help in solving my problem.
Finally I figure out the problem after many, many tests....
The problem is in the following websocket code:
#ServerEndpoint("/endpoint/{authentication}")
public class WSManager {
UserEntityManager userEntityManager = new UserEntityManager();
#OnOpen
public void onOpen(Session session, #PathParam("authentication") String authString) {
User user = new User();
user = (User) userEntityManager.getUser(parameter[0]);}
The problem is instantiating UserEntityManager class outside any of the following websocket class methods (onOpen, onMessage, onError, onClose).
Just moving the instantiation inside onOpen method will solve the problem.
I can't elaborate on the reason of such behavior, so, may some experts do.