Persistencia de Objetos Java utilizando EJBs

Puede encontrar la versión original de este artículo en Inglés en:

http://www.devx.com/Java/

Introducción

Para la mayoría de las aplicaciones, almacenar y recuperar información implica alguna forma de interacción con una base de datos relacional. Esto ha representado un problema fundamental para los desarrolladores porque algunas veces el diseño de datos relacionales y los ejemplares orientados a objetos comparten estructuras de relaciones muy diferentes dentro de sus respectivos entornos.

Las bases de datos relacionales están estructuradas en un configuración tabular y los ejemplares orientados a objetos normalmente están relacionados en forma de árbol. Esta 'diferencia de impedancia' ha llevado a los desarrolladores de varias tecnologías de persistencia de objetos a intentar construir un puente entre el muno relacional y el mundo orientado a objetos. El marco de trabajo Enterprise JavaBeans (EJB) proporciona uno de los muchos métodos para reducir esta distancia.

Este artículo es el primero de una serie, en la que discutiremos cómo tres de estas tecnologías de persistencia de objetos (EJB, Java Data Objects, e Hibernate) intentan simplificar la tarea de conectar bases de datos relacionales y el lenguaje Java.

Persistencia de Objetos

La tarea de persistir objetos Java en una base de datos relacional actualmente está siendo facilitada por un gran número de herramientas que permiten a los desarrolladores dirigir motores de persistencia para convertir objetos Java a columnas/registros de una base de datos y viceversa. Esencial para este esfuerzo es la necesidad de mapear los objetos Java a columnas y registros de la base de datos de una manera optimizada en velocidad y eficiencia.

El marco de trabajo Enterprise JavaBeans (EJB) proporciona un mecanismo para persistencia de objetos. Describiremos este mecanismo a lo largo de este artículo, pero primero echemos un breve vistazo a la arquitectura general de EJB.

Enterprise JavaBeans

La tecnología EJB se puede definir como un marco de trabajao de componentes basados en Java, del lado del servidor y reutilizables para aplicaciones distribuidas. Este marco de trabajo facilia el manejo centralizado de la lógica de negocio, el despliegue declarativo y la persistencia de objetos. Aquí puede ver algunas de las características del marco de trabajo EJB:

  • Los EJBs son objetos Java ejcutados dentro de un entorno servidor.
  • Los EJBs pueden distribuirse entre varias máquinas y se puede acceder a ellos de forma remota como si estuvieran en una máquina local.
  • Los EJBs son manejados de forma centralizada por un contenedor.

Junto a la especificación EJB y la arquitectura hay un artefacto conocido como 'Enterprise Java Bean' (que, como al marco de trabajo, normalmente se le da el acrónimo EJB). Aunque los nombres del marco de trabajo EJB son muy similares a los nombres del marco de trabajo JavaBeans, las especificaciones de diseño para cada uno de ellos son muy diferentes.

Los nombres de las especificaciones EJB y JavaBeans y de sus componentes son muy similares, ahí es donde terminan las similitudes. La especificación y el modelo de componentes de JavaBeans y el modelo de componentes Enterprise JavaBeans tienen muy poco en común. Para ilustrar esto, veamos en más detalle los conceptos, componentes y entorno EJB:

Entorno de Ejecución EJB

Un JavaBean Enterprise es un objeto Java que expone algunos interfaces y que vive y se ejecuta dentro de un entorno de ejecución conocido como contenedor EJB. Un JavaBean Enterprise no puede existir fuera de un contenedor EJB. De echo, la relación entre un contenedor EJB y un EJB es conocida com "inversión de control" o el "principio de Hollywood" (No nos llame, ya le llamaremos!).

Un contenedor EJb es un entorno de ejecución para controlar beans enterprise. El contenedor almacena y maneja un bean enterprise de la misma manera que un motor servlet hospeda un servlet Java. El contenedor EJB ejemplariza y controla los beans enterprise y les proporciona servicios de bajo nivel.

Una aplicación cliente que desee interactuar con un bean enterprise no accede directamente a él. En lugar de eso, el bean está aislado de la aplicación cliente mediante el contenedor.

Servicios Proporcionados por un Contenedor EJB

Un desarrollador que vaya a crear las clases e interfaces a partir de las cuales se creará un objeto bean enterprise puede asumir que el contenedor EJB tendrá disponibles los siguientes servicios de bajo nivel:

  • Maneja las transaciones del bean.
  • Proporciona seguridad al bean
  • Proporciona persistencia para el bean
  • Acceso remoto al bean
  • Control del ciclo de vida del bean
  • Repositorio de conexiones a la base de datos
  • Repositorio de ejemplares del bean

Como el contenedor EJB maneja el paquete de servicios a nivel de infraestructura para un bean enterprise, un programador se puede concentrar en programar la lógica de negocio de ese bean.

Tipos de Beans Enterprise

La arquitectura EJB define tres tipos de beans enterprise distintos: :

  • Beans dirigidos-por-mensaje
  • Beans de sesión
  • Beans de entidad

A los beans de sesión y de entidad se les invoca síncronamente mediante un cliente bean enterprise. A los beans dirigidos por mensaje (MDBs) los invoca un contenedor de mensaje, como un tópico publicar/subscribir.

  • Beans Dirigidos por Mensaje

    Un bean dirigido por mensaje (MDB) es un bean enterprise que maneja de forma asíncrona los mensajes entrantes. Normalmente, un ejemplar de MDB actúa como un oyente de mensajes enviados desde un tópico publicar/subscribir. Un MDB puede recibir mensajes compatibles con JMS.

    Un contenedor EJB maneja el ciclo de vida de un MDB, sin embargo, al contrario que los beans de sesión y entidad; los programas clientes no se dirigen al MDB con llamadas a métodos. En vez de eso, el MDB recibe mensajes de una fuente de mensajes a través de un método de retrollamada, onMessage.

  • Beans de Sesión

    Un bean de sesión reperesenta un único cliente y no se comparte entre clientes. Un cliente llama a los métodos del bean de sesión, que son dirigidos a través del contenedor EJB al bean enterprise. El bean de sesión realiza la lógica de negocio para el cliente y el contenedor devuelve el control al cliente. Un bean de sesión no persiste entre varias sesiones. Hay dos tipos de beans de sesión:

    • Beans de Sesión con Estado
      Un bean de sesión con estado mantiene un estado conversacional con un cliente durante la duración de una sesión. Esto implica que el bean de sesión con estado puede mantener ejemplares de variables a través de varias llamadas desde un cliente durante una única sesión.
      Cuando el cliente termina de interactúar con el bean enterprise y el contenedor EJB lo elimina, termina la sesión del bean y se borran todos los datos de estado del bean.
    • Beans de Sesión sin Estado
      Un bean de sesión sin estado no mantiene un estado conversacional para cada cliente individual. Cada llamada a un bean de sesión sin estado debería considerarse como uns petición a un ejemplar totalmente nuevo, ya que cualquier estado de las variables de ejemplar se perderá entre dos llamadas.
      El contenedor EJB no persiste los beans de sesión sin estado en el almacenamiento secundario; por lo tanto un programador debe reconocer que todos los datos son temporales entre llamadas de un cliente. La naturaleza temporal de los beans de sesión sin estado permite a un contenedor EB reutilizar ejemplares de beans y por lo tanto, normalmente optimiza el rendimiento de los beans.
  • La imagen muestra como un contenedor EJB actúa como un proxy entre el cliente EJB y el propio ejemplar de EJB. Esto le da al contendor la libertad de hacer invocaciones a los ejemplares del EJB y controlar así el ciclo de vida de cada ejemplar EJB.

  • Beans de Entidad

    Un bean de entidad está pensado para representar la lógica de engocio de una entidad existente en un almacenamiento persistente, como una base de datos relacional. Los beans de entidad comparten algunas cualidaes que podría encontrar en una base de datos relacional, por ejemplo:

    • Los beans de entidad son persistentes: el estado de un bean de entidad existe más allá del ciclo de vida de la aplicación en la que se ha creado, o incluso más allá del ciclo de vida del conteendor EJB. Esto implica que l contenedor EJB puede restaurar el bean de entidad a su estado original.
    • Los beans de entidad permiten compartir accesos: los beans podrían compartirse entre varios clientes y la concurrencia la maneja el contenedor.
    • Los beans de entidad tienen claves primarias: Existen clases Primary-key para identificar un ejemplar de un bean de entidad. La clave primaria contiene toda la información necesaria para encontrar un bean almacenado.
    • Los beans de entidad podrían participar en relaciones: Se han presentado interfaces locales para manejar las relaciones entre beans.
    • Los beans de entidad pueden participar en transsaciones: como varios clientes pueden aceder y modificar los datos, es importante para los beans de entidad poder especificar las propiedades transacionales para su interacción. Las propiedades de transacación es especifican declarativamente en descriptores de despliegue, y los límites de transación los maneja el contenedor.

    El mapeo objeto-relacional implícito en los beans de entidad requiere que un bean de entidad sea responsable de insertar, actualizar, seleccionar y eliminar datos dentro de la fuente de datos. Este proceso del manejo de la comunicación entre el componente y la fuente de datos se llama persistencia. En otras palabras, persistencia es el proceso de escribir la información en una fuente de datos externa. Hay dos tipos de persistencia para los beans de entidad:

    • Persistencia Manejada por el Bean (BMP)
      Con la persistencia manejada por el bean (BMP), el programador es el responsable de escribir dentro del bean todo el código para acceder a la fuente de datos. Este tipo de persistenca le da más flexibilidad al programador porque controla todos los accesos a la fuente de datos.
    • Persistencia Manejada por el Contenedor (CMP)
      Con la persistencia manejada por el contenedor EJB es el propio contenedor EJB el que maneja todos los accesos a la base de datos requeridos por el bean de entidad. Como resultado, el código de acceso a los datos del bean, no está acoplado programáticamente a una fuente de datos específica. Esto libera al programador de tener que escribir código de acceso a los datos y permite que el bean de entidad se pueda desplegar en diferentes contenedores y/o contra diferentes fuentes de datos.

    La imagen muestra el camino de una petición de cliente hasta la capa de aplicación. Una vez que el servlet controlador recibe la petición, la convierte a un petición de servicio de negocio y llama a los servicios de negocio apropiados en la capa de servicio de negocio. Los servicios de negocio utilizan uno o más beans de entidad para cargar y grabar datos desde los recursos de la capa de datos.

Los Entornos de Despligue y Ejecución EJB

Vamos a utilizar JBoss 3.0.2 como entorno de despliegue y ejecución para los siguientes ejemplos. Diseñaremos una sencilla aplicación Web que permita crear cuentas de usuario y recuperarlas utilizando un navegador Web que se comunique con un servlet Java, que se comunica a su vez con un servicio de usuario, que se comunca con un EJB de entidad (como se puede ver en la imagen anterior...)

Escribir y Desplegar un Bean de Entidad

Estos cuatro pasos ilustran el proceso típico para desarrollar y desplegar un bean de entidad:

  1. Escribir las clases e interfaces del bean de entidad.
  2. Escribir un descriptor de despliegue.
  3. Empaquetar el bean de entidad y los ficheros asociados dentro de un fichero jar.
  4. Desplegar el bean.

Un bean de entidad se compone como mínimo de tres clases/interfaces:

  1. El Interface componente. Como sólo estamos interesados en acceder al EJB desde la misma JVM, crearemos un interface que extienda javax.ejb.EJBLocalObject.
    package com.jeffhanson.datatier.ejb;
    
    import javax.ejb.EJBLocalObject;
    
    public interface LocalUser extends EJBLocalObject {
       public String getUserID();  //primary key
       public String getFullName();
       public String setAddress(String address);
       public String getAddress();
       public String setCity(String city);
       public String getCity();
       public String setState(String state);
       public String getState();
       public String setZip(String zip);
       public String getZip();
    }
    
  2. El interface Home. De nuevo, como sólo estamos interesados en acceder al EJB desde la misma JVM crearemos un interace que extienda javax.ejb.EJBLocalHome.
    package com.jeffhanson.datatier.ejb;
    
    import javax.ejb.CreateException;
    import javax.ejb.FinderException;
    import javax.ejb.EJBLocalHome;
    import java.util.Collection;
    public interface LocalUserHome extends EJBLocalHome {
       public LocalUser create(String userID,
                               String fullName,
                               String address,
                               String city,
                               String state,
                               String zip)
          throws CreateException;
    
       public Collection findByFullName(String fullName)
          throws FinderException;
    
       public LocalUser findByPrimaryKey(String userID)
          throws FinderException;
    }
    
  3. La clase bean enterprise. La clase final implementa javax.ejb.SessionBean o javax.ejb.EntityBean:
    package com.jeffhanson.datatier.ejb;
    
    import javax.ejb.EntityBean;
    import javax.ejb.EntityContext;
    import javax.ejb.CreateException;
    import java.util.Locale;
    
    public class UserEJB implements EntityBean {
       // default to the US English
       private Locale locale = Locale.US;
       transient private EntityContext ctx;
       public String USERID;
       public String FULLNAME;
       public String ADDRESS;
       public String CITY;
       public String STATE;
       public String ZIP;
    
       public UserEJB() {
       }
    
       public void setLocale(Locale locale) {
          this.locale = locale;
       }
    
       //access methods for cmp fields
       public void setUserID(String userID) {
          USERID = userID;
       }
    
       public String getUserID() { //primary key 
          return USERID;
       }
    
       public void setFullName(String fullName) {
          FULLNAME = fullName;
       }
    
       public String getFullName() {
          return FULLNAME;
       }
    
       public void setAddress(String address) {
          ADDRESS = address;
       }
    
       public String getAddress() {
          return ADDRESS;
       }
    
       public void setCity(String city) {
          CITY = city;
       }
    
       public String getCity()  {
          return CITY;
       }
    
       public void setState(String state) {
          STATE = state;
       }
    
       public String getState() {
          return STATE;
       }
    
       public void setZip(String zip) {
          ZIP = zip;
       }
    
       public String getZip() {
          return ZIP;
       }
    
       public String ejbCreate(String userID, String fullName,
                             String address, String city, String state, String zip) {
          System.out.println("ejbCreate called with userID: " + userID);
          setUserID(userID);
          setFullName(fullName);
          setAddress(address);
          setCity(city);
          setState(state);
          setZip(zip);
    
          return userID;
       }
    
       public void ejbPostCreate(String userID, String fullName, String address, 
                          String city, String state, String zip)  throws CreateException  {
          // Called by container after ejbCreate
          System.out.println("ejbPostCreate called with userID: " + userID);
       }
    
       public void setEntityContext(EntityContext ctx) {
          this.ctx = ctx;
          System.out.println("setEntityContext called");
       }
    
       public void unsetEntityContext() {
          ctx = null;
       }
    
       public void ejbActivate() {
          // Called by container before the bean
          // is swapped into memory
       }
    
       public void ejbPassivate() {
          // Called by container before
          // the bean is swapped into storage
       }
    
       public void ejbLoad() {
          // Called by container to
          // refresh the entity bean's state
       }
    
       public void ejbStore() {
          // Called by container to save
          // bean's state to database
       }
    
       public void ejbRemove() {
          // Called by container before
          // the data is removed from the database
       }
    }
    

El Descriptor de Despliegue

Para desplegar un EJB en el entorno de un contenedor EJB, se debe suminsitrar un ficheros descriptor de despliegue para el contenedor EJB. Un descriptor de despliegue es un documento XML, llamado ejb-jar.xml, que especifica información sobre el bean como su tipo de persistencia y los atributos de transación. Es necesario empaquetar las clases Java y el descriptor de despliegue en un fichero JAr o ERA.

Además del fichero ejb-jar.xml estándar, JBoss tiene un descriptor de despliegue adicional para declarar las propiedades de persistencia CMP para los beans enterprise, llamado jaws.xml. El siguiente listado ilustra el descriptor de despliegue ejb-jar.xml para el UserEJB.:


<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC
   "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
   "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">

<ejb-jar>
  <display-name>Users</display-name>
  <enterprise-beans>

    <entity>
      <description>Encapsulates a User</description>
      <ejb-name>UserEJB</ejb-name>
      <local-home>com.jeffhanson.datatier.ejb.LocalUserHome</local-home>
      <local>com.jeffhanson.datatier.ejb.LocalUser</local>
      <ejb-class>com.jeffhanson.datatier.ejb.UserEJB</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.String</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-field><field-name>USERID</field-name></cmp-field>
      <cmp-field><field-name>FULLNAME</field-name></cmp-field>
      <cmp-field><field-name>ADDRESS</field-name></cmp-field>
      <cmp-field><field-name>CITY</field-name></cmp-field>
      <cmp-field><field-name>STATE</field-name></cmp-field>
      <cmp-field><field-name>ZIP</field-name></cmp-field>
      <primkey-field>USERID</primkey-field>
    </entity>

  </enterprise-beans>

  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>UserEJB</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>

Observe que el listado especifica el tipo y el nombre de la clave primaria para el EJB y los campos de éste que son persistentes. Se crea una tabla con un nombre que es el mismo que el de la clase Bea, que en este caso será UserEJB. El siguiente listado ilustra el descriptor de despliegue jaws.xml para UserEJB:


<?xml version="1.0" encoding="ISO-8859-1"?>

<jaws>
   <datasource>java:/DefaultDS</datasource>
   <type-mapping>Hypersonic SQL</type-mapping>
   
   <enterprise-beans>
    <entity>
        <ejb-name>UserEJB</ejb-name>
        <create-table>true</create-table>
        <table-name>UserEJB</table-name>
        <remove-table>false</remove-table>
        <tuned-updates>false</tuned-updates>
        <read-only>false</read-only>
        <time-out>300</time-out>
        <cmp-field>
          <field-name>USERID</field-name>
          <column-name>USERID</column-name>
        </cmp-field>
        <cmp-field>
          <field-name>FULLNAME</field-name>
          <column-name>FULLNAME</column-name>
        </cmp-field>
        <cmp-field>
          <field-name>ADDRESS</field-name>
          <column-name>ADDRESS</column-name>
        </cmp-field>
        <cmp-field>
          <field-name>CITY</field-name>
          <column-name>CITY</column-name>
        </cmp-field>
        <cmp-field>
          <field-name>STATE</field-name>
          <column-name>STATE</column-name>
        </cmp-field>
        <cmp-field>
          <field-name>ZIP</field-name>
          <column-name>ZIP</column-name>
        </cmp-field>
     </entity>
   </enterprise-beans>

</jaws>

Observe en el listado anterior, se declara cada campo dentro de un elemento cmp-field. Esto instruirá al contenedor EJB para crear una columna para cada campo en la nueva tabla de la base de datos y para mapear cada campo a su columna particular.

Todo lo que necesita hacer para desplegar UserEJB en JBoss es crear un fichero jar con las clases compiladas del EJB y los descriptores de desliegue y situarlo en el directorio de despliegue de su servidor particular JBoss.

El cliente EJB

La arquitectura de esta aplicación hace posible que se pueda acceder al EJB desde dentro de la misma JVM. Este diseño simplifica algunas cosas, especialmente el tipo de forzado necesario para obtener el interface home del EJB. El siguiente listado ilustra el objeto UserService, que accederá al EJB.


public class UserService {
   private static LocalUserHome home = null;

   private static LocalUserHome getUserHome() throws NamingException  {
      if (home != null) {
         return home;
      }
      
      // Get a naming context
      InitialContext ctx = new InitialContext();

      // Get a reference to a user Bean
      System.out.println("Looking up EJB...");
      Object objRef = ctx.lookup("local/UserEJB");

      // cast to the Bean's Home interface
      home = (LocalUserHome)objRef;
      return home;
   }

   public static UserInfo getUser(String userID) {
      UserInfo userInfo = null;

      try {
         LocalUserHome home = getUserHome();
         LocalUser localUser = null;
         try       {
            System.out.println("Finding user...");
            localUser = home.findByPrimaryKey(userID);
         }
         catch (FinderException e)  {
         }

         if (localUser == null)  {
            System.out.println("Creating user...");
            localUser = home.create(userID,  "John " + userID + " Doe",
                                    "123 anywhere st.",  "Seattle", "WA", "87654");
         }

         System.out.println("EJB returned User ID: " + localUser.getUserID());
         userInfo = convertToUserInfo(localUser);
         System.out.println("User FullName: " + localUser.getFullName());
      }
      catch (Exception e)  {
         System.err.println(e.toString());
      }

      return userInfo;
   }

   private static UserInfo convertToUserInfo(LocalUser localUser) {
      UserInfo userInfo;
      userInfo = new UserInfo();
      userInfo.setId(localUser.getUserID());
      userInfo.setFullName(localUser.getFullName());
      userInfo.setAddress(localUser.getAddress());
      userInfo.setCity(localUser.getCity());
      userInfo.setState(localUser.getState());
      userInfo.setZip(localUser.getZip());
      return userInfo;
   }
}

Observe que en el istado anterior primero se intenta encontar un ejemplar del EJB llamado al método findByPrimaryKey y pasándole un ID de usuario. Si no se encuentra el ejemplar, se llama al método create del interface home del EJB para poder crear el EJB. El contenedor EJB intercepta el método findByPrimaryKey, que intenta recuperar un registro de la base de datos con una clave primaria nombrada por el ID de usuario. El método create añadirá un nuevo registro a la base de datos con una clave primaria nombrada por el ID de usuario.

El Lenguaje EJB Query

EJB ofrece un lenguaje de consultas, llamado EJB QL, utilizado para escribir consultas para beans de entidad manejados por el contenedor. Las consultas las traduce el contenedor EJB al lenguaje de consulta de la facilidad de almacenamiento en la que se ha desplegado el EJB. Para este EJB, el contenedor, convertirá las consultas en SQL.

EJB QL se utiliza para expresar consultas para el método find definido en un interface home y realiza los métodos internos select definidos en la clase del bean de entidad. Las consultas EJB QL contienen una claúsula SELECT y una claúsula FROM, y opcionalmente una claúsula WHERE. La consulta se situa en el fichero ejb-jar.xml de la aplicación.

El siguiente código XML (definido en el fichero jaws.xml) mapea una consulta a un método findByState en el interface home de UserEJB. La aplicación de ejemplo UserEJB utiliza esta consulta y este método para buscar el usuario que corresponde a un estado dado:

<entity>

      ...
      <query>
         <query-method>
            <method-name>findByState</method-name>
            <method-params>
               <method-param>java.lang.String</method-param>
            </method-params>
         </query-method>
         <ejb-ql>
            [!CDATA[
            SELECT DISTINCT object(u)
            FROM UserEJB u
            WHERE u.STATE = ?1]]
         </ejb-ql>
      </query>
    </entity>

En referencia a la definición de la consulta precedente, el elemento ejb-ql define la consulta real a utilizar. La palabra clave OBJECT es necesaria cuando se devuelve un único tipo de objeto. Las consultas parametrizadas, como la de arriba, facilitan su uso con la utilización de lugares reservados para parámetros. Cada número representa un parámtero de la lista de parámetros, empezando con un indice de 1.

En el ejemplo de arriba, el número 1 será reemplazado por el parámetro state del método findByState. Los beans de entidad que emplean CMP puede definir un método findAll y/o un método findByPrimaryKey, que serán implementados y ejecutados de forma transparente por el contenedor EJB.

La Consulta EJB QL en Acción

En el siguiente listado, se define el método getUsersByState de la clase UserService. Este método hace una llamada al método findByState del interface home de UserEJB. El contenedor EJB interceptará la llamada y ejecutará la consulta definida en el fichero jaws.xml:

  public static UserInfo[] getUsersByState(String state) {
      UserInfo[] users = null;

      // Find all employees that earn more than John:

      try {
         LocalUserHome home = getUserHome();

         Collection userList = home.findByState(state);
         System.out.println("Found userList");
         if (userList != null)  {
            users = new UserInfo[userList.size()];
            int i = 0;
            Iterator iter = userList.iterator();
            while (iter.hasNext())  {
               LocalUser localUser = (LocalUser)iter.next();
               users[i++] = convertToUserInfo(localUser);
            }
         }
      }
      catch (NamingException e) {
         System.err.println(e.toString());
      }
      catch (FinderException e) {
         System.err.println(e.toString());
      }

      return users;
   }

Las diferencias arquitecturales entre el árbol de objetos Java y las tablas de las bases de datos relacionales, hacen que sea un poco desalentadora para los desarrolladores la tarea de persistir objetos Java en una base de datos relacional. La diferencia de impedancia entre las tablas relacionales y el árbol de objetos Java ha llevado a los desarrolladores a tratar con muchas tecnologías de persistencia de objetos diferentes para intentar reducir la distancia entre el mundo relacional y el mundo orientado a objetos. El marco de trabajo Enterprise JavaBeans define un mecanismo de persistencia manejado por el contenedor que le ha dado a los programadores una herramienta que puede simplificar este problema, cuando se utiliza con el suficiente cuidado.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR