persistence@glassfish.java.net

row updates outside of JPA not reflected in JPA

From: Girish Kumar Balachandran <Girish.Balachandran_at_Sun.COM>
Date: Tue, 15 Jan 2008 21:18:18 -0800

(Not sure if this is the right alias to ask this question. If not please
forward to the right alias.)

Modifications to a row that are directly made on the DB externally via
SQL does not seem to reflect in the JPA returned objects. New row
additions are recognized though. Is this something that JPA supports or
is it a bug?

I have attached a simple program that demonstrates the scenario. I
created this program in netbeans. Run the following table creation SQL
statement first to the DB connection:

CREATE TABLE VIR.GIRISH(
    ID BIGINT generated always as identity NOT NULL,
    STRING VARCHAR(20),
    VERSION INT DEFAULT 0,
    CONSTRAINT PRINCIPAL_PK PRIMARY KEY (ID)
);

Then compile and run the program. While it is running execute:

 UPDATE VIR.GIRISH SET STRING = 'modified', VERSION=2 WHERE ID = 1;

and observe that the output of the program does not get the changes.
Restarting the program will get the changes though.

Is there a special thing I need to do to cover this usecase? I wonder
how clustered environments use JPA if this is not supported inherently.


Thanks,
-Girish




import java.io.UnsupportedEncodingException;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

/**
 *
 * @author girix
 */
public class JPATester {
        
        private static HashMap properties;
        
        private static String jdbcURL;
        
        private static String dbDriver;
        
        private static EntityManagerFactory emf;
        
        private static EntityManager em;
        
        /** Creates a new instance of Main */
        public JPATester() {
        }
        
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) throws SQLException, UnsupportedEncodingException, InterruptedException {
                DriverManager.registerDriver(new org.apache.derby.jdbc.ClientDriver());
                
                properties = new HashMap<String,String>();
                jdbcURL = "jdbc:derby://localhost:1527/vir";
                dbDriver = "org.apache.derby.jdbc.ClientDriver";
                
                properties.put("toplink.jdbc.user","app");
                properties.put("toplink.jdbc.password","app");
                properties.put("toplink.jdbc.url",jdbcURL);
                properties.put("toplink.jdbc.driver",dbDriver);
                properties.put("toplink.logging.level","FINE");
                
                emf = Persistence.createEntityManagerFactory("ScratchpadProjectPU", properties);
                
                
                em = emf.createEntityManager();
                
                DbGirish girish = new DbGirish();
                girish.setString("kumar");
                
                em.getTransaction().begin();
                em.persist(girish);
                em.getTransaction().commit();
                
                
                int j = 0;
                while(true){
                        //re-creating a new EMF also does not solve the problem.
                        //emf = Persistence.createEntityManagerFactory("ScratchpadProjectPU", properties);
                        //creating a new EM also does not help
                        //em = emf.createEntityManager();
                        Query q = em.createQuery("SELECT girish FROM DbGirish girish");
                        Thread.sleep(3000);
                        System.out.println("\n\nIteration number:"+j++);
                        List<DbGirish> lis = q.getResultList();
                        int i = 0;
                        for(DbGirish gir : lis){
                                System.out.println(i+". Entry ID:"+gir.getId()+" String:"+
                                                gir.getString()+" Version:"+gir.getVersion());
                                i++;
                        }
                        em.close();
                }
        
        }
}





import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Version;

/**
 *
 * @author girix
 */
@Entity
@Table(name = "VIR.GIRISH")
@NamedQueries({_at_NamedQuery(name = "DbGirish.findById", query = "SELECT d FROM DbGirish d WHERE d.id = :id"), @NamedQuery(name = "DbGirish.findByString", query = "SELECT d FROM DbGirish d WHERE d.string = :string"), @NamedQuery(name = "DbGirish.findByVersion", query = "SELECT d FROM DbGirish d WHERE d.version = :version")})
public class DbGirish implements Serializable {
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name = "ID", nullable = false)
        private Long id;
        @Column(name = "STRING")
        private String string;
        @Version
        @Column(name = "VERSION")
        private Integer version;

        public DbGirish() {
        }

        public DbGirish(Long id) {
                this.id = id;
        }

        public Long getId() {
                return id;
        }

        public void setId(Long id) {
                this.id = id;
        }

        public String getString() {
                return string;
        }

        public void setString(String string) {
                this.string = string;
        }

        public Integer getVersion() {
                return version;
        }

        public void setVersion(Integer version) {
                this.version = version;
        }

        @Override
        public int hashCode() {
                int hash = 0;
                hash += (id != null ? id.hashCode() : 0);
                return hash;
        }

        @Override
        public boolean equals(Object object) {
                // TODO: Warning - this method won't work in the case the id fields are not set
                if (!(object instanceof DbGirish)) {
                        return false;
                }
                DbGirish other = (DbGirish) object;
                if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
                        return false;
                }
                return true;
        }

        @Override
        public String toString() {
                return "grt.DbGirish[id=" + id + "]";
        }

}