【问题标题】:Use Spring and EJB transaction together一起使用 Spring 和 EJB 事务
【发布时间】:2018-09-05 18:34:11
【问题描述】:

我在尝试将实体添加到数据库时遇到错误。我已经推荐了this。但它没有太多关于我的问题的信息

我有一个用于管理获取、保存和更新实体的 EJB jar。

这是我的远程 ejb

@Remote
public abstract interface DatalayerService{
   public abstract void add(Object object)
}

这是实现

@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class DatalayerServiceImpl implements DatalayerService{
  @PersistenceContext(name="myPersistenceUnit")
   EntityManager em = null;

  @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void add(Object object) throws FatalException{
        try {
            em.persist(object);
        }
        catch (Throwable e){
            throw manageDatalayerError(e);
        }
        finally {

        }
    }
}

我正在尝试在我的应用程序中使用上述 ejb

1)

@ComponentScan({"com.springboot"})
@EnableJpaRepositories
@SpringBootApplication
public class SpringEjbApplication extends SpringBootServletInitializer{


    public static void main(String args[]){
        SpringApplication.run(SpringApplication.class,args);
    }



    @Bean
    public DatalayerService datalayerService() throws NamingException{
        return new DatalayerServiceImpl();
    }


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException{
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[]{"com.springboot.pojo"});
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        em.setJpaVendorAdapter(vendorAdapter);
        em.setPersistenceUnitName("myPersistenceUnit");
        em.setJpaProperties(additionalProperties());
        return em;
    }



    @Bean
    public DataSource dataSource() throws NamingException{
        return (DataSource) new JndiTemplate().lookup("openejb:Resource/MyDataSource");
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }


    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }


    private Properties additionalProperties(){
        Properties properties = new Properties();
        properties.setProperty("hibernate.max_fetch_depth", "3");
        properties.setProperty("hibernate.default_batch_fetch_size", "2");
        properties.setProperty("hibernate.jdbc.batch_size", "100");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.format_sql", "false");
        return properties;
    }
}

2)休息服务

@RestController
public class HomeEndPoint{

    @Autowired
    private IUserService iUserService;

    @GetMapping("/createUser")
    @Transactional(rollbackFor = {ServiceExpectedException.class,FatalException.class,MandatoryParameterMissingFatalException.class})
    public void createUser() throws FatalException,ServiceExpectedException{
        iUserService.createUser();
    }

}

3)用户服务及其实现

public interface IUserService{
   public void createUser() throws FatalException;
}

    @Service
@Transactional(rollbackFor = {ServiceExpectedException.class,FatalException.class,MandatoryParameterMissingFatalException.class})
public class UserServiceImpl implements IUserService{
     @Autowired
    private DatalayerGenericService datalayerGenericService;

     @Override
    public void createUser() throws FatalException,ServiceExpectedException{
     Team team = new Team(simpleContextService);
        team.setGroupName("MyTeam");
        team.setStoreId(100);
        // Team
        datalayerGenericService.add(team);
        Log.info(this,"add team ");
        // Build user1
        datalayerGenericService.add(user1);
        Log.info(this,"############################# Added User1 ######################################");
        // Build user2
        datalayerGenericService.add(user2);
        Log.info(this,"############################# Added User2 ######################################");

}
}

我尝试使用 url 运行其余服务

http://localhost:6180/SpringBootDatalayer/createUser

我收到以下异常。

信息:(com.edifixio.springboot.service.impl.UserServiceImpl)

###################### teamOid 20 信息:(com.edifixio.springboot.service.impl.UserServiceImpl) ###################### 添加用户1######################## ############ 信息:(com.edifixio.springboot.service.impl.UserServiceImpl) ###################### 添加了用户2 ######################## ############ 信息:http-nio-6180-exec-1:AbstractBatchImpl.release:HHH000010:在批次发布时它仍然

包含 JDBC 语句 2018-03-27 16:28:17,683:错误: http-nio-6180-exec-1:BatchingBatch.performExecution:HHH000315: 执行批处理的异常[java.sql.BatchUpdateException:批处理条目 0 插入 TEAM (CREATE_TIMESTAMP, PROJECT_GROUP_NAME, LAST_UPDATE_TIMESTAMP、STORE_ID、ID)值('2018-3-27 16:28:17.447000 +5:30:0','MMA_TEST','2018-3-27 16:28:17.503000 +5:30:0', 100, 21) 被中止。调用 getNextException 查看原因。], SQL: insert into TEAM (CREATE_TIMESTAMP, PROJECT_GROUP_NAME, LAST_UPDATE_TIMESTAMP、STORE_ID、ID)值(?、?、?、?、?)

从异常中可以看出,它是使用 datalayerGenericService 创建团队、用户 1 和用户 2。但尝试再次执行以给出 AbstractBatchImpl.release : HHH000010: 在批处理发布时它仍然包含 JDBC 语句。

这是我得到的例外:

java.sql.BatchUpdateException:批处理条目 1 插入 TEAM (CREATE_TIMESTAMP、PROJECT_GROUP_NAME、LAST_UPDATE_TIMESTAMP、 STORE_ID, ID) 值 ('2018-3-29 12:9:26.611000 +5:30:0', 'MMA_TEST', '2018-3-29 12:9:26.836000 +5:30:0', 100, 23) 被中止。称呼 getNextException 来查看原因。

我该如何解决这个问题?为什么查询会执行两次?

如果 EJB 方法发生任何异常,它应该回滚事务。但它没有发生

注意:如果我从服务中删除 @Transactional 注释,它可以正常工作。 我使用的是 TomEE 7.0.2 服务器。

【问题讨论】:

  • 您已将事务指定为NOT_SUPPORTED,因此不会启动任何事务。请改用REQUIRED。此外,这里不涉及 EJB 内容,无论您添加了这些注释。 Spring 不会启动 EJB 容器,因此它只是一个普通的 Spring bean。
  • 方法中有注解@TransactionAttribute(TransactionAttributeType.REQUIRED)。所以这里涉及到 EJB 的东西。
  • 不,没有...您只是在使用默认事务注释,它不会使其成为 EJB。添加所有这些接口和注释不会给您带来任何好处,只会增加 Spring 默默忽略的代码的复杂性和开销(除了 Transactional,因为 spring 确实支持这一点)。
  • 那么,如果我理解你的评论,你是说 DatalayerServiceImpl 不是 EJB?
  • 正确,它只是一个 Spring Bean。 Spring 不是 EJB 容器...

标签: spring spring-boot jpa transactions ejb-3.0


【解决方案1】:

从技术上讲,您既不会插入用户也不会插入团队。您将它们持久化到 PersistenceContext。当你的代码离开时

@Transactional(rollbackFor = {ServiceExpectedException.class,FatalException.class,MandatoryParameterMissingFatalException.class})
    public void createUser()

只要您根据需要标记它,它就必须被提交或刷新或会话关闭。它在第一次插入(团队)时失败,因为您没有上面列出的任何内容。

是的 - 你在这里使用来自 EJB 的注释。实际上,您使用的是 Hibernate,并且这里只有 @Transactional 作为 Spring 服务注释有效。

【讨论】:

    【解决方案2】:

    我是如何解决这个问题的?

    我被误解为这里涉及 EJB 的东西 但是@M。 Deinum 澄清说这里不涉及 EJB,不管我添加了这些注释,这意味着我的 DatalayerServiceImpl 只是一个 SpringBean。 添加所有这些接口和注释并没有给我任何东西,只是增加了 Spring 默默忽略的代码的复杂性和开销(除了 Transactional,因为 Spring 确实支持这一点)。

    针对我的问题,我已经声明了 Team In Users 类

    @ManyToOne(cascade={CascadeType.PERSIST},fetch=FetchType.LAZY)
    @JoinColumn(name="TEAM_ID",nullable=false)
    @JsonBackReference
    private Team team;
    

    在创建用户时,我将 Created 团队实例引用到用户类

    我在做

    Team team = new Team(simpleContextService);
    team.setGroupName("MMA_TEST");
    team.setStoreId(100);
    // Team
    Long teamOid = datalayerGenericService.updateWithId(team);
    
    Users user1 = new Users(simpleContextService);
    ...Set other fields
    user1.setTeam(team);
    

    正如团队声明为Cascade type Persist inside Users,它试图在持久化用户时插入团队。

    所以我已将Cascade type 更改为 MERGE。所以它工作正常。

    【讨论】:

      猜你喜欢
      • 2012-01-29
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多