unserialize - Serialización casera vs. Java
unserialize java (14)
Tengo un POJO determinado que necesita persistir en una base de datos, el diseño actual especifica su campo como una sola columna de cadena, y agregar campos adicionales a la tabla no es una opción.
Es decir, los objetos deben ser serializados de alguna manera. Así que solo para la implementación básica fui y diseñé mi propia forma serializada del objeto, lo que significaba concatenar todos sus campos en una secuencia agradable, separados por un delimitador que elegí. Pero esto es bastante feo y puede causar problemas, por ejemplo, si uno de los campos contiene mi delimitador.
Así que probé la serialización básica de Java, pero a partir de una prueba básica que realicé, esto de alguna manera se convierte en una operación muy costosa (construir un ByteArrayOutputStream, un ObjectOutputStream, y así sucesivamente, lo mismo para la deserialización).
Entonces ¿cuales son mis opciones? ¿Cuál es la forma preferida para serializar objetos para ir a una base de datos?
Editar: esta va a ser una operación muy común en mi proyecto, por lo que los gastos generales deben reducirse al mínimo, y el rendimiento es crucial. Además, las soluciones de terceros son agradables, pero irrelevantes (y generalmente generan gastos generales que intento evitar)
Tengo un POJO determinado que necesita persistir en una base de datos, el diseño actual especifica su campo como una sola columna de cadena, y agregar campos adicionales a la tabla no es una opción.
¿Podría crear una nueva tabla y poner una clave externa en esa columna? :) ¡Sospecho que no, pero cubramos todas las bases!
Serialización: recientemente tuvimos esta discusión, por lo que si nuestra aplicación falla, podemos resucitarla en el mismo estado que anteriormente. Básicamente enviamos un evento de persistencia a una cola, y luego esto toma el objeto, lo bloquea y luego lo serializa. Esto parece bastante rápido. ¿Cuántos datos está serializando? ¿Puedes hacer que las variables sean transitorias (es decir, variables en caché)? ¿Puedes considerar dividir tu serialización? Cuidado: ¿qué sucede si los objetos cambian (bloqueo) o las clases cambian (identificador de serialización diferente)? Tendrá que actualizar todo lo que se serializa a las últimas clases. ¿Quizás solo necesites almacenar esto de la noche a la mañana para que no importe?
XML: puede usar algo como xstream para lograr esto. Crear algo personalizado es posible (¡una buena pregunta para la entrevista!), Pero probablemente yo no lo haga. ¿Por qué molestarse? Recuerde si tiene enlaces cíclicos o si tiene referencias a objetos más de una vez. Reconstruir los objetos no es tan trivial.
Almacenamiento de la base de datos: si está utilizando Oracle 10g para almacenar blobs, actualice a la última versión, ya que el rendimiento c / blob se incrementa enormemente. Si estamos hablando de grandes cantidades de datos, ¿tal vez comprimir el flujo de salida?
¿Es esta una aplicación en tiempo real, o habrá una segunda o dos pausas en las que puede persistir con seguridad el objeto real? Si tienes tiempo, entonces puedes clonarlo y luego persistir el clon en otro hilo. ¿Para qué es la persistencia? ¿Es crítico que se haga dentro de una transacción?
¿Has investigado JAXB ? Es un mecanismo mediante el cual puede definir un conjunto de objetos java que se crean a partir de un esquema XML. Le permite ordenar de una jerarquía de objetos a XML o volver a colocar el XML en una jerarquía de objetos.
¿Qué tal el mecanismo de persistencia estándar de JavaBeans?
java.beans.XMLEncoder
java.beans.XMLDecoder
Estos pueden crear POJOs de Java desde XML (que se han conservado en XML). De memoria, se ve (algo) como ...
<object class="java.util.HashMap">
<void method="put">
<string>Hello</string>
<float>1</float>
</void>
</object>
PersistenceDelegate
proporcionar clases PersistenceDelegate
para que sepa cómo persistir las clases definidas por el usuario. Suponiendo que no elimina ningún método público, es resistente a los cambios de esquema.
Considera cambiar tu esquema. Incluso si encuentra una manera rápida de serializar un POJO en una cadena, ¿cómo maneja las diferentes versiones? ¿Cómo se migra la base de datos de X-> Y? O peor de A-> D? Estoy viendo problemas donde almacenamos un objeto de serialización en un campo BLOB y tenemos que migrar a un cliente a través de múltiples versiones.
Debe considerar el control de versiones en su solución. La incompatibilidad de datos es un problema que experimentará con cualquier solución que implique el uso de una serialización binaria del objeto. ¿Cómo se carga una fila de datos más antigua en una versión más nueva del objeto?
Por lo tanto, las soluciones anteriores que implican la serialización de un nombre / valor pares es el enfoque que probablemente desee utilizar.
Una solución es incluir un número de versión como uno de los valores de campo. A medida que se agregan, modifican o eliminan nuevos campos, la versión se puede modificar.
Al deserializar los datos, puede tener diferentes manejadores de deserialización para cada versión que pueden usarse para convertir datos de una versión a otra.
Elliot Rusty Harold escribió un buen argumento en contra del uso de la serialización de objetos Java para los objetos en su biblioteca XOM. Los mismos principios se aplican a ti. La serialización de Java incorporada es específica de Java, frágil y lenta, por lo que es mejor evitarla.
Tiene aproximadamente la idea correcta al usar un formato basado en cadenas. El problema, como dices, es que te estás encontrando con problemas de formato / sintaxis con delimitadores. La solución es usar un formato que ya está diseñado para manejar esto. Si se trata de un formato estandarizado, también puede utilizar otras bibliotecas / idiomas para manipularlo. Además, un formato basado en cadenas significa que tiene la esperanza de comprenderlo simplemente observando los datos; los formatos binarios eliminan esa opción.
XML y JSON son dos grandes opciones aquí; Están estandarizados, basados en texto, son flexibles, legibles y tienen mucho soporte de biblioteca. También funcionarán sorprendentemente bien (a veces incluso más rápido que la serialización de Java).
En segundo lugar, sugiero usar JAXB, o posiblemente XStream (el primero es más rápido, el último tiene más enfoque en la parte de serialización de objetos). Además, sugeriré una alternativa decente basada en JSON, Jackson ( http://jackson.codehaus.org/Tutorial ), que puede serializar / deserializar por completo los beans al texto JSON para almacenar en la columna.
Ah, y estoy absolutamente de acuerdo en que no utilice la serialización binaria de Java bajo ninguna circunstancia para el almacenamiento de datos a largo plazo. Lo mismo ocurre con los Buffers de Protocolo; ambos son demasiado frágiles para este propósito (son mejores para la transferencia de datos entre sistemas acoplados).
Puede intentar con Preon . Preon pretende ser con datos binarios codificados lo que Hibernate es para bases de datos relacionales y JAXB para XML.
Puede optimizar la serialización externalizando su objeto. Eso le dará control total sobre cómo se serializa y mejorará el rendimiento del proceso. Esto es simple de hacer, siempre que su POJO sea simple (es decir, no tenga referencias a otros objetos); de lo contrario, puede romper fácilmente la serialización.
EDITAR: no implica que este sea el enfoque preferido, pero tiene muy pocas opciones si es crítico para el rendimiento y solo puede usar una columna de cadena en la tabla.
Puede probar Protocol Buffers , es un proyecto de fuente abierta de Google, se dice que es rápido (genera una forma serializada más corta que XML, y funciona más rápido). También maneja la adición de un nuevo campo suavemente (inserta valores por defecto).
Si está usando un delimitador, puede usar un carácter que nunca ocurrirá en su texto, como / 0, o símbolos especiales http://unicode.org/charts/symbols.html
Sin embargo, el tiempo dedicado a enviar los datos a la base de datos y persistir es probable que sea mucho mayor que el costo de la serialización. Así que sugiero comenzar con algo simple y fácil de leer (como XStream) y ver dónde está gastando la mayor parte de su aplicación y optimizarla.
Yo diría que su enfoque inicial no es del todo malo si su POJO está formado por cadenas y tipos primitivos. Puede forzar el escape del delimitador para evitar corrupciones. Además, si utiliza Hibernate, encapsula la serialización en un tipo personalizado .
Si no le importa otra dependencia, se supone que Hessian es una forma más eficiente de serializar objetos Java.
Considere colocar los datos en un objeto de Properties
y use su serialización load()/store()
. Esa es una técnica basada en texto, por lo que todavía es legible en la base de datos:
public String getFieldsAsString() {
Properties data = new Properties();
data.setProperty( "foo", this.getFoo() );
data.setProperty( "bar", this.getBar() );
...
ByteArrayOutputStream out = new ByteArrayOutputStream();
data.store( out, "" );
return new String( out.toByteArray(), "8859-1" ); //store() always uses this encoding
}
Para cargar desde una cadena, haz algo similar usando un nuevo objeto de Properties
y load()
los datos.
Esto es mejor que la serialización de Java porque es muy legible y compacto.
Si necesita soporte para diferentes tipos de datos (es decir, no solo String), use BeanUtils para convertir cada campo a y desde una representación de cadena.