【问题标题】:EntityManager persist silently failsEntityManager 静默坚持失败
【发布时间】:2013-09-04 08:14:22
【问题描述】:

我有一个 Jax RS 服务器,当使用 XML 格式的电影发送 POST 请求时,它会被正确调用。

@Resource(name = "movie")
@Path("/movie")
public class MovieResource
{

    @PersistenceContext(unitName = "movieDS")
    private EntityManager em;

    public MovieResource()
    {
        em = PersistenceProvider.createEntityManager();
    }

    @POST
    @Path("/post")
    @Consumes(
    {
        MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML
    })
    public Response createMovie(Movie movie)
    {
            if (!em.contains(newMovie))
            {
                em.merge(newMovie);
            }
        String result = "Movie created : " + movie;
        return Response.status(201).entity(movie).build();
    }
}

调试没有显示任何错误,但是没有任何内容被持久化。 数据源是JTA over EclipseLink,这里是persistence.xml

<?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">
  <!-- The data source should be set up in Glassfish -->
  <persistence-unit name="MovieManager" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/movieDS</jta-data-source>
    <properties>
      <property name="eclipselink.logging.level" value="ALL"/>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

EclipseLink 返回的日志在调用 em.merge() 时没有显示任何错误,它们主要涉及序列创建:

FINEST: Execute query ValueReadQuery(name="SEQUENCE" sql="SELECT SEQ_COUNT FROM SEQUENCE WHERE SEQ_NAME = #SEQ_NAME")
FINE: SELECT SEQ_COUNT FROM SEQUENCE WHERE SEQ_NAME = ?
    bind => [1 parameter bound]
FINEST: local sequencing preallocation for SEQ_GEN: objects: 50 , first: 51, last: 100
INFO: RAR7115: Unable to set ClientInfo for connection
FINEST: Connection released to connection pool [default].
FINER: TX commitTransaction, status=STATUS_ACTIVE
FINER: TX Internally committing
FINEST: local sequencing preallocation is copied to preallocation after transaction commit
FINER: external transaction has committed internally
FINEST: assign sequence to the object (51 -> net.plarz.entities.LoginInformation@91229c)

有人知道缺少什么吗? Movie 类非常简单,与其他表没有依赖关系,我认为它非常简单。

编辑:

如果我在 merge() 之后添加一个 flush(),我会得到一个错误:

javax.persistence.TransactionRequiredException: 
Exception Description: No externally managed transaction is currently active for this thread

【问题讨论】:

    标签: java dependency-injection eclipselink jta


    【解决方案1】:

    你不应该调用 flush() 而是创建一个企业 bean,这样:

    @Stateless
    public class MovieEJB
    {
      @PersistenceContext(unitName = "movieDS")
        private EntityManager em;
    
        @Override
        public Movie create(Movie movie) throws Exception
        {
            em.persist(movie);
            return movie;
        }
    
        @Override
        public void delete(Movie movie)
        {
            em.remove(em.merge(movie));
        }
    
        @Override
        public Movie update(Movie movie) throws Exception
        {
            return em.merge(movie);
        }
    }
    

    然后修改你的 MovieResource 类:

    @ManagedBean(name = "restController")
    @SessionScoped
    @Resource(name = "movie")
    @Path("/movie")
    public class MovieResource
    {
        @EJB
        private MovieEJB movieEJB;
    
        public MovieResource()
        {
    
        }
    
        public MovieEJBLocal getMovieEJB()
        {
            return movieEJB;
        }
    
        public void setMovieEJB(MovieEJBLocal movieEJB)
        {
            this.movieEJB = movieEJB;
        }
    
        @POST
        @Path("/post")
        @Consumes(
        {
            MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML
        })
        public Response createMovie(Movie movie)
        {
            getMovieEJB().create(movie);
            String result = "Movie created : " + movie;
            return Response.status(201).entity(movie).build();
        }
    }
    

    【讨论】:

    • 试过了,但它不起作用,恐怕我不能同时将一个类声明为 ManagedBean 和 @Resource 的 Jax RS 类。所以唯一的选择是在没有依赖注入的情况下调用 MovieEJB,知道吗?
    • 好吧,@Resource其实没用,把MovieResource注解改成:@Path("/movie")@Stateless
    • 谢谢莎拉!你让我今天一整天都感觉很好。我想知道为什么除了你没有人回答我。
    【解决方案2】:

    您正在使用 JTA 持久性单元,但未启动 JTA 事务。

    要么切换到 RESOURCE_LOCAL 和非 JTA 数据源,要么使用 JTA 事务,例如使用 EJB(参见其他答案)。

    【讨论】:

    • 其他答案解决了我的问题。谢谢詹姆斯
    猜你喜欢
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2017-01-10
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多