用Spring和JPA(Hibernate)更新DB的正确方法是什么

时间:2014-05-15 09:15:54

标签: spring hibernate jpa

我有两个模特课程:

package com.me.model;

import java.util.Objects;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;


@Entity
public class Post {

    private Integer id;
    private String text;
    private Person person;

    @Id
    @GeneratedValue
    @Column(name = "ID")
    public Integer getId() {
        return id;
    }

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

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    @ManyToOne(cascade = {CascadeType.ALL})
    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return String.format("\nThe id of a post is: %d, written by person %s, containing a text: %s\n", this.id, this.person.toString(), this.text);
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 89 * hash + Objects.hashCode(this.id);
        hash = 89 * hash + Objects.hashCode(this.text);
        hash = 89 * hash + Objects.hashCode(this.person);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Post other = (Post) obj;
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        if (!Objects.equals(this.text, other.text)) {
            return false;
        }
        if (!Objects.equals(this.person, other.person)) {
            return false;
        }
        return true;
    }

}


package com.me.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "PERSON")
public class Person implements Serializable {

    private Integer id;
    private String name;
    private String email;
    private List<Post> posts;

    @OneToMany(mappedBy = "person", fetch = FetchType.EAGER,
            cascade = {CascadeType.ALL})
    public List<Post> getPosts() {
        return posts;
    }

    public void setPosts(List<Post> posts) {
        this.posts = posts;
    }

    public void addPost(Post post) {
        post.setPerson(this);
        if (posts == null) {
            posts = new ArrayList<Post>();
        }
        posts.add(post);
    }

    @Id
    @GeneratedValue
    @Column(name = "ID")
    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", email=" + email + ", no of posts: " + this.posts.size() + "]";
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 17 * hash + Objects.hashCode(this.id);
        hash = 17 * hash + Objects.hashCode(this.name);
        hash = 17 * hash + Objects.hashCode(this.email);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Person other = (Person) obj;
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        if (!Objects.equals(this.email, other.email)) {
            return false;
        }
        return true;
    }

}

和测试类:

public static final Logger log = Logger.getLogger(Main.class.getName());

    public static void main(String[] args) {
        log.info("************** BEGINNING PROGRAM **************");

        ApplicationContext context = new ClassPathXmlApplicationContext("WEB-INF/spring-config.xml");
        PersonService personService = (PersonService) context.getBean("personService");
        PostService postService = (PostService) context.getBean("postService");

        Person person = new Person();
        person.setName("me");
        person.setEmail("me@box.com");

        Post post = new Post();
        String text = "bbbbbbbbbbbbbbbbbbbbbbbbb";
        post.setText(text);

        Person personFromDB = personService.getPersonFromDB(person.getName(), person.getEmail());
        if (personFromDB == null) {
            log.info("No person in DB!! ");
            person.addPost(post);
            personService.addPerson(person);
        } else {
            log.info("Person " + personFromDB + " is being found in DB!");
//            personService.getPersonDao().getEntityManager().detach(personFromDB);
            personFromDB.addPost(post);


 //            personService.addPerson(personFromDB);
            personService.updatePerson(personFromDB);
        }

        List<Person> persons = personService.fetchAllPersons();
        log.info("\nThe list of all persons = " + persons);

        List<Post> posts = postService.fetchAllPosts();
        log.info("\nThe list of all posts = " + posts);

        log.info("************** ENDING PROGRAM *****************");
    }

andocourse DAO和Service类(由Spring注入的entityManager)。 现在我想从DB更新一个人物对象(在添加另一个帖子之后)。在调试程序时,我可以看到添加到arraylist的新帖子。但是当调用personService.updatePerson(它反过来调用getPersonDao()。getEntityManager()。merge(person);)时没有任何反应!仍然在集合中只有一个项目获得相同的对象 的persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    version="1.0">
    <persistence-unit name="personPersistenceUnit" transaction-type="RESOURCE_LOCAL" >
    <class>com.me.model.Person</class>
    <class>com.me.model.Post</class>
    <properties>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
</persistence-unit>
</persistence> 

服务类:

import com.me.dao.PersonDao;
import com.me.model.Person;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PersonService {

    private PersonDao personDao;

    public PersonDao getPersonDao() {
        return personDao;
    }
    @Autowired
    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }

    public void addPerson(Person person) {
        getPersonDao().insert(person);
    }

    public void updatePerson(Person person){
        getPersonDao().getEntityManager().merge(person);
    }

    public List<Person> fetchAllPersons() {
        return getPersonDao().selectAll();
    }

    public boolean isPersonExist(Person person){
        if(personDao.getPersonByNameAndEMail(person.getName(), person.getEmail()) != null){
            return true;
        }
        return false;
    }

    public Person getPersonFromDB(String name, String email){
        return personDao.getPersonByNameAndEMail(name, email);
    }
}

package com.me.service;

import com.me.dao.PostDao;
import com.me.model.Post;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class PostService {

    private PostDao personDao;

    public PostDao getPostDao() {
        return personDao;
    }

    @Autowired
    public void setPostDao(PostDao personDao) {
        this.personDao = personDao;
    }

    public void addPost(Post person) {
        getPostDao().insert(person);
    }

    public void merge(Post post){
        getPostDao().getEntityManager().merge(post);
    }

    public List<Post> fetchAllPosts() {
        return getPostDao().selectAll();
    }
}

dao classes:

package com.me.dao;

import com.me.model.Person;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository("personDao")
@Transactional(propagation = Propagation.REQUIRED)
public class PersonDao {

    private static final String SELECT_QUERY = "select p from Person p";

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void insert(Person person) {
        if(getPersonByNameAndEMail(person.getName(), person.getEmail()) != null){
            return;
        }
        entityManager.persist(person);
    }

    public List<Person> selectAll() {
        Query query = entityManager.createQuery(SELECT_QUERY);
        List<Person> persons = (List<Person>) query.getResultList();
        return persons;
    }

    public Person getPersonByNameAndEMail(String name, String email) {
        String hql = "select p from Person p where p.name = :theName and p.email = :email";
        Query q = entityManager.createQuery(hql);
        q.setParameter("theName", name);
        q.setParameter("email", email);
        q.setMaxResults(1);
        Person p;
        try{
            p = (Person) q.getSingleResult();
        }catch(NoResultException e){
            p = null;
        }
        return p;
    }

}

package com.me.dao;

import com.me.model.Post;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


@Repository("potDao")
@Transactional(propagation = Propagation.REQUIRED)
public class PostDao {
    private static final String SELECT_QUERY = "select p from Post p";

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void insert(Post person) {
        entityManager.persist(person);
    }

    public List<Post> selectAll() {
        Query query = entityManager.createQuery(SELECT_QUERY);
        List<Post> persons = (List<Post>) query.getResultList();
        return persons;
    }
}

1 个答案:

答案 0 :(得分:0)

我注意到的一个问题与初始化子集合的方式有关。

您没有声明空集合关联:

private List<Post> posts;

但你是这样做的:

private List<Post> posts = new ArrayList();

然后addPost变为:

public void addPost(Post post) {
    post.setPerson(this);
    posts.add(post);
}

Hibernate将始终使用代理替换发布的ArrayList,这样您就可以确保在访问getPosts()时不需要调用addPost()就可以获得NullPointerException。

Post也是子实体,因为它首先需要Person。您通常不会从子级级联到父级,因此在Post实体中,您可以将级联移除到Parent:

@ManyToOne
public Person getPerson() {
    return person;
}

由于this而依赖于equals和hashCode中的id并不是一个好主意。

调用merge并在Parent中进行级联应该将更改传播到数据库。因为双向关联是由addPost设置的。

您的服务方法是否标有@Transactional?