带有 JPA、H2 内存并部署在 Wildfly 上的 Jave Rest-api:由于事务和自动提交,无法 PUT 和 POST

Jave Rest-api with JPA, H2 in-memory and deployed on Wildfly: cannot PUT and POST due to transaction and Auto-commit

提问人:Scrat 提问时间:11/15/2023 更新时间:11/15/2023 访问量:22

问:

我正在构建一个用于维护用户的 Rest-api 服务。这很简单,但我有两个主要限制:

  • 使用的数据库必须位于内存中
  • 它必须部署在 Wildfly 上

对于内存数据库,我使用 H2,正如您在我的持久性 .xml 上看到的那样:

<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_1.xsd"
             version="3.0">

    <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
        <!-- Entity classes -->
        <class>com.xxxx.business.User</class>
        <class>com.xxxx.business.Gender</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.url"    value="jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'src/main/resources/h2init.sql';DB_CLOSE_DELAY=-1;"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.show_sql" value="true"/>

            <property name="hibernate.connection.autocommit" value="true" />

            <property name="javax.persistence.schema-generation.database.action"
                      value="drop-and-create" />
            <property name="javax.persistence.sql-load-script-source"
                      value="/h2init.sql" />
        </properties>

    </persistence-unit>
</persistence>

我使用RESOURCE_LOCAL事务和脚本插入到我的数据库中。到目前为止,它工作正常。

我的 POJO 很常见:


import jakarta.ejb.TransactionManagement;
import jakarta.ejb.TransactionManagementType;
import jakarta.enterprise.inject.Model;
import jakarta.persistence.*;

import java.io.Serializable;
import java.util.Date;

@Entity
@Model
@TransactionManagement(TransactionManagementType.BEAN)
@Table(name = "UserApi")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "USER_ID")
    private long id;
    @Column(name = "FIRST_NAME")
    private String firstName;
    @Column(name = "LAST_NAME")
    private String lastName;
    @Column(name = "EMAIL")
    private String email;
    @Column(name = "BIRTHDAY")
    private Date birthday ;
    @Column(name = "PASSWORD")
    private String password;


    public User(String firstName, String lastName, String email, Date birthday, String password) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.birthday = birthday;
        this.password = password;
    }

    public User() {
        super();
    }

    public long getId() {
        return id;
    }

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

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getPassword() {
        return password;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", birthday=" + birthday +
                ", password='" + password + '\'' +
                '}';
    }
}

这是我的资源:


import jakarta.inject.Inject;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

@Path("/users")
@Produces("application/json")
@Consumes("application/json")
public class UserResource {
    @Inject
    UserService userService;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GET
    @Path("/sf/{firstName}")
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> getUsersByFirstName(@PathParam("firstName")String firstName) {
        if(!StringUtils.isAllEmpty(firstName)){
            return userService.getUsersByFirstName(firstName);
        }
        return userService.getAllUsers();
    }

    @GET
    @Path("/si/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getUser(@PathParam("id")long id) {
        return userService.getUserById(id);
    }

    @PUT
    @Path("/u")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Transactional
    public Response updateCustomer(User user) {
        userService.updateUser(user);
        return Response.status(204).build();
    }

    @POST
    @Path("/c")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Transactional
    public Response create(User user) {
        userService.createUser(user);
        return Response.status(201).build();
    }
}

我的服务:

import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.persistence.*;
import jakarta.transaction.*;
import jakarta.transaction.RollbackException;
import jakarta.ws.rs.WebApplicationException;

import java.util.List;
//import java.util.logging.Logger;

public class UserService {
    //private static final Logger LOGGER = Logger.getLogger(UserService.class.getName());
    private static final String getAllUsers = "select u from User u";
    private static final String getUsersByFirstNameSql = "select u from User u where u.firstName=:firstName";
    private static final String getUsersByLastNameSql = "select u from User u where u.lastName=:lastName";
    private static final String getUserByIdSql = "select u from User u where id=:id";

    @PersistenceContext
    EntityManager em;

    public void createUser(User user) {



        try {
            em.getTransaction().begin();
            em.persist(user);
            em.getTransaction().commit();
            em.close();
        } catch (IllegalStateException  e) {
            em.getTransaction().rollback();
        }
        //LOGGER.info("Created user "+user);
    }

    public void updateUser( User user ) {
        em.getTransaction().begin();
        User u = getUserById(user.getId());
        u.setFirstName(user.getFirstName());
        u.setLastName(user.getLastName());
        u.setBirthday(user.getBirthday());
        u.setEmail(user.getEmail());
        u.setPassword(user.getPassword());
        em.persist(u);
        em.getTransaction().commit();
        em.close();
        //LOGGER.info("Updated user" + user);
    }

    public void deleteUser(Long id) {
        User user = getUserById(id);
        em.remove(user);
        //LOGGER.info("Deleted User with id" + id);
    }
    public User getUserById(Long id) {
        User user = em.find(User.class, id);
        if (user == null) {
            throw new WebApplicationException("User with id of " + id + " does not exist.", 404);
        }
        return user;
    }
    public List<User> getAllUsers() {
        List<User> users = em.createQuery(getAllUsers, User.class).getResultList();
        return users;
    }
    public List<User> getUsersByFirstName(String firstName){
        List<User> users = em.createQuery( getUsersByFirstNameSql, User.class)
                .setParameter("firstName", firstName).getResultList();
        return users;
    }

}

问题是,如果我不使用事务,我根本无法持久化。因此,我从我的 EntityManager 中得到了一个事务。结果,我收到“java.sql.SQLException: IJ031017: You cannot set autocommit during a managed transaction”。

尝试在持久性中添加 AUTOCOMMIT = false(无论是对于休眠还是从 jdbc h2)绝对没有做任何事情。非常感谢专家的帮助。

先谢谢你!

Java JPA 事务 EntityManager 自动提交

评论

0赞 Chris 11/15/2023
为什么您使用 connection.autocommit,并尝试将该休眠属性设置为 true?我也不认为您的 TransactionManagementType.BEAN 定义适用于实体 - 似乎应该在您的 UserService 类中指定它,以便您的容器知道如何处理它注入的 EntityManager 上下文的事务
0赞 Scrat 11/16/2023
我测试了日志上出现的,但我忘了将休眠设置为 false。我的错。感谢您的建议。

答:

0赞 Scrat 11/15/2023 #1

我通过修改wildfly文件夹上的独立.xml配置文件来解决自己的问题。您必须在使用的数据源上添加 jta=“false” <datasource jta=“false”...。>.

更多解释:https://www.mastertheboss.com/jbossas/jboss-datasource/demystifying-datasource-jta-and-xa-settings-on-jboss-wildfly/

我希望有一天它能帮助到某人。