I have a need to persist(insert) a entity to database immediately when the save (or saveAndFlush) code is called.
However although the entity is created in the context it is not persisted in the database immediately.
We are using Spring Boot.
public interface MessageRepository extends JpaRepository<MessageEntity, Long> {
}
In the Service class
#Service
public class TestService {
#Autowired
private MessageRepository messageRepository;
#Transactional
public MessageEntity saveMessage(MessageEntity entity) throws Exception {
entity = messageRepository.saveAndFlush(entity);
return entity;
}
}
Though the entity is created it is not persisted/committed to the database immediately.
We are facing this issue within the Activiti Tasks only.
Any feedback will be appreciated.
This worked.
#Component
public class MessageRepositoryCustomImpl implements MessageRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public MessageEntity saveImmediate(MessageEntity entity) {
entityManager.persist(entity);
return entity;
}
}
One way of overcoming this situation is by taking advantage of the REQUIRES_NEW transaction attribute.
In your situation you would have to create a new repository:
public interface MessageRepositoryCustom{
void saveAndFLush(MessageEntity ent);
}
public MessageRepositoryCustomImpl implements MessageRepositoryCustom{
#Autowired
private SessionFactory sessionFactory;
#Transactional(propagation = Propagation.REQUIRES_NEW)
void saveAndFLush(MessageEntity ent){
Session session = sessionFactory.getCurrentSession();
session.persist(ent);
}
}
Then in your service you would use that repository:
#Transactional
public MessageEntity saveMessage(MessageEntity entity) throws Exception {
entity = messageRepositoryCutom.saveAndFlush(entity);
// other processing
return entity;
}
}
Now after the messageRepositoryCutom.saveAndFlush method has finished processing the entity will be physically persisted in the database as it was created in a separate transaction which has been commited.
Related
I am using the Spring Data JPA Repository methods deleteAll() and saveAll(List) in 2 different methods and transactions in a service class. The saveAll(List) method is called to repopulate the table after the deleteAll() call, but I keep getting an org.hibernate.ObjectDeletedException: deleted instance passed to merge error.
#Service
ServiceClass
{
#Autowired MyRepository repository;
public void test()
{
List<myEntity> entities = new ArrayList<>();
//code to populate list
clearTable();
populateTable(entities);
}
#Modifying
#Transactional
private void clearTable()
{
repository.deleteAll();
}
#Modifying
#Transactional
private void populateTable(List<myEntity> entities)
{
repository.saveAll(entities);
}
}
//Repository class
public interface MyRepository extends CrudRepository<myEntity, Long>
{
}
The internal implementation of delete in CrudRepository is as
#Transactional
public void delete(T entity) {
Assert.notNull(entity, "The entity must not be null!");
em.remove(em.contains(entity) ? entity : em.merge(entity));
}
Before an entity removed, this entity must be manage state. We can use some of the function merge, find, etc. Note : After EntityManager is closed, all the entities of its will be detached.
So do a commit after you delete
i have created a Base entity interface with getId() method and implemented into
entities for doing crud operations on all entity save is works and
delete,update also work but retriving by id doesnt work i am not sure its
possible or not if possible then suggest or any other way.
this is base interface for all entities and getId() overrides in each entity
public interface DemoEntity extends Serializable {
public long getId();
}
this is an user entity
public class User implements Serializable,DemoEntity {
getter/setters
}
public class Subject implements Serializable,DemoEntity {
getter/setters
}
//this is modelmanager class for doing crud operations
public class ModelManager {
#Autowired
#PersistenceContext
private EntityManager em;
#Transactional
public void save(DemoEntity entity) {
em.persist(entity);
}
#Transactional
public DemoEntity getEntityById(long id) {
DemoEntity de=em.find(DemoEntity.class, id);
return de;
}
}
#Autowired <-- is not necessary
#PersistenceContext
private EntityManager em;
Your method would looks like better
#Transactional
public DemoEntity getEntityById(long id) {
return em.find(DemoEntity.class, id);
}
and on the top of the class you need to put an annotation like #Component #Repository
And finally you did not say what kind of error you got
We have set up the Spring Framework like this:
#Eager
public interface CatalogElementRepository extends PagingAndSortingRepository<CatalogElementEntity, Long> {
}
#Service
public class CatalogImpl implements CatalogManager {
#Inject
CatalogElementRepository catalogElementRepository;
#Override
public CatalogElement createCatalogElement(CatalogElementEntity catalogElement) {
return this.catalogElementRepository.save(catalogElement);
}
}
#Stateless
#Remote(CatalogManager.class)
public class CatalogManagerBean implements CatalogManager {
#Inject
CatalogManager delegate;
#Override
public CatalogElement createCatalogElement(CatalogElementEntity catalogElement) {
return this.delegate.createCatalogElement(catalogElement);
}
}
So whenever someone calls the method on the remote interface createCatalogElement, I'd assume the entity gets stored in the database. It does not (weirdly enough, findOne still returns the very same entity, but it can't be found via findByProperty).
Other questions said to add #Transactional, so I added #javax.transaction.Transactional and org.springframework.transaction.annotation.Transactional on the methods and classes to be on the safe side, nothing worked.
What could be the problem?
I don't see any configuration files for the Spring Framework, but it's a legacy project, so they might just be hidden very well.
For some reason using this class as a producer for the EntityManager helped:
public class SpringConfig {
#PersistenceUnit
EntityManagerFactory emf;
#PersistenceContext
EntityManager em;
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
return this.emf;
}
#Produces
public EntityManager createEntityManager() {
return this.em;
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
public void close(#Disposes EntityManager entityManager) {
entityManager.close();
}
}
I was reading a Java EE book recently, and apparently entity beans were recently removed from the EJB specification. You are supposed to use JPA instead. But I want entity beans!! What I am really looking for is a JPA persistent entity that is remotely accessible, like an EJB. Something like this:
#Entity
#Remote(MyEntityRemote.class)
#LocalBean
public class MyEntityEJB implements MyEntityRemote {
public void doSomething() {
// actually do something
}
}
Is this at all possible without removing the bean annotations and writing a session bean like this:
#Stateless
#Remote(StatelessInterfaceToMyEntityRemote.class)
#LocalBean
public class StatelessInterfaceToMyEntity implements StatelessInterfaceToMyEntityRemote {
public void doSomething(MyEntity entity) {
entity.doSomething();
}
}
If I understand you correctly it is possible
first you create an Entity:
#Entity
#Table('MyEntityTable')
public class MyEntity {...}
Then you create a session bean facade for the entity exposing through it any interfaces you may need
#Stateless //Facade is a seesion bean so it can be #Stateless or #Statefull for basic CRUD it shoud be #Stateless
public class EntityFacade extends AbstractFacade<MyEntity> {
#PersistenceContext(unitName = "MyPersistanceUnit") //remember to define it first
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
Now u can define any methods that work with your Entity class. Remember if you expose your entity via Remote Interfaces it will be in a detached state. So after updating you will first nee to use the merge(object) method of EntityManager
EDIT
Abstract facade is a concept that is used with JPA Entity, NetBeans in version 7.3 generates it for you automatically. It is used to define the most common operations on Entities so you dont have to repeat the code for every Entity. It goes like this
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
...
}
The function above do some basic CRUD operations without much effort. So extending the facade gives you the ability to have does operations defined you could say out of the box. Of course this just for basic configurations the Entity facade can use many entities and do some business logic before it persists anything. So in your case it would go like this:
public class EntityFacade extends AbstractFacade<MyEntity> {
#PersistenceContext(unitName = "MyPersistanceUnit") //remember to define it first
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public doSomething(MyEntity entity)
{
entity.get(...);
...
entity.set(...)
if(iWantToPesristIt)
edit(entity)
else
return;
}
}
I've encountered a problem I don't really understand - unless a method working with the DAO is annotated as #Transactional, the underlying database doesn't get updated. My app runs on JPA/Hibernate, Spring and Wicket. Why is that?
DAO:
#Repository(value = "userDao")
public class UserDaoJpa implements UserDao {
#PersistenceContext
private EntityManager em;
public User findById(Long id) {
return em.find(User.class, id);
}
public List findAll() {
Query query = em.createQuery("select e from User e");
return query.getResultList();
}
public User create(User user) {
em.persist(user);
return user;
}
public User update(User user) {
return em.merge(user);
}
public void delete(User user) {
user = em.merge(user);
em.remove(user);
}
}
Service:
#Service(value = "userManager")
public class UserManagerImpl implements UserManager {
#Autowired
UserDao dao;
public void setUserDao(UserDao dao) {
this.dao = dao;
}
public List getUsers() {
return dao.findAll();
}
public User getUser(String userId) {
return dao.findById(Long.valueOf(userId));
}
public void saveUser(User user) {
dao.update(user);
}
#Transactional
public void removeUser(User user) {
dao.delete(user);
}
}
In case I leave out the #Transactional annotation, the database doesn't get updated.
Well thats normal:
Every database manipulation in the CRUD Scheme needs it's transaction boundaries. Without those boundaries, nothing gets actually written in the DB.
A Transaction is a collection of DB Manipulations (inserts, Updates) whoich have all to be successfull or the whole action gets undone by the DB. That's why you have to tell Hibernate when a Transaction starts and ends, so hibernate can tell which actions have to be regardes as Units of Work. Without transaction boundaries the final commit to the database never happens.
hope that helped
Try to flush and commit.