Announcement Announcement Module
Collapse
No announcement yet.
Persistence problem with JPA+Hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Persistence problem with JPA+Hibernate

    I am fairly new to Spring and JPA. I am using Spring with JPA & Hibernate. I can create new enteries in the database and modify them. The software I am developing controls a automated CD production machine which has java libraries. The libraries call a status listener. It is in this listener that I am not able to write to the database. The changes made to the objects are not reflected in the database even when I call the flush() function of the entity manager.

    Any ideas what I am doing wrong?

    Here is the configuration:

    Code:
        <tx:annotation-driven/>
        <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
    
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
        <bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <!--<property name="loadTimeWeaver">
                <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
            </property>-->
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="database" value="MYSQL" />
                    <property name="showSql" value="false" />
                    <property name="generateDdl" value="false" />
                </bean>
            </property>
        </bean>
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://ubuntu-sdk.local:3306/shm_test?autoReconnect=true" />
            <property name="username" value="user" />
            <property name="password" value="password" />
        </bean>
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory"
    			ref="entityManagerFactory" />
            <property name="dataSource" ref="dataSource" />
        </bean>
    
    	<!-- Application bean defintions. -->
        <bean id="orderStateRepo" class="org.sthelensmedia.dao.OrderStateJpaRepository"/>
        <bean id="productOrderRepo" class="org.sthelensmedia.dao.ProductOrderJpaRepository" />
        <bean id="productionRepo" class="org.sthelensmedia.dao.ProductionJpaRepository" />
    
        <bean id="cdproducer" class="org.sthelensmedia.cdproducer.CDProducer">
            <property name="orderStateRepo" ref="orderStateRepo"/>
            <property name="productOrderRepo" ref="productOrderRepo"/>
            <property name="productionRepo" ref="productionRepo"/>
        </bean>
    This is the code for the production repository:

    Code:
    @Repository
    @Transactional
    public class ProductionJpaRepository implements ProductionRepository {
    
        private EntityManager entityManager;
        private static final Log logger = LogFactory.getLog(ProductOrderJpaRepository.class);
    
        @PersistenceContext
        public void setEntityManager(EntityManager entityManager) {
            this.entityManager = entityManager;
        }
    
        public void deleteProduction(Production production) {
            if (logger.isInfoEnabled()) {
                logger.info("Deleting " + production);
            }
            entityManager.remove(production);
        }
    
        public void persistProduction(Production production) {
            if (logger.isInfoEnabled()) {
                logger.info("Persisting " + production);
            }
            entityManager.persist(production);
    
        }
    
        public Production retrieveProductionById(Integer productionId) {
            if (logger.isInfoEnabled()) {
                logger.info("Retrieving order " + productionId);
            }
            return entityManager.find(Production.class, productionId);
        }
    
        @SuppressWarnings("unchecked")
        public List<Production> retrieveAllProductions() {
            Query q = entityManager.createNamedQuery("allProductions");
            return q.getResultList();
        }
    
        public void save() {
            entityManager.flush();
        }
    Here is an extract from the CDProducer code:
    The execute function works correctly, it is the code in the status listener sub class that does not update the database. Any ideas?

    Code:
    @Transactional
    public class CDProducer {
    
        ProductOrderRepository productOrderRepo;
        ProductionRepository productionRepo;
        OrderStateRepository orderStateRepo;
    
        public class ImageOrderStatusListener implements OrderStatusListener {
            Production production=null;
    
            Public ImageOrderStatusListner(Production production) {
                    this.production=production;
            }
    
            @Transactional
            public void onStatus(String receivedXmlOrderStatus) {
                boolean bProductOrder;
                String errMsg;
                String errCode;
                String state;
    
                // Replace the base URI in the XML string
                String xmlOrderStatus = resetDTD(receivedXmlOrderStatus);
                Document document = parseXML(xmlOrderStatus);
                // Check for the state of your order here, using an XML parser.
                // This code will run in a different thread from the one
                // that submitted the order
                if (document != null) {
                    state = getElementAtt(document, "Status", "State");
                    System.out.print("Imaging " + state.toLowerCase() + ": " +
                            getElementAtt(document, "Status", "PercentCompleted") + "% completed.\n");
                    production.setMessage("Imaging " + state.toLowerCase() + ": " +
                            getElementAtt(document, "Status", "PercentCompleted") + "% completed.");
                    productionRepo.save();
    
                    if (state.equals("COMPLETED")) {
                        String orderStr = order.createDataProductionOrder();
                        System.out.println(orderStr);
                        sendProductionOrder(orderStr, production);
                    }
                    errMsg = getElementAtt(document, "Status", "ErrorMessage");
                    errCode = getElementAtt(document, "Status", "ErrorCode");
    
                    if (errMsg.length() > 0 || (errCode.length() > 0 && errCode != "0")) {
                        System.out.println("Image Server Error Code: " + errCode + "; Error Message: " + errMsg);
                        production.setMessage("Image Server Error Code: " + errCode + "; Error Message: " + errMsg);
                        productionRepo.save();
                        //System.exit(1);
                    }
                }
            }
        }
    
    ...
    ...
    
        @Transactional
        public void execute() {
              ....
    
                    Production production = new Production();
                    production.setStartTime(new Date());
                   production.setOrderComponent(orderComponent);
                    productionRepo.persistProduction(production);
                    production.setMessage("initiated");
                    productionRepo.save();
              ...
    }

  • #2
    First to make one thing clear flushing isn't the same as committing! Flushing only synchronizes/issues the sql statements to the database nothing is committed!

    A few things with your code

    1) Your internal class ImageOrderStatusListener is probably not going to be scanned for @Transactional annotations (also it isn't a subclass it is an internal class!)
    2) You use multiple threads, transactions are thread bound
    3) You don't follow the best practice of programming to interfaces, CDProducer doesn't implement interfaces so you must use class proxying for transactions to work

    Comment

    Working...
    X