Hibernate JPA с JTA и сервером приложений Glassfish, кажется, не фиксирует - PullRequest
3 голосов
/ 01 августа 2011

Я новичок в спящем режиме и хочу использовать подключение к базе данных с сервера приложений через JNDI.

Странно то, что он создает мои таблицы в базе данных, но не сохраняет сущность. Кажется, что он не совершает.

Кто-нибудь сталкивался с подобными проблемами в спящем режиме?

Это маленький тест-сервлет:

public class WriteTest extends HttpServlet
{
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        /*try
        { 
            User user = new User("Hans", "Maulwurf", "hans.maulwurf@test.de");

            InitialContext ctx = new InitialContext();
            UserFacadeBean bean = (UserFacadeBean) ctx.lookup("ejb/UserFacadeBeanService");
            bean.persist(user);
        }
        catch (NamingException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/

        EntityManager em = JpaUtil.getEntityManagerFactory().createEntityManager();
        //em.getTransaction().begin();

        System.out.println("Begin transfer");

        User user = new User("Hans", "Maulwurf", "hans.maulwurf@test.de");
        Adress adress = new Adress("Deppenstraße 3","Deppingen");
        //user.setAddress(adress);

        System.out.println("Save User 'Hans Maulwurf'");

        em.persist(user);
        //em.persist(adress);
        //em.getTransaction().commit();
        em.close();

        System.out.println("Everything went better than expected!");
    }
}

Это маленький вспомогательный класс:

public class JpaUtil
{
    private static final EntityManagerFactory emf;

    static
    {
        try
        {
            System.out.println("Initialize EntityManagerFactory...");
            emf = Persistence.createEntityManagerFactory("testPU");
        }
        catch (Throwable ex)
        {
            System.err.println("Initial EntityManagerFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static EntityManagerFactory getEntityManagerFactory()
    {
        return emf;
    }
}

Мой пользовательский объект:

@Entity
@Table(name = "T_UserJpa")
public class User implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Embedded
    @AttributeOverrides(
    {
        @AttributeOverride(name = "street", column =
        @Column(name = "user_street")),
        @AttributeOverride(name = "city", column =
        @Column(name = "user_city", length = 50))
    })
    private Adress adress;
    private String firstname;
    private String lastname;
    private String email;

    public User()
    {
    }

    public User(String firstname, String lastname, String email)
    {
        this.firstname = firstname;
        this.lastname = lastname;
        this.email = email;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public Adress getAddress()
    {
        return adress;
    }

    public void setAddress(Adress adress)
    {
        this.adress = adress;
    }

    public String getFirstname()
    {
        return firstname;
    }

    public void setFirstname(String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname()
    {
        return lastname;
    }

    public void setLastname(String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (!(obj instanceof User))
        {
            return false;
        }
        final User user = (User) obj;
        return !(email != null ? !email.equals(user.email) : user.email != null);
    }

    @Override
    public int hashCode()
    {
        return 29 * (email != null ? email.hashCode() : 0);
    }
}

My persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
  <persistence-unit name="testPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/testdb</jta-data-source>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.autocommit" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

Редактировать: я забыл упомянуть, что уже использовал информацию, представленную в этой теме: Учебный ресурс по настройке Hibernate JPA 2.0 на сервере Glassfish

Ответы [ 4 ]

6 голосов
/ 01 августа 2011

На сервере приложений вы можете иметь управляемый контейнер EntityManager (или постоянный контекст) или управляемое приложение EntityManager.В обоих случаях вам придется связать контекст постоянства с Транзакцией, которая является либо Транзакцией JTA, либо простой транзакцией JDBC.

Что касается рассматриваемой проблемы, следует учитывать следующие моменты:

  • Ваш файл persistence.xml указывает на то, что вы собираетесь использовать источник данных JTA и, следовательно, транзакции JTA для выполнения транзакций.
  • Кроме того, ваш класс JpaUtil отвечает за создание приложения.управляемые EntityManager экземпляры.

В свете вышеупомянутых двух утверждений и поведения, продемонстрированного вашим приложением, может показаться, что ваш экземпляр EntityManager не связан с транзакцией JTA.Следовательно, любые изменения, сделанные в контексте постоянства, просто не будут сброшены в базу данных.Это просто связано с тем, что поставщик JPA будет полагаться на транзакцию JTA и задействованные ресурсы для выполнения транзакции;если ничего не найдено, то никакая работа не будет выполнена (в отличие от случая с транзакциями Resource-Local, где пул соединений и перечисление ресурсов выполняется самим поставщиком JPA).

Следовательно, EntityManager или контекст постоянства должен быть связан с активной транзакцией перед выполнением каких-либо изменений в сущностях, чтобы все изменения, внесенные в сущности в контексте постоянства, могли быть сброшены в базу данных.Чтобы решить вашу проблему, вы должны:

  • начать новую транзакцию JTA.Вы можете выбрать либо управляемые контейнером транзакции, либо управляемые приложением транзакции.

    • Контейнерные управляемые транзакции в качестве состояний имен полностью управляются контейнером.Вы не можете вызывать API для запуска и завершения таких транзакций.Вместо этого вы должны выполнять всю транзакционную работу внутри EJB.Рассматриваемые EJB должны быть настроены как требующие транзакций, управляемых контейнером.Демонстрация использования EJB для выполнения транзакционной работы в вашем сценарии была бы за пределами этого ответа.Я бы посоветовал прочесть о EJB, если вы еще не научились писать.
    • Транзакции, управляемые приложением или компонентом, управляются самим приложением, а не контейнером.Хотя это может показаться подходящим в вашем случае, учтите, что теперь вы несете ответственность за управление транзакциями;часто эта стратегия приводит к ошибкам, и довольно часто разработчики не понимают ее, в результате чего ее часто считают плохой практикой в ​​большинстве проектов.Если вы хотите использовать управляемые Бином транзакции, вам нужно будет запустить Транзакцию, используя класс API UserTransaction, как показано ниже:

      public class WriteTest extends HttpServlet
      {
          @Resource
          UserTransaction tx; // a UserTransaction reference is injected like a any other resource. It can also be looked up from JNDI.
      
          public void doGet(HttpServletRequest request, HttpServletResponse response)
          {
              ...
              tx.begin(); // Start a new JTA BMT
              EntityManager em = JpaUtil.getEntityManagerFactory().createEntityManager();
              ...
              User user = new User("Hans", "Maulwurf", "hans.maulwurf@test.de");
              Adress adress = new Adress("Deppenstraße 3","Deppingen");
              //user.setAddress(adress);
      
              em.persist(user);
              em.close();
              ...
              tx.commit(); // Commit the JTA BMT
          }
      
      }
      

      Приведенный выше код не совсемпроизводство готовых.Например, он не выполняет обработку исключений и не выполняет явный откат изменений в случае сбоя приложения.

  • присоединиться к EntityManagerэкземпляр с транзакцией JTA, если EntityManager еще не связан с транзакцией JTA.В этом нет необходимости, если вы сначала запускаете транзакцию JTA (что делается в приведенном выше примере с транзакциями, управляемыми компонентом Bean), но если вы сначала создаете EntityManager, используя класс JpaUtil, а затем начинаете транзакцию, а затемнеобходимо использовать метод EntityManager.joinTransaction(), чтобы присоединить контекст постоянства к транзакции JTA.Совершенно очевидно, что любые изменения, сброшенные из контекста постоянства, не связанного с транзакцией, будут игнорироваться.

3 голосов
/ 01 августа 2011

Вы должны использовать поддержку транзакций, предоставляемую контейнером.Это примеры из книги Pro JPA 2 Освоение API персистентности Java.Надеюсь, это поможет:

public class EmployeeServlet extends HttpServlet {
    @PersistenceUnit(unitName="EmployeeService")
    EntityManagerFactory emf;
    @Resource UserTransaction tx;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ...
        int id = Integer.parseInt(request.getParameter("id"));
        String name = request.getParameter("name");
        long salary = Long.parseLong(request.getParameter("salary"));
        tx.begin();
        EntityManager em = emf.createEntityManager();
        try {
            EmployeeService service = new EmployeeService(em);
            service.createEmployee(id, name, salary);
        } finally {
            em.close();
        }
        tx.commit();
        // ...
    }
}
1 голос
/ 13 июля 2014

Это руководство предназначено для интеграции hibernate.4.3.5, EJB, JTA и GlassFish.4.0 в среду IDE NetBeans.8.0. Создайте веб-проект в сетевых компонентах (внимание: не создавайте веб-проект с помощью maven, поскольку в IDE Netbeans.8.0 есть ошибка) и добавьте в проект файлы JAR-файлов гибернации, а другие настройки, связанные с настройкой MySql и glassfish, очень просты (просто определить пул соединений и JDBC в разделе «Ресурсы»> «JDBC: пулы соединений JDBC и ресурсы JDBC», руководство по этому вопросу можно найти в Интернете, если вы его ищете) (внимание: для определения правильного JNDI сначала создайте временный проект, который зависит от JNDI, например JPA проект в glassfish, затем скопируйте настройки, созданные в Glassfish для этого проекта, потому что в glassfish есть ошибка, когда вы собираетесь получить ping для MySQl при создании вашего первого пула подключений, если вы создаете его самостоятельно в glassfish), поэтому Я не описываю в этой статье, а затем создайте файл persistence.xml следующим образом:

<persistence-unit name="omidashouriPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/yourJNDI (which you defined in glassfish) </jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.connection.driver_class"  value="com.mysql.jdbc.Driver"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/YourSchemaName"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="yourpassword"/>
            <property name="hibernate.show_sql" value="true"/>
    </properties>
</persistence-unit>

В вашем классе EJB (класс, аннотированный @Stateless) для создания EntityManager используйте следующий синтаксис:

@PersistenceContext(unitName = " omidashouriPU ")
EntityManager em;
em.persist(YourEntityObject);

Как вы знаете, когда вы используете «action-type = "JTA", управление транзакцией не с вами, это означает, что управление открытием и закрытием транзакции является обязанностью сервера приложений (здесь GlassFish). В самом деле, если вы проверите свой файл persistence.xml в дизайне режима, перед выпадающим списком поставщика постоянства вы увидите, что теперь добавлен hibernate.

0 голосов
/ 01 августа 2011

Подтверждает ли это, когда вы в обязательном порядке фиксируете свои изменения, т.е. когда вы раскомментируете строку фиксации?

Также попробуйте проверить, установлена ​​ли ваша конфигурация с помощью

toggleAutoCommit = session.connection (). GetAutoCommit ();

...