JPA从数据库

时间:2016-06-13 23:09:52

标签: java jpa eclipselink jpa-2.1

我应该如何尽可能简单地管理创建,编辑和删除操作?

例如:

用户:

public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    ...

    // Item can't exist without user
    @OneToMany(cascade=CascadeType.ALL,mappedBy = "user",orphanRemoval=true)
    private Set<Item> items = new HashSet<Item>();

    public Set<Item> getItems() { return items; }

    public void addItem(Item item) {
        items.add(item);
    }

    public void removeItem(Item item) {
        if(!items.contains(item)) return;
        items.remove(item);
    }

    // Group can exist without a user
    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},mappedBy="users")
    private Set<Group> groups = new HashSet<Group>();

    public Set<Group> getGroups() { return groups; }

    public void setGroups(Set<Group> groups) { this.groups = groups; }

    public void addGroup(Group group) {
        groups.add(group);
    }

    publi void removeGroup(Group group) {
        if(!groups.contains(group)) return;
        groups.remove(group);
    }

    ...
}

组:

@Entity
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    ...

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "GroupToUser", joinColumns =
    @JoinColumn(name = "GroupId", referencedColumnName="Id"), inverseJoinColumns =
    @JoinColumn(name = "UserId", referencedColumnName="Id"))
    private Set<User> users = new HashSet<User>();

    public Set<User> getUsers() { return users; }

    public void setUsers(Set<User> users) { this.users = users; }

    public void addUser(User user) {
        user.addGroup(this);
    }

    publi void removeUser(User user) {
        if(!users.contains(user)) return;
        users.remove(user);
    }

    ...
}

项目:

@Entity
public class Item {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    ...

    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinColumn(name="UserId")
    private User user;

    public Set<User> getUser() { return user; }

    public void setUser(User user) {
        this.user = user;
    }

    publi void removeUser() {
        this.user = null;
    }

    ...
}

我正在使用jpa注释吗?

我应该在这写什么?

EntityManager em = getEntityManager();
em.getTransaction().begin();
???
em.getTransaction().commit();

我是否必须为删除/创建/编辑操作调用em.remove / persist / merge方法?

我应该何时在这些操作中使用javax.persistence.EntityManager.getReference方法?

4 个答案:

答案 0 :(得分:1)

Find()从持久化上下文的缓存中提供实体,或者如果不在那里,它将从数据库加载。

GetReference()不会立即加载实体。返回一个代理(某个对象,一个所谓的“代理”,带有用于加载实际实体的丰富方法)。所以它是在LazyLoading的帮助下实现的。

只有在需要/调用代理或其他持久性方法的属性时,代理才会从数据库中交互并加载实际实体。

例如:

User us = em.find(User.class, 70992);

类似地使用GetReference()。

 User us = em.getReference(User.class, 70922);

如果持久化上下文中未知用户标识的实体,则抛出EntityNotFoundException()。

当我不需要访问数据库状态时,我通常使用getReference方法(我的意思是getter方法)。只是改变状态(我的意思是设定方法)。

在上述情况下,如果我想在获得用户后更新用户的年龄:

setAge(age);

如果我调用find方法,JPA提供商,在幕后,将调用

SELECT NAME, AGE FROM USER WHERE USER_ID = ?

UPDATE USER SET AGE = ? WHERE USER_ID = ?

如果我调用getReference方法,JPA提供者将在幕后调用

UPDATE PERSON SET AGE = ? WHERE USER_ID = ?

因为当你调用getReference时,你会得到一个代理对象。

为了休息,我们必须像你说的那样使用删除,保持和合并

答案 1 :(得分:0)

我个人建议您阅读Repository Software PatternSingle Responsability Principle

我的想法是创建一个UserRepository,另一个类,比如Controller,在创建必要的对象并尝试持久化之后会转到该存储库。

应该像这样工作:

首先获取实体管理器和事务,然后尝试persist()实体。如果persist()方法检测到实体处于持久性状态,则会抛出PersistenceException。抓住它,获取新的交易并调用merge()方法。

答案 2 :(得分:0)

最简单的方法不是最好的方法。我认为最简单的方法就是这个(但是关于更新操作,你最好阅读更多关于JPQL namedQueries / orm.xml的信息):

@WebFilter("*.htm")
public class JPAFilter implements Filter {
    private static final EntityManagerFactory entityManagerFactory
        = Persistence.createEntityManagerFactory(/* yourprojectname */);
    private static final ThreadLocal<EntityManager> entityManagers
        = new ThreadLocal<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
            entityManagers.set(entityManagerFactory.createEntityManager());
        EntityManager entityManager = entityManagers.get();
        try {
            request.setCharacterEncoding("UTF-8");
            chain.doFilter(request, response);
        } finally {
            if (entityManager.getTransaction().isActive()) {
                entityManager.getTransaction().rollback();
            }
            entityManager.close();
            entityManagers.remove();
        }
    }

    public static EntityManager getEntityManager() {
        return entityManagers.get();
    }

    @Override
    public void destroy() {
        entityManagerFactory.close();
    }
}

----

abstract class AbstractDAO {
    protected EntityManager getEntityManager() {
        return JPAFilter.getEntityManager()
    }
}

----

public class UserDAO extends AbstractDAO {
    public void create(User user) {
        getEntityManager().persist(user);
    }

    public User read(long id) {
        return getEntityManager().find(User.class, id);
    }

    public void delete(long id) {
        if (user != null) {
            getEntityManager().remove(user);
        }
    }
}

----

abstract class AbstractService {
    private EntityManager getEntityManager() {
        return JPAFilter.getEntityManager();
    }

    protected void beginTransaction() {
        getEntityManager().getTransaction().begin();
    }

    protected void commit() {
        getEntityManager().getTransaction().commit();
    }

    protected void rollback() {
        getEntityManager().getTransaction().rollback();
    }
}

----

public class UserService extends AbstractService {
    private final UserDAO userDAO = new UserDAO();

    public void create(User user) {
        beginTransaction();
        userDAO.create(user);
        commit();
    }

    public User read(long id) {
        return userDAO.read(id)
    }

    public void delete(long id) {
        userDAO.delete(id);
    }
}

----

@WebServlet("/users.htm")
public class ManageUsersServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final String VIEW = "/WEB-INF/JSP/users.jsp";
    private final transient UserService userService = new UserService();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // here you do whatever you want using your userService methods.
    }
}

P.S。更新时不要忘记从数据库锁定记录(使用悲观锁或捕获乐观锁异常)。

如果您使用JPA&#34;搜索&#34; CRUD操作,您也可以找到很多相关信息。我找到的第一个教程就是这个:http://www.objectdb.com/java/jpa/persistence/crud

答案 3 :(得分:0)

  

我正在使用jpa注释吗?

乍一看,我只是质疑缺少@Version字段,这是EntityManager执行乐观锁定所必需的,这是防止丢失更新的标准安全措施,除非您使用可序列化的隔离级别(需要在许多数据库系统上进行特殊配置。)

  

我是否必须为删除/创建/编辑操作调用em.remove / persist / merge方法?

这是最简单,也是最好的方式。

  

我应该何时在这些操作中使用javax.persistence.EntityManager.getReference方法?

如果要在不从数据库加载数据的情况下引用实体,则

getReference非常有用。例如,您可以:

public void updateUser(Item item, int userId) {
    item.setUser(entityManager.getReference(User.class, userId)); // does not require a query
    entityManager.merge(item);
}
  

交易

如果抛出异常,您将要回滚事务,并在完成后关闭entityManager(在成功和失败的情况下)。

在相关的说明中,如果您的应用程序不是很小,您将要查看声明式事务管理,这样您就不必为每个操作编写代码。例如,在Spring中,您只需使用@Transactional对类进行注释,以便在调用方法时让Spring启动(并结束)事务。