java spring - ¿Por qué JPA tiene una anotación @Transient?




entity persistent (6)

Java tiene la palabra clave transient . ¿Por qué JPA tiene @Transient lugar de simplemente usar la palabra clave java ya existente?


Answers

La palabra clave transient de Java se usa para indicar que un campo no debe ser serializado, mientras que la anotación @Transient de JPA se usa para indicar que un campo no debe persistir en la base de datos, es decir, su semántica es diferente.


Intentaré responder a la pregunta de "por qué". Imagine una situación en la que tenga una gran base de datos con muchas columnas en una tabla, y su proyecto / sistema use herramientas para generar entidades desde la base de datos. (Hibernate los tiene, etc.) Ahora, suponga que, según su lógica empresarial, necesita que un campo en particular NO sea persistente. Tienes que "configurar" tu entidad de una manera particular. Mientras que la palabra clave Transient funciona en un objeto, ya que se comporta dentro de un lenguaje java, @Transient solo está diseñado para responder a las tareas que pertenecen solo a las tareas de persistencia.


El propósito es diferente:

La palabra clave transient y la anotación @Transient tienen dos propósitos diferentes: uno trata con la serialización y el otro con la persistencia . Como programadores, a menudo unimos estos dos conceptos en uno solo, pero esto no es exacto en general. Persistence refiere a la característica de estado que sobrevive al proceso que lo creó. Serialization en Java se refiere al proceso de codificación / decodificación del estado de un objeto como un flujo de bytes.

La palabra clave transient es una condición más fuerte que @Transient :

Si un campo utiliza la palabra clave transient , ese campo no se serializará cuando el objeto se convierta en un flujo de bytes. Además, dado que JPA trata los campos marcados con la palabra clave transient como que tienen la anotación @Transient , el campo tampoco será persistente por JPA.

Por otro lado, los campos anotados solo @Transient se convertirán en un flujo de bytes cuando el objeto se serialice, pero JPA no lo persistirá. Por lo tanto, la palabra clave transient es una condición más fuerte que la anotación @Transient .

Ejemplo

Esto plantea la pregunta: ¿Por qué alguien querría serializar un campo que no se mantiene en la base de datos de la aplicación? La realidad es que la serialización se usa para algo más que la persistencia . En una aplicación Enterprise Java debe existir un mecanismo para intercambiar objetos entre componentes distribuidos ; La serialización proporciona un protocolo de comunicación común para manejar esto. Por lo tanto, un campo puede contener información crítica para fines de comunicación entre componentes; pero ese mismo campo puede no tener valor desde una perspectiva de persistencia.

Por ejemplo, supongamos que un algoritmo de optimización se ejecuta en un servidor, y supongamos que este algoritmo tarda varias horas en completarse. Para un cliente, tener el conjunto de soluciones más actualizado es importante. Por lo tanto, un cliente puede suscribirse al servidor y recibir actualizaciones periódicas durante la fase de ejecución del algoritmo. Estas actualizaciones se proporcionan utilizando el objeto ProgressReport :

@Entity
public class ProgressReport implements Serializable{

    private static final long serialVersionUID = 1L;

    @Transient
    long estimatedMinutesRemaining;
    String statusMessage;
    Solution currentBestSolution;

}

La clase de Solution podría verse así:

@Entity
public class Solution implements Serializable{

    private static final long serialVersionUID = 1L;

    double[][] dataArray;
    Properties properties;
}

El servidor persiste cada ProgressReport a su base de datos. El servidor no se preocupa por persistir estimatedMinutesRemaining minutos que permanecen, pero el cliente ciertamente se preocupa por esta información. Por lo tanto, el @Transient se anota utilizando @Transient . Cuando la Solution final es localizada por el algoritmo, JPA la conserva directamente sin usar un ProgressReport .


Como han dicho otros, @Transient se utiliza para marcar campos que no deben persistir. Considere este breve ejemplo:

public enum Gender { MALE, FEMALE, UNKNOWN }

@Entity
public Person {
    private Gender g;
    private long id;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }

    public Gender getGender() { return g; }    
    public void setGender(Gender g) { this.g = g; }

    @Transient
    public boolean isMale() {
        return Gender.MALE.equals(g);
    }

    @Transient
    public boolean isFemale() {
        return Gender.FEMALE.equals(g);
    }
}

Cuando esta clase se alimenta a la JPA, persiste el gender y la id pero no intenta @Transient los métodos booleanos auxiliares; sin @Transient el sistema subyacente se quejaría de que faltan los setMale() y setFemale() la entidad Entity. y así no persistiría Person en absoluto.


Porque tienen significados diferentes. La anotación @Transient le dice al proveedor de JPA que no persista ningún atributo (no transient ). El otro le dice al marco de serialización que no serialice un atributo. Es posible que desee tener una propiedad @Transient y seguir serializándola.


Bueno, creo que ya tenemos suficientes explicaciones teóricas, así que considera este código.

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

Nota: synchronized bloquea la llamada del siguiente hilo al método de prueba () siempre y cuando la ejecución del hilo anterior no haya finalizado. Los hilos pueden acceder a este método uno a la vez. Sin synchronized todos los hilos pueden acceder a este método simultáneamente.

Cuando un subproceso llama al método sincronizado "prueba" del objeto (aquí el objeto es una instancia de la clase "TheDemo") adquiere el bloqueo de ese objeto, cualquier nuevo subproceso no puede llamar CUALQUIER método sincronizado del mismo objeto siempre que el subproceso anterior El que había adquirido la cerradura no libera la cerradura.

Algo similar sucede cuando se llama a cualquier método sincronizado estático de la clase. El subproceso adquiere el bloqueo asociado con la clase (en este caso, cualquier subproceso puede llamar a cualquier método sincronizado no estático de una clase de esa clase porque ese bloqueo de nivel de objeto todavía está disponible). Cualquier otro subproceso no podrá llamar a ningún método estático sincronizado de la clase siempre y cuando el bloqueo que actualmente mantiene el bloqueo no libere el bloqueo de nivel de clase.

Salida con sincronizado

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

Salida sin sincronizar

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9






java jpa java-ee annotations transient