【问题标题】:How do I prevent EclipseLink (JPA 2.0) from clearing my database/table?如何防止 EclipseLink (JPA 2.0) 清除我的数据库/表?
【发布时间】:2011-08-28 05:28:25
【问题描述】:

我在 Netbeans 7.0 上使用带有 MySQL 数据库的 EclipseLink (JPA 2.0) - 我根据 this screencast 进行配置。但是有时当我持久化一个对象/实体时,我的表会在该对象持久化之前被清除,并且我得到一个只有这个对象的表(就像它已被清除一样)。我只是简单地在(填充)数据库中添加新条目。

如何防止这种情况发生?

这是我的代码:

Movie movie = new Movie(
    jsondata.path("Title").getTextValue(),
    jsondata.path("Year").getValueAsInt(),
    jsondata.path("Genre").getTextValue(),
    jsondata.path("Plot").getTextValue(),
    jsondata.path("Poster").getTextValue());
persist(movie);

我的 persist() 函数:

public static void persist(Object object) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("AllmoviesPU");
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    try {
        em.persist(object);
        em.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
        em.getTransaction().rollback();
    }
    em.close();
}

我的电影对象/实体:

@Entity
public class Movie implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    @Column(name="MOVIEYEAR")
    private int year;
    private String genre;
    private String synopsis;
    private String image;

    public Movie(String title, int year, String genre, String synopsis, String image) {
        this.title = title;
        this.year = year;
        this.genre = genre;
        this.synopsis = synopsis;
        this.image = image;
    }

    public Movie() {
    }

    /* ... Getters and Setters stuff ... */

}

我的persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="AllmoviesPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>allmovies.data.Movie</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://123.123.123.123:3306/psanta_allmovies"/>
      <property name="javax.persistence.jdbc.password" value="XXXXXX"/>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.user" value="psanta_allmovies"/>
    </properties>
  </persistence-unit>
</persistence>

【问题讨论】:

  • 您之前在其他地方发布过这个问题吗?完成(工作!!)数据库登录设置en public?不就是一些小丑不时地截断你的桌子吗?尝试更改您的密码,不要在万维网上发布数据库连接详细信息...

标签: java mysql jpa persistence eclipselink


【解决方案1】:

尝试打开记录到 FINEST 或 FINE 以查看发生了什么。 ("eclipselink.logging.level"="finest")。

EclipseLink 确实有一个在启动时重新创建表的选项(“eclipselink.ddl-generation”=“drop-and-create-tables”),请确保您没有使用它。 NetBeans 或 Glassfish 可能会默认设置此设置,我认为他们可能会在开发模式下执行此操作。

【讨论】:

    【解决方案2】:

    您的代码中有很多事情需要解决,尽管我不能保证它们与您的问题有关。

    第一件事是,每次您只想持久化实体时都创建实体管理器工厂和实体管理器太昂贵了。此外,您不会关闭实体管理器工厂。

    正确的做法是创建一个实体管理器工厂,并使其在应用程序的整个生命周期内都可用。每次您开始与用户对话(即事务)然后向其请求实体管理器时,使用它来持久化您想要持久化的所有内容,然后关闭实体管理器。

    当您的应用程序完成后,关闭实体管理器工厂。

    您可能需要考虑的第二个方面是某些异常已经意味着回滚,例如,在提交执行期间抛出的任何异常。因此,如果您尝试第二次回滚,那么您将获得第二个您未处理的异常。

    我不能保证这些更改会解决您的问题,但它们肯定是一个好的开始。

    话虽这么说,但从您的代码中,我并没有明显看出您在其中保留了多个实体。我想,需要更多的上下文。

    我建议有点像这样:

    public class DataAccessLayer {
    
        private EntityManagerFactory emf;
    
        public DataAccessLayer (){
        }
    
        public synchronized void start(){
           if(isStarted())
             throw new IllegalStateException("Already started");
           this.emf = Persistence.createEntityManagerFactory("AllmoviesPU");
        }
    
        public synchronized void stop(){
           if(!isStarted())
             throw new IllegalStateException("Not started");
           this.emf.close();
           this.emf = null;
        }
    
       public synchronized boolean isStarted(){
         return this.emf != null;
       }
    
        public void doPersistenceStuff(InputData o){
                if(!isStarted())
                  throw new IllegalStateException("Not started");
            EntityManager em = emf.getEntityManager();
            EntityTransaction t = entityManager.getTransaction();
            try {
                t.begin();
                //do persistence stuff here
                t.commit();
            }
            catch (RollbackException e) {
                //transaction already rolledback
                throw new MyPersistenceException(e);
            }
            catch (Exception e) {
                t.rollback(); //manual rollback
                throw new MyPersistenceException(e);
            }
            em.close()
        }
    }
    

    并且您可以通过在数据访问层实例中调用 stop() 方法来确保在应用程序完成时(例如当用户单击退出按钮,或者当您的服务器停止或关闭时)关闭 emf。

    【讨论】:

    • 当我想持久化另一个实体/对象时,请考虑运行相同的代码。好的,感谢工厂提示。我会试试的。
    • 我现在在出口关闭工厂时运行代码,行为是相同的:有时会清除表格。
    • 请澄清一下,您是在创建全局实体管理器工厂,还是在每次坚持时仍在创建实体管理器工厂?为您的应用程序创建一个实体管理器工厂并在每次想要持久化时重用它,而不是每次都创建一个新的,这一点至关重要。
    • 正如你所说,我正在创建一个全局工厂,当我退出程序时我会关闭它 - 一个控制台应用程序。但问题依然存在。
    • @pedrosante 你能从你实际调用persist方法的地方用更多上下文代码更新你的帖子吗?我也更新了我的帖子,提出了更多建议。
    猜你喜欢
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 2022-12-14
    • 2016-03-30
    • 2020-01-21
    • 2014-01-08
    • 1970-01-01
    相关资源
    最近更新 更多