一起使用 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 服务注释在这里有效。
我在尝试将实体添加到数据库时遇到错误。我提到了
我有一个 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 stillcontained 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 服务注释在这里有效。