You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Maven可运行Jar中EntityManager自动注入为空及增改失效问题求助

问题分析与解决方案

问题描述

开发一个可运行Jar的Maven项目,遇到两个JPA相关问题:

  1. 未手动赋值EntityManager时,通过@PersistenceContext注入的EntityManager始终为null;
  2. 手动赋值EntityManager后,查询功能正常,但新增、更新操作无报错却无法持久化数据。

相关配置与代码

Persistence.xml

<persistence-unit name="GreedTechDB">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <shared-cache-mode>NONE</shared-cache-mode>
    <properties>
        <property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://CORRECT_URL/GreedTechV1"/>
        <property name="jakarta.persistence.jdbc.user" value="CORRECT_USER"/>
        <property name="jakarta.persistence.jdbc.password" value="CORRECT_PASSWORD"/>
        <property name="jakarta.persistence.schema-generation.database.action" value="create" />
        <property name="hibernate.dialect"    value="org.hibernate.dialect.MySQLDialect" />
        <property name="hibernate.show_sql"   value="true" />
        <property name="hibernate.format_sql" value="true" />
    </properties>
</persistence-unit>

BaseSource.java

public class BaseSource implements Serializable {

    @Getter
    @PersistenceContext
    protected EntityManager em;

    private JPAQueryFactory queryFactory = null;

    protected JPAQueryFactory jpaQueryFactory() {
        if (queryFactory == null)
            queryFactory = new JPAQueryFactory(em);
        //em.clear();
        return queryFactory;
    }
}

MainSource.java

public class MainSource extends BaseSource {

    public List<Streamer> getChannelsToJoin() {
        QStreamer qStreamer = QStreamer.streamer;
        return jpaQueryFactory().selectFrom(qStreamer).where(qStreamer.modules.like("%bot%")).fetch();
    }

    @Transactional
    public void insertPengStats(int channel_id, int user_id, boolean success, int time_done) {
        PengStats stats = new PengStats();
        stats.setChannelId(channel_id);
        stats.setUserId(user_id);
        stats.setKilled(success);
        stats.setTimeDone(time_done);
        stats.setTimestamp(LocalDateTime.now());
        em.persist(stats);
    }
}

问题原因与解决办法

问题1:@PersistenceContext注入EntityManager为null

原因:
可运行Jar属于Java SE环境,@PersistenceContext是Java EE规范注解,依赖Tomcat、WildFly这类Java EE容器完成注入,SE环境没有容器支持,所以注解不生效,EntityManager始终为null。

解决办法:
手动通过EntityManagerFactory创建EntityManager,替代容器注入。修改BaseSource类:

public class BaseSource implements Serializable {

    protected EntityManager em;
    private JPAQueryFactory queryFactory = null;
    private static EntityManagerFactory emf;

    // 静态初始化EntityManagerFactory,项目启动仅执行一次
    static {
        emf = Persistence.createEntityManagerFactory("GreedTechDB");
    }

    public BaseSource() {
        // 创建EntityManager实例
        this.em = emf.createEntityManager();
    }

    protected JPAQueryFactory jpaQueryFactory() {
        if (queryFactory == null)
            queryFactory = new JPAQueryFactory(em);
        return queryFactory;
    }

    // 项目结束时调用,释放资源
    public void close() {
        if (em != null && em.isOpen()) {
            em.close();
        }
        if (emf != null && emf.isOpen()) {
            emf.close();
        }
    }
}

问题2:手动赋值后增改操作无法持久化

原因:
手动创建的EntityManager没有事务管理支持,@Transactional注解在Java SE环境下默认不生效(需要Spring或Java EE容器解析并管理事务)。调用em.persist()后事务未提交,数据不会写入数据库。

解决办法:
手动管理事务,在增改操作中显式开启、提交事务,异常时回滚。修改MainSource中的insertPengStats方法:

public void insertPengStats(int channel_id, int user_id, boolean success, int time_done) {
    try {
        // 开启事务
        em.getTransaction().begin();
        PengStats stats = new PengStats();
        stats.setChannelId(channel_id);
        stats.setUserId(user_id);
        stats.setKilled(success);
        stats.setTimeDone(time_done);
        stats.setTimestamp(LocalDateTime.now());
        em.persist(stats);
        // 提交事务
        em.getTransaction().commit();
    } catch (Exception e) {
        // 异常时回滚事务
        if (em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }
        e.printStackTrace();
    }
}

额外注意事项

  • EntityManagerFactory必须单例,避免重复创建浪费资源;
  • 项目终止时调用close()方法关闭EntityManager和EntityManagerFactory,释放数据库连接;
  • 若想简化事务管理,可引入Spring Context,通过Spring托管EntityManager和事务,让@Transactional注解生效。

内容的提问来源于stack exchange,提问作者recklessGreed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 06:06:01