¿Por qué quitar Hibernate todos los elementos en un conjunto Si quito todos los elementos de otro conjunto en la misma clase?

rescatado:

Tengo dos clases: Libro y miembros. En la clase hay dos miembros HashSet que almacenan libros: borrowedBooksy returnedBooks.

Cuando se quita un libro de borrowedBooksy lo puse en returnedBook, Hibernate hacerlo sin un problema para todos excepto para el último elemento borrowedBooks. Sin embargo, si quito el último elemento de borrowedBooksHibernate también elimina todos los libros en returnedBook. Así, al final del escenario no hay libros en borrowedBooks, pero también hay libros en returnedBooks.

Por ejemplo:

1) borrowedBooks: a, b, c
1) returnedBooks:
---
2) borrowedBooks: a, b
2) returnedBooks: c
---
3) borrowedBooks: a
3) returnedBooks: b, c
---
4) borrowedBooks: -
4) returnedBooks: -

Eso no es muy comprensible! ¿Por qué pasó esto? ¡Muchas gracias por tu ayuda! Aquí están mis clases:

@Entity
public class Book {

@Id
@TableGenerator(...)
@GeneratedValue(generator = "Book_Barcode")
private long barcode;
private long isbn=0;
private String bookTitle="";
// some other fields

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (barcode ^ (barcode >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Book other = (Book) obj;
    if (barcode != other.barcode)
        return false;
    return true;
}

}



@Entity
public class Member {

@Id
@TableGenerator(...)
@GeneratedValue(generator = "Member_Id")
private int id;

@OneToMany(fetch = FetchType.EAGER) //please ignore FetchType!
private Set<Book> returnedBooks = new HashSet<>();

@OneToMany(fetch = FetchType.EAGER)
private Set<Book> borrowedBooks = new HashSet<>();

@OneToMany(fetch = FetchType.EAGER)
private Set<Book> renewedBooks = new HashSet<>();
}

@Repository
public class MemberDAOImpl implements MemberDAO {

@Autowired
private SessionFactory sessionFactory;

@Override
@Transactional
public void borrowBook(Member member, Book book) {
    if (book.getStatus().equals("Available") && 
        book.getAvailableAmount() > 0) {

        Session currentSession = sessionFactory.getCurrentSession();

        book.setBorrowedDate(new Date());
        book.setAvailableAmount(book.getAvailableAmount() - 1);
        book.setStatus("Borrowed");

        Member newMember = currentSession.find(Member.class, member.getId());
        newMember.getBorrowedBooks().add(book);
    } 
}

@Override
@Transactional
public void returnBook(Member member, Book book) {
    if (book.getStatus().equals("Borrowed")) {

        Session currentSession = sessionFactory.getCurrentSession();

        Member newMember = currentSession.find(Member.class, member.getId());
        newMember.getReturnedBooks().add(book);
        newMember.getBorrowedBooks().remove(book);

        book.setBorrowedDate(null);
        book.setAvailableAmount(book.getAvailableAmount() + 1);
        book.setStatus("Available");
        book.setRenewedTimes(0);
    } 
}
}

@Controller
@RequestMapping("/member")
public class MemberController {

static Member member;

@Autowired
private MemberService memberService;

@Autowired
private BookService bookService;

@GetMapping("/bookBorrow")
public String bookBorrow(@RequestParam("barcode") long barcode, Model model) {
    Book book = bookService.searchBookByBarcode(barcode);
    memberService.borrowBook(member, book);
    model.addAttribute("booksList", member.getBorrowedBooks());
    model.addAttribute("member", member);
    return "member-specific-home-page";
}

@GetMapping("/bookReturn")
public String bookReturn(@RequestParam("barcode") long barcode, Model model) {
    Book book = bookService.searchBookByBarcode(barcode);
    memberService.returnBook(member, book);
    model.addAttribute("booksList", member.getReturnedBooks());
    model.addAttribute("member", member);
    return "member-specific-home-page";
}


}

Por lo tanto, creo que no hay ningún problema en public void borrowBook(...). ¿Hay algo malo en public void returnBook(...)? Me pasé un montón de tiempo, pero no pude encontrar una manera ... Gracias de antemano!

================================ Hay algo malo con Hibernate! Por ejemplo: si tengo 3 libros en borrowedBooks establecidos y que si trato de devolverlos: eliminar de manera borrowedBooks y poner en returnedBook.

Primera vuelta:

Hibernate: actualización del libro cantidad fija = ?, availableAmount = ?, BOOKTITLE = ?, borrowedDate = ?, Descripción = = ?, editedDate ?, edición = ?, ISBN = ?, issuedDate = ?, language = ?, página = ?, precio = = ?, editor ?, registrationDate = ?, renewedDate = ?, renewedTimes = ?, estado =? donde = código de barras?

Hibernate: inserto en Member_Book (??), (MEMBER_ID, returnedBooks_barcode) los valores

Hibernate: borrado de Member_Book donde MEMBER_ID =? y borrowedBooks_barcode =?

Segunda vuelta:

Hibernate: actualización del libro cantidad fija = ?, availableAmount = ?, BOOKTITLE = ?, borrowedDate = ?, Descripción = = ?, editedDate ?, edición = ?, ISBN = ?, issuedDate = ?, language = ?, página = ?, precio = = ?, editor ?, registrationDate = ?, renewedDate = ?, renewedTimes = ?, estado =? donde = código de barras?

Hibernate: inserto en Member_Book (??), (MEMBER_ID, returnedBooks_barcode) los valores

Hibernate: borrado de Member_Book donde MEMBER_ID =? y borrowedBooks_barcode =?

TERCER RETORNO:

Hibernate: actualización del libro cantidad fija = ?, availableAmount = ?, BOOKTITLE = ?, borrowedDate = ?, Descripción = = ?, editedDate ?, edición = ?, ISBN = ?, issuedDate = ?, language = ?, página = ?, precio = = ?, editor ?, registrationDate = ?, renewedDate = ?, renewedTimes = ?, estado =? donde = código de barras?

Hibernate: inserto en Member_Book (??), (MEMBER_ID, returnedBooks_barcode) los valores

Hibernate: borrado de Member_Book donde MEMBER_ID =?

Por favor, mire el "último" operación de borrado: borrado de Member_Book donde MEMBER_ID =? ¿Por qué sólo "donde MEMBER_ID =?" ???

GPI:

No estoy seguro es la respuesta correcta, pero hay dos cosas se destacan de su código:

límites sesión / Transacitonal

Su controladora no es transactionnal (que está bien).

@GetMapping("/bookBorrow")
public String bookBorrow(@RequestParam("barcode") long barcode, Model model) {
    Book book = bookService.searchBookByBarcode(barcode);
    memberService.returnBook(member, book);
    //...

Sus memberService.returnBook()es:

@Transactional
public void returnBook(Member member, Book book) {

Por lo que podemos deducir que para una sola petición HTTP (llamada a su controladora), hay una sesión abierta a la hibernación bookService.searchBook..., y el otro abierto en memberService.returnBook.

Cuando se tienen dos sesiones de hibernación que comparten las mismas entidades, las cosas "divertidas" suceder. No se debe utilizar la bookinstancia conseguido desde el bookServiceinterior de la memeberService, al menos no sin volver a conectarlo.

(Bueno en realidad mi consejo sería tener su despacho controladora todo a una sola transacción y de hibernación sesión, no dos, y no tener que preocuparse de cosas por el estilo).

¿Qué significa "raro" media? El principal problema es que la hibernación se garantiza que, en una sola sesión, cualquier mango le da a un objeto persistente (libro, miembro), es el mismo, como en: son ==. Si se encuentra en una sola sesión, a continuación bookService.load(id) == bookService.load(id). Este no es el caso en su aplicación controladora de la corriente, por lo que los objetos puede o no ser el mismo.

Que es una especie de probelmatic, porque ... tema 2

HashCode / Igual diseño

Su hashCode y equals no están alineados con una intención reasonnable. Básicamente su libro hashCodees un hash del código de barras. Y sus iguales es una ==comparación sobre el código de barras. Apuesto que quería decir .equals(), pero escribí "==".

Por lo menos dos libros tienen la misma instancia de código de barras String (muy poco probable), que nunca son iguales.

Así que lo que sucede ?

Bueno, usted lo trae un libro en una sesión de hibernación, se obtiene una instancia posterior que llamaré libro @ 1, con un código de barras "123", que es una instancia de String que llamaré cadena @ 1.

A continuación, se cierra la sesión de hibernación, y se introduce otro.

En esta sesión, se carga un Miembro, Miembro @ 1, que tiene un conjunto de libros, que hiberna carga, pero se encuentra en una nueva sesión. Así hibernación cargas de una nueva instancia de libros cada vez, y se termina con instancia libro libro @ 2, con código de barras "123", que es String @ 2 (las cadenas tienen los mismos caracteres, que son .equals, pero no son ==).

Así se quita libro @ 1 @ del miembro de conjunto el libro de 1. ¿Qué hace la implementación? Se ve si libro @ 2 y libro @ 1 son los mismos. .hashcode()sabia, lo son. .equals()sabio ? Ellos no son. El @ Libro1 no es @ Book2 y no es igual a ella, por lo que no se elimina.

Otra consecuencia es que cualquier cosa que hagas para reservar @ 1 no se realiza un seguimiento de hibernación, porque la sesión que creó libro @ 1 está cerrado. Lo que en realidad se convierte en una zona gris: ¿y si se agrega libro @ 1 @ 1 al miembro. ¿Cómo podría hibernar saber que en realidad no es un nuevo libro que acaba de crear? En caso de que conocerla en absoluto?

Ahora que ?

Arreglar sus iguales. Es bueno que usted tiene una "clave natural" para los libros, y que lo use, pero probablemente acostumbrado ==en el que debería haber utilizado.equals()

Tienen límites de las transacciones adecuadas. Hibernate funcionará mucho mejor si no dedicar tiempo a crear situaciones en las que tienen diferentes instancias de la misma entidad.

Usuario denominación correcta: lo que se llama MemberDAO no es un DAO. Un DAO accede y tiendas de objetos de acuerdo a los patrones de consulta. Aquí, su MemberDAO manipula diferentes entidades, de acuerdo a la lógica de negocio (por ejemplo, si me dan una copia de libro, incrementar un contador de disponibilidad). Este no es el trabajo de un DAO, es el trabajo de un servicio. nombramiento apropiado generalmente ayudará a establecer los límites de transacción apropiados, que ayudarán a la demarcación sesión adecuada. (Por ejemplo, por lo general es sospechoso de tener @Transactionnal en una aplicación DAO, a menos que "cortar las esquinas". Sucede, si se escribe un servicio CRUD muy simple y quiere ahorrar tiempo, pero cuando la lógica de negocio se cuela, esta es una código oler tener un DAO @Transactionnal).

Y, por último, utilice un paso a paso depurador. Hibernate no suele enviar SQL que no coincide con el estado de instancias de objetos que.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=221108&siteId=1
Recomendado
Clasificación