JavaEE JPA返回旧数据的版本

时间:2015-11-30 00:28:26

标签: java hibernate jpa intellij-idea

我们正在使用JPA构建REST应用程序,但我们无法正常工作。

问题是,在进行更新或添加项目时,jpa选择开始返回更改的多个版本。例如,如果Item包含A并且更改为B然后更改为C,则选择查询将返回第一次运行,B秒,C第三次,第四次等等。有时它不会直接显示但是在浏览器上按住f5以获取GET项目资源然后更改数据总会产生此问题。

我创建了一个干净的示例项目来演示这一点。我们使用Glassfish 4.1.0(因为4.1.1中存在其他问题)。

  1. 创建了mysql数据库'testdb'创建了一个包含两个VARCHAR(45)字段'firstName'和'lastName'的表'item'。
  2. 基于'javaee7-essentials-acrhetype'创建了一个新的maven项目。 (https://github.com/AdamBien/javaee7-essentials-archetype
  3. 在intellij中添加了数据源,并为此Item实体生成了一个Entity bean。调整后的persistence.xml以包含用户名和密码。
  4. 创建了一个简单的DTO / Pojo类来接收PUT数据。
  5. 创建了一个ItemResource类。
  6. 总共4个类和persistence.xml + pom.xml

    的pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>test.server</groupId>
        <artifactId>testdb</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>4.3.11.Final</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.37</version>
            </dependency>
    
        </dependencies>
        <build>
            <finalName>testdb</finalName>
        </build>
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </properties>
    </project>
    

    的persistence.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
        <persistence-unit name="LocalUnit">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <class>test.server.entities.ItemEntity</class>
            <properties>
                <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/testdb"/>
                <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
                <property name="hibernate.connection.username" value="root" />
                <property name="hibernate.connection.password" value="abc123" />
                <property name="hibernate.archive.autodetection" value="class"/>
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.format_sql" value="true"/>
                <property name="hbm2ddl.auto" value="update"/>
            </properties>
        </persistence-unit>
    </persistence>
    

    ItemDTO

    public class ItemDTO {
        private String firstName;
        private String lastName;
    
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    }
    

    ItemEntity bean(手动添加namedqueries)

    @Entity
    @NamedQueries({
            @NamedQuery(name = "Item.All", query = "SELECT item from ItemEntity item"),
            @NamedQuery(name = "Item.Get", query = "SELECT item from ItemEntity item WHERE item.id = :id")
    })
    @Table(name = "item", schema = "testdb", catalog = "")
    public class ItemEntity {
        private Integer id;
        private String firstName;
        private String lastName;
    
        @Id
        @Column(name = "id")
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        @Basic
        @Column(name = "firstName")
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        @Basic
        @Column(name = "lastName")
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            ItemEntity that = (ItemEntity) o;
    
            if (id != null ? !id.equals(that.id) : that.id != null) return false;
            if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null) return false;
            if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null) return false;
    
            return true;
        }
    
        @Override
        public int hashCode() {
            int result = id != null ? id.hashCode() : 0;
            result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
            result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
            return result;
        }
    }
    

    ItemResources类

    @Path("items")
    public class ItemResources {
    
        private static EntityManagerFactory emf = null;
    
        public ItemResources() {
            if(emf == null) {
                emf = Persistence.createEntityManagerFactory("LocalUnit");
            }
        }
    
        public EntityManager getEntityManager() {
            return emf.createEntityManager();
        }
    
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getAllAccounts() {
            EntityManager manager = getEntityManager();
            Collection<ItemEntity> accounts = null;
            try {
                accounts = manager.createNamedQuery("Item.All").getResultList();
            } catch(Exception e) {
                throw new RuntimeException(e);
            } finally {
                manager.close();
            }
            return Response.ok().entity(new GenericEntity<Collection<ItemEntity>>(accounts) {}).build();
        }
    
        @PUT
        @Path("{id}")
        @Consumes(MediaType.APPLICATION_JSON)
        public Response updateAccount(@PathParam("id") int id, ItemDTO itemDTO) {
            EntityManager manager = getEntityManager();
            try {
                manager.getTransaction().begin();
                TypedQuery<ItemEntity> query = manager.createNamedQuery("Item.Get", ItemEntity.class);
                query.setParameter("id", id);
                ItemEntity account = query.getSingleResult();
                account.setFirstName(itemDTO.getFirstName());
                account.setLastName(itemDTO.getLastName());
                manager.getTransaction().commit();
            } catch(Exception e) {
                manager.getTransaction().rollback();
                throw new RuntimeException(e);
            } finally {
                manager.close();
            }
    
            return Response.ok().entity("OK").build();
        }
    }
    

    主应用程序类(没有web.xml,空beans.xml)

    @ApplicationPath("resources")
    public class JAXRSConfiguration extends Application {
    
    }
    

    总结这个不行。在开始时描述的问题发生,这使得它不可能用于任何真实的东西。我们在这里遗漏了什么,这个简单的例子不适用吗?

    我们有一个真正的应用程序包含这个问题,我们有时间试图找出它的行为。我们尝试了不同的方法来清除缓存,驱逐工厂,尝试更改连接隔离,在persistence.xml中禁用2ndlevel和查询缓存,但最终仍然遇到相同的问题或交易更严重的数据库问题。尝试运行相同glassfish版本的两个不同服务器。因此,如果我们必须回滚到纯jdbc / sql以使其正常工作,我们就处于这一点。

    然而奇怪的是,我还没有能够在intellij中部署时再现这个问题。但是,在我们尝试过的任何服务器上部署.war文件时,问题出现了。但是当正式解复时,似乎使其工作的唯一方法是为每个请求创建一个新的fctory实例,然后在完成时关闭它。这似乎非常浪费。

    如果有人能帮助我们解决这个问题,从而避免很多重构,那么我们将永远是伟大的:)我们是否遗漏了一些必要的重要工作?

0 个答案:

没有答案