7.29.2015

Entity EJB & Wildfly



В сервер wildfly  встроена реализация JPA, т. е. по умолчанию можно использовать библиотеки JPA hibernate  четвертой версии, описывать сущности с помощью аннотации @Entity.  Давайте создадим приложение, которое использует JPA, для начала нужно определиться с базой данных. В wildfly  уже есть встроенная база h2, используем её для наших целей. Заглянем в конфигурационный файл JBOSS_HOME/Standalone/configuration/standalone.xml, там должен быть настроен источник  данных который мы будем использовать:

<subsystem xmlns="urn:jboss:domain:datasources:2.0">
            <datasources>
                <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
                    <driver>h2</driver>
                    <security>
                        <user-name>sa</user-name>
                        <password>sa</password>
                    </security>
                </datasource>
                <drivers>
                    <driver name="h2" module="com.h2database.h2">
                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                    </driver>
                </drivers>
            </datasources>
        </subsystem>

И так напомню, мы будем использовать JPA  в web  приложении, опишем нашу сущность:

package com.vit.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;

@Entity(name="persons")
public class Person implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    private Long Id;

    @Column
    private String myName;

    public Person() {
    }
….
Getters & Setters
….
}

Опишем наш конфигурационный файл JPA, он должен находиться в директории web приложения jboss_ejb_war.war\WEB-INF\classes\META-INF\persistence.xml, а не в jboss_ejb_war.war\META-INF, рассмотрим его:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
   xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   <persistence-unit name="primary">        
      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>//наш источник данных h2
      <class>com.vit.model.Person</class> // наш класс сущности
      <properties>
         <!-- Properties for Hibernate -->
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>
</persistence>

Напишем Stateless бин, и внедрим в него EntityManager:

package com.vit;

import com.vit.model.Person;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class EntityBean {

    @PersistenceContext //Inject  Ентити менеджер
    private EntityManager em;

    public void saveAs(String name){
        Person p = new Person();
        p.setId(1L);
        p.setMyName(name);
        Person p1 = null;
        p1 = em.find(Person.class,p.getId());
        if (p1==null) em.persist(p); else  em.merge(p); //сохраняем нашу сущность
    }

    public String getName(){
        return em.find(Person.class,1L).getMyName(); // запрашиваем имя
    }
}

Напишем jsp  страничку, работающую с  нашим  EJB бином, смотрим код:

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page pageEncoding="UTF-8" %>
<%@ page session="false" %>
<%@ page import=" com.vit.EntityBean " %>
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<html>
<head>
    <title>Home</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>
    Hello world!
</h1>
<%
    Context context = new InitialContext();  
    EntityBean calc2 = (EntityBean) context.lookup("java:app/jboss_ejb_war/EntityBean!com.vit.EntityBean");
    calc2.saveAs("Hello Session Stateful Entity Bean!!!");//сохраняем наше значение в базе данных h2
    out.println(calc2.getName());//выводим наше значение из базы данных h2
%>
</body>
</html>

Как обычно, осталось только развернуть приложение, вы всё должны запаковать в war архив и скопировать в каталог JBOSS_HOME/Standalone/deployments, после деплоя, запустите jsp страницу. Внимательный читатель, который знаком с hibernate, наверное, уже задается вопросом – “А где же транзакции?”. Транзакции применяются по умолчанию ко всем EJB бинам, у нас есть аннотация @TransactionAttribute(value = TransactionAttributeType.REQUIRED) которая является дефолтной и она по умолчанию применяется ко всем методам, которые вы вызываете на сервере wildfly. Это все дело еще, когда метод автоматически обёртывается в транзакцию,  называют  CMT (Container Management Transaction), т.е. когда сервер за вас начинает транзакцию и завершает её. Т.е. к классу   EntityBean  который мы ранее написали, по умолчанию применяются такие аннотации:

@Stateless
@TransactionManagement(value = TransactionManagementType.CONTAINER) //управляет транзакциями сервер
@TransactionAttribute(value = TransactionAttributeType.REQUIRED) //по умолчанию ко всем методам EJB  применяется уровень транзакции  REQUIRED
public class EntityBean {

    @PersistenceContext //@Inject
    private EntityManager em;

….

}

Если  вы сами хотите  управлять транзакциями EJB бина, то вам нужно, во-первых выставить атрибут у аннотации в @TransactionManagement в BEAN, затем добавить транзакции UserTransaction tx,  и работать с этой транзакцией как вам заблагорассудится, смотрим на наш переписанный EJB бин:
package com.vit;

import com.vit.model.Person;

import javax.annotation.Resource;
import javax.ejb.*;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.*;

@Stateless
@TransactionManagement(value = TransactionManagementType.BEAN)
public class EntityBean {

    @PersistenceContext //@Inject
    private EntityManager em;

    @Resource
    UserTransaction tx;

    public void saveAs(String name) {
        Person p = new Person();
        p.setId(1L);
        p.setMyName(name);
        Person p1 = null;
        try {
            tx.begin(); //начинаем транзакцию
            p1 = em.find(Person.class, p.getId());
            if (p1 == null) em.persist(p);
            else em.merge(p);
            tx.commit();//подтверждаем транзакцию
        } catch (RollbackException e) {
            e.printStackTrace();
        } catch (HeuristicMixedException e) {
            e.printStackTrace();
        } catch (HeuristicRollbackException e) {
            e.printStackTrace();
        } catch (NotSupportedException e) {
            e.printStackTrace();
        } catch (SystemException e) {
            e.printStackTrace();
        }
    }

    public String getName() {
        String s = null;
        try{
        tx.begin();
        s = em.find(Person.class, 1L).getMyName();
        tx.commit();
        } catch (RollbackException e) {
            e.printStackTrace();
        } catch (HeuristicMixedException e) {
            e.printStackTrace();
        } catch (HeuristicRollbackException e) {
            e.printStackTrace();
        } catch (NotSupportedException e) {
            e.printStackTrace();
        } catch (SystemException e) {
            e.printStackTrace();
        }
        return s;
    }
}