一起使用 Spring 和 EJB 事务

Use Spring and EJB transaction together

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

我有一个 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

我遇到以下异常。

INFO: (com.edifixio.springboot.service.impl.UserServiceImpl)

####################### teamOid 20 INFO: (com.edifixio.springboot.service.impl.UserServiceImpl) ####################### Added User1 ##################################### INFO: (com.edifixio.springboot.service.impl.UserServiceImpl) ####################### Added User2 ##################################### INFO : http-nio-6180-exec-1 : AbstractBatchImpl.release : HHH000010: On release of batch it still

contained JDBC statements 2018-03-27 16:28:17,683 : ERROR : http-nio-6180-exec-1 : BatchingBatch.performExecution : HHH000315: Exception executing batch [java.sql.BatchUpdateException: Batch entry 0 insert into TEAM (CREATE_TIMESTAMP, PROJECT_GROUP_NAME, LAST_UPDATE_TIMESTAMP, STORE_ID, ID) values ('2018-3-27 16:28:17.447000 +5:30:0', 'MMA_TEST', '2018-3-27 16:28:17.503000 +5:30:0', 100, 21) was aborted. Call getNextException to see the cause.], SQL: insert into TEAM (CREATE_TIMESTAMP, PROJECT_GROUP_NAME, LAST_UPDATE_TIMESTAMP, STORE_ID, ID) values (?, ?, ?, ?, ?)

正如您从异常中看到的,它正在使用 datalayerGenericService 创建 team、user1 和 user2。但是尝试再次执行以提供 AbstractBatchImpl.release:HHH000010:在批处理发布时它仍然包含 JDBC 语句。

这是我得到的异常:

java.sql.BatchUpdateException: Batch entry 1 insert into TEAM (CREATE_TIMESTAMP, PROJECT_GROUP_NAME, LAST_UPDATE_TIMESTAMP, STORE_ID, ID) values ('2018-3-29 12:9:26.611000 +5:30:0', 'MMA_TEST', '2018-3-29 12:9:26.836000 +5:30:0', 100, 23) was aborted. Call getNextException to see the cause.

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

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

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

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

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

针对我的问题,我已在用户中声明团队 class

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

在创建用户时,我将创建的团队实例引用给用户 class

我在做

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 在用户内部持久化,它试图在持久化用户时插入团队。

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

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

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

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

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