EntityManager.persist 没有任何作用

EntityManager.persist does not have any effect

我正在使用 Java EE 开发 API (JAXRS) 并尝试实施 JPA。为此,据我所知,我正在使用 EclipseLink,并且我的应用程序部署在 Payara 服务器上。

当我尝试使用 EntityManager 中的持久化方法时,没有任何反应,也没有错误消息或其他内容。

这是我的 DAO class:

package shareloc.model.dao;

import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Optional;

import static shareloc.ServletContextListenerImpl.createEntityManager;

public abstract class DAO<T> {
    @PersistenceContext(unitName = "MariaDB")
    protected EntityManager em;
    private Class<T> entityClass;

    public DAO(Class<T> entityClass) {
        this.entityClass = entityClass;
        this.em = getEntityManager();
    }

    private EntityManager getEntityManager() {
        if (em == null) {
            em = createEntityManager();
        }
        return em;
    }

    public T create(T entity) {
        em.persist(entity);

        return entity;
    }

    public void update(T entity) {
        em.merge(entity);
    }

    public void delete(T entity) {
        em.remove(em.merge(entity));
    }

    public Optional<T> findById(Object id) {
        return Optional.ofNullable(em.find(entityClass, id));
    }

    public List<T> findAll() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<T> cq = cb.createQuery(entityClass);
        Root<T> root = cq.from(entityClass);

        cq.select(root);
        return em.createQuery(cq).getResultList();
    }
}

EJB 用户:

package shareloc.ejb;

import javax.persistence.*;

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private int userId;
    @Column(name = "pseudo")
    private String pseudo;
    @Column(name = "email")
    private String email;
    @Column(name = "password")
    private String password;
    @Column(name = "firstname")
    private String firstname;
    @Column(name = "lastname")
    private String lastname;

    public User() {}

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

    public User(int userId, String pseudo, String email, String password, String firstname, String lastname) {
        this.userId = userId;
        this.pseudo = pseudo;
        this.email = email;
        this.password = password;
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getPseudo() {
        return pseudo;
    }

    public void setPseudo(String pseudo) {
        this.pseudo = pseudo;
    }

    public String getEmail() {
        return email;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    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;
    }
}

调用DAO Create方法的方法:

public static HashMap<String, String> register(String email, String pseudo, String password, String firstname, String lastname) {
        HashMap<String, String> formError = new HashMap<>();

        formError.putAll(checkEmail(email));
        formError.putAll(checkPassword(password));
        formError.putAll(checkPseudo(pseudo));
        formError.putAll(checkFirstname(firstname));
        formError.putAll(checkLastname(lastname));

        if (formError.isEmpty()) {
            System.out.println("form error empty test");
            userDAO.create(new User(pseudo, email, password, firstname, lastname));
        }

        return formError;
    }

认证根:

    @POST
    @Path("register")
    @Produces(MediaType.APPLICATION_JSON)
    public Response register(@QueryParam("email") String email, @QueryParam("pseudo") String pseudo,
                             @QueryParam("password") String password, @QueryParam("firstname") String firstname,
                             @QueryParam("lastname") String lastname) {
        HashMap<String, String> errorMsgs = AuthManager.register(email, pseudo, password, firstname, lastname);

        if (errorMsgs.isEmpty()) {
            return Response.ok().build();
        } else {
            GenericEntity<HashMap<String, String>> entity =
                    new GenericEntity<>(errorMsgs) {};

            return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
        }
    }

创建一个销毁em Factory的ServletContextListener:

@WebListener
public class ServletContextListenerImpl implements ServletContextListener {
    private static EntityManagerFactory emf;

    // Application start-up
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        emf = Persistence.createEntityManagerFactory("MariaDB");
    }

    // Application destroyed
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        emf.close();
    }

    public static EntityManager createEntityManager() {
        if (emf == null)
            throw new NullPointerException("Context is not initialized yet.");

        return emf.createEntityManager();
    }
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>fr.unistra.iutrs</groupId>
    <artifactId>ShareLoc-API</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>ShareLoc-API</name>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <junit.version>5.6.2</junit.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.eclipse.persistence/org.eclipse.persistence.jpa -->
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa</artifactId>
            <version>3.0.0-M1</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>8.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.mvc</groupId>
            <artifactId>javax.mvc-api</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>9</source>
                    <target>9</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

persistence.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
    <persistence-unit name="MariaDB" transaction-type="JTA">
        <jta-data-source>java:global/mariadb</jta-data-source>
        <properties>
            <property name="javax.persistence.transactionType" value="JTA"/>
            <property name="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mariadb://mysql.iutrs.unistra.fr:3306/sharelocda" />
            <property name="javax.persistence.jdbc.user" value="" />
            <property name="javax.persistence.jdbc.password" value="" />

            <property name="eclipselink.target-database" value="MySQL"/>
            <property name="eclipselink.logging.level.sql" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <data-source>
        <name>java:global/mariadb</name>
        <class-name>org.mariadb.jdbc.MariaDbDataSource</class-name>
        <server-name>mysql.iutrs.unistra.fr</server-name>
        <port-number>3306</port-number>
        <database-name>sharelocda</database-name>
        <user></user>
        <password></password>
    </data-source>


    <listener>
        <listener-class>
            shareloc.ServletContextListenerImpl
        </listener-class>
    </listener>
</web-app>

而且,这是来自 Payara 的日志:

[2020-11-14T17:38:44.418+0100] [Payara 5.2020.5] [WARNING] [] [javax.enterprise.resource.resourceadapter.org.glassfish.jdbc.deployer] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371924418] [levelValue: 900] [[
  Value of maxPoolSize Given, -1, was outside the bounds, default value of 32 will be used - PLEASE UPDATE YOUR VALUE]]

[2020-11-14T17:38:44.419+0100] [Payara 5.2020.5] [WARNING] [] [javax.enterprise.resource.resourceadapter.org.glassfish.jdbc.deployer] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371924419] [levelValue: 900] [[
  Value of steadyPoolSize Given, -1, was outside the bounds, default value of 8 will be used - PLEASE UPDATE YOUR VALUE]]

[2020-11-14T17:38:44.499+0100] [Payara 5.2020.5] [INFO] [] [org.eclipse.persistence.session./file:/D:/Utilisateurs/razor/Documents/Etudes/IUT/IUT Robert Schuman/LP CDAD/LP1 - Développement Service Web/ShareLoc-API/target/ShareLoc-API-1.0-SNAPSHOT/WEB-INF/classes/_MariaDB] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371924499] [levelValue: 800] [[
  EclipseLink, version: Eclipse Persistence Services - 2.7.7.payara-p2]]

[2020-11-14T17:38:45.791+0100] [Payara 5.2020.5] [INFO] [] [fish.payara.micro.cdi.extension.ClusteredCDIEventBusImpl] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371925791] [levelValue: 800] [[
  Clustered CDI Event bus initialized]]

[2020-11-14T17:38:45.856+0100] [Payara 5.2020.5] [INFO] [] [org.glassfish.soteria.servlet.SamRegistrationInstaller] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371925856] [levelValue: 800] [[
  Initializing Soteria 1.1-b01.payara-p5 for context '/ShareLoc-API-1.0-SNAPSHOT']]

[2020-11-14T17:38:45.947+0100] [Payara 5.2020.5] [INFO] [jsf.config.listener.version] [javax.enterprise.resource.webcontainer.jsf.config] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371925947] [levelValue: 800] [[
  Initializing Mojarra |version.string| for context '/ShareLoc-API-1.0-SNAPSHOT']]

[2020-11-14T17:38:46.062+0100] [Payara 5.2020.5] [FINE] [] [org.eclipse.persistence.default] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371926062] [levelValue: 500] [[
  SAXParserFactory instance: com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl@72289c40]]

[2020-11-14T17:38:46.114+0100] [Payara 5.2020.5] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371926114] [levelValue: 800] [[
  Loading application [ShareLoc-API-1.0-SNAPSHOT] at [/ShareLoc-API-1.0-SNAPSHOT]]]

[2020-11-14T17:38:46.147+0100] [Payara 5.2020.5] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=125 _ThreadName=admin-thread-pool::admin-listener(1)] [timeMillis: 1605371926147] [levelValue: 800] [[
  ShareLoc-API-1.0-SNAPSHOT was successfully deployed in 2 990 milliseconds.]]

[2020-11-14T17:39:01.341+0100] [Payara 5.2020.5] [FINE] [] [org.eclipse.persistence.session./file:/D:/Utilisateurs/razor/Documents/Etudes/IUT/IUT Robert Schuman/LP CDAD/LP1 - Développement Service Web/ShareLoc-API/target/ShareLoc-API-1.0-SNAPSHOT/WEB-INF/classes/_MariaDB.sql] [tid: _ThreadID=111 _ThreadName=http-thread-pool::http-listener-1(4)] [timeMillis: 1605371941341] [levelValue: 500] [[
  SELECT user_id, email, firstname, lastname, password, pseudo FROM user WHERE (email = ?)
    bind => [test@gmail.fr]]]

[2020-11-14T17:39:01.429+0100] [Payara 5.2020.5] [INFO] [] [] [tid: _ThreadID=111 _ThreadName=http-thread-pool::http-listener-1(4)] [timeMillis: 1605371941429] [levelValue: 800] [[
  form error empty test]]

所以,没有例外,没有什么可以解释我做错了什么。问之前上网查了一下,发现有人有同样的问题,但是没有解决办法解决我的问题...

如果有人能解决我的问题,我会很高兴! (因为我的天啊,我在学习Java EE lol时遇到了很多问题) 如果您需要更多信息或代码,请告诉我! 谢谢!

编辑

public class AuthManager {
    private static UserDAO userDAO = new UserDAO(); // I'm calling my DAO with this.

    public static HashMap<String, String> register(String email, String pseudo, String password, String firstname, String lastname) {
        HashMap<String, String> formError = new HashMap<>();
       
       // Some check about the email, pseudo, etc..

        if (formError.isEmpty()) {
            System.out.println("form error empty test");
            userDAO.create(new User(pseudo, email, password, firstname, lastname)); // That the create method from the DAO wihch only do a em.persist
        }

        return formError;
    }

这是我的 UserDAO class:

public class UserDAO extends DAO<User> {
    public UserDAO() {
        super(User.class);
    }

    @Transactional
    public Optional<User> findByEmail(String email) {
        User user;

        Query query = em.createQuery("SELECT u FROM User u WHERE u.email = :email");
        query.setParameter("email", email);

        try {
            user = (User) query.getSingleResult();
            return Optional.of(user);
        } catch (NoResultException e) {
            return Optional.empty();
        }
    }
}

DAO:

public abstract class DAO<T> {
    @PersistenceContext(unitName = "MariaDB")
    protected EntityManager em;
    private Class<T> entityClass;

    public DAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    @Transactional
    public T create(T entity) {
        em.persist(entity);

        return entity;
    }
    
    // + update, findAll, etc...

我很困惑。您是否已将持久性单元配置为指向由您的容器 (java:global/mariadb) 管理的数据源 并且 配置了 JDBC 属性?你要拿定主意,要么使用容器提供的数据源,要么自己配置,但不能同时(换句话说,jta-data-source属性 与 javax.persistence.jdbc.* 属性互斥)。

您收到错误是因为您已将持久性单元设置为使用 JTA,然后您正尝试使用 em.getTransaction() 在某处开始事务,这对于 JTA 是不允许的。此外,您将 @PersistenceContext 放在 entityManager 之上,这意味着在调用构造函数后,entityManager 可能会被注入的实例覆盖。

解决方案是,假设您 do 实际上想使用 JTA,使用 @PersistenceContext 注入 EntityManager(您不必初始化它是手动的),然后用 @Transactional 注释你想自动执行的方法,而不是尝试使用 entityManager.getTransaction().