Не удается получить идентификатор объекта после persist() в многопользовательской среде Hibernete

#hibernate #jax-rs

#спящий режим #jax-rs

Вопрос:

Я пытаюсь получить идентификатор объекта после вызова persist() менеджера объектов. Однако после вызова persist() Я не получаю идентификатор. Также em.refresh() завершается с ошибкой. Я использую многопользовательскую базу данных Hibernate. Все работало нормально до того, как я ввел многопользовательскую среду.

Это то, что у меня есть:

 public class MyEntity{
@Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Basic(optional = false)
   @Column(name = "ID")
.....
}


@Stateless
public class ActionDAO{
......
@PersistenceContext(unitName = "project-persistence-unit")
   protected EntityManager em;

public void saveEntity(MyEntity q) {
       if (q.getId() == null) {
           em.persist(q);
           System.out.println(q.getID); // expect to get an ID here but i get 0 .
       } else {
           em.merge(q);
       }
 }
}
  

Я искал, но не смог найти решение!

Классы с несколькими арендаторами приведены ниже:

 public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
    @Override
    public String resolveCurrentTenantIdentifier() {
        String tenant = ThreadState.INSTANCE.getTenantId();
        return tenant;
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }
}

public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider {
    @Override
    protected ConnectionProvider getAnyConnectionProvider() {
        Properties properties = new Properties();
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl("jdbc:mysql://localhost:8889/project1?serverTimezone=UTC");
        ds.setUsername("root");
        ds.setPassword("root");
        DatasourceConnectionProviderImpl d = new DatasourceConnectionProviderImpl();
        d.setDataSource(ds);
        d.configure(properties);
        return (ConnectionProvider) d;
    }

    @Override
    protected ConnectionProvider selectConnectionProvider(String tenantId) {
        Properties properties = new Properties();
        String path = MyConstants.DOCUMENT_ROOT   "/"   tenantId.toUpperCase();
        File file = new File(path   File.separator   "DATABASE.properties");
        if (file.exists()) {
            Properties prop = new Properties();
            try {
                InputStream input = new FileInputStream(path   "/DATABASE.properties");
                prop.load(input);
                DriverManagerDataSource ds = new DriverManagerDataSource();
                ds.setUrl(prop.getProperty("URL"));
                ds.setUsername(prop.getProperty("USERNAME"));
                ds.setPassword(prop.getProperty("PASSWORD"));
                input.close();
                DatasourceConnectionProviderImpl d = new DatasourceConnectionProviderImpl();
                d.setDataSource(ds);
                d.configure(properties);
                return (ConnectionProvider) d;

            } catch (IOException | NullPointerException ex) {
                Logger.getLogger(MultiTenantConnectionProviderImpl.class.getName()).log(Level.SEVERE, null, ex);
                ex.printStackTrace();
            }
        }
        return null;

    }

}
  

Persistence.xml

 <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="project-persistence-unit" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <!--<jta-data-source>java:/PROJECT-DS</jta-data-source>-->
         <properties>
            <property name="hibernate.jdbc.time_zone" value="UTC"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.jdbc.batch_size" value="250"/>
            <property name="hibernate.jdbc.fetch_size" value="500"/> 
            <property name="hibernate.order_inserts" value="true"/>
            <property name="hibernate.order_updates" value="true"/>
            <property name="jboss.entity.manager.jndi.name" value="java:/myprojectEM"/>
            <property name="jboss.entity.manager.factory.jndi.name" value="java:/myprojectEMF"/>
            <property name="hibernate.generate_statistics" value="false"/>
            <property name="hibernate.multi_tenant_connection_provider" value="com.myproject.auxiliary.MultiTenantConnectionProviderImpl"/>
            <property name="hibernate.tenant_identifier_resolver" value="com.myproject.auxiliary.CurrentTenantIdentifierResolverImpl"/>
            <property name="hibernate.multiTenancy" value="DATABASE"/>
            <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
        </properties>
    </persistence-unit>
</persistence>
  

Комментарии:

1. Попробуйте добавить аннотацию @Transactional поверх вашего метода saveEntity или начните транзакцию с помощью em.getTransaction().begin() перед сохранением объекта, а затем зафиксируйте транзакцию с помощью em.getTransaction().commit()

2. Спасибо Onur. Добавление @Transactional правильно выдает ошибку («Транзакция недоступна при использовании JTA с включенным доступом к транзакциям, совместимым с JPA»), потому что я использую JTA в качестве своего типа транзакции. Обратите внимание, что когда я удаляю многопользовательскую среду, я могу получить идентификатор. Я, должно быть, что-то упускаю?

3. Я вижу! Хорошо, извините. На самом деле может быть много возможностей. Прежде всего, постарайтесь убедиться, что транзакция зафиксирована. Может быть, проблема с сеансом или состоянием объекта! Может быть, currentTenantIdentifier не может быть разрешен правильно? Просто проверьте это baeldung.com/hibernate-5-multitenancy и просмотрите свою конфигурацию после того, как убедитесь, что транзакция зафиксирована!

4. Спасибо Onur. Я решил это, изменив источник данных с ‘DriverManagerDataSource’ на ‘BasicDataSource’ (в моем MultiTenantConnectionProviderImpl).

Ответ №1:

Обновите класс MultiTenantConnectionProviderImpl, чтобы использовать org.apache.commons.dbcp.BasicDataSource вместо org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl