目录
5. 补充说明-★★★EJB中的有状态与无状态(类似单例模式)★★★:
5.【使用 @Stateful 时,出现 passivation capable dependencies 】
6. @PostConstruct 和 @PreDestroy
7.不使用容器管理事务时,可以使用 @Stateless 吗
2. 使用 @Stateless 并启用 Bean 管理事务
3. 如何在 @Stateless 中使用 Bean 管理事务
8.EJP, 使用原生JPA连接数据库,如何设置事务隔离级别
10.什么时候能发生 EJBTransactionRollbackException
11.EJB容器控制事务时,方法中抛出什么异常,事务才能回滚
===
参考文章
JPA、EJB、事务管理、WebSphere ---相关内容整理_ejb jpa-优快云博客
前言:
在 EJB(Enterprise JavaBeans) 中,事务管理也是一个核心功能。EJB 提供了类似于 Spring 的注解来控制事务行为。以下是 EJB 中常用的与事务管理相关的注解及其作用:
1. @TransactionManagement
作用:指定 EJB 的事务管理方式(容器管理或 Bean 管理)。
类全称:javax.ejb.TransactionManagement
属性:
value:可以是 TransactionManagementType.CONTAINER(容器管理事务,默认)或 TransactionManagementType.BEAN(Bean 管理事务)。
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class MyEJB {
// 业务逻辑
}
===
2. @TransactionAttribute
作用:指定 EJB 方法的事务属性(类似于 Spring 的 @Transactional)。
类全称:javax.ejb.TransactionAttribute
属性:
value:指定事务传播行为,可以是以下枚举值:
TransactionAttributeType.REQUIRED:如果当前存在事务,则加入该事务;否则创建一个新事务。
TransactionAttributeType.REQUIRES_NEW:总是创建一个新事务,如果当前存在事务,则挂起当前事务。
TransactionAttributeType.SUPPORTS:如果当前存在事务,则加入该事务;否则以非事务方式执行。
TransactionAttributeType.NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务。
TransactionAttributeType.MANDATORY:如果当前存在事务,则加入该事务;否则抛出异常。
TransactionAttributeType.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
@Stateless
public class MyEJB {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void doSomething() {
// 业务逻辑
}
}
===
3. @ApplicationException
作用:指定某个异常是否触发事务回滚。
类全称:javax.ejb.ApplicationException
属性:
rollback:如果为 true,则当抛出该异常时触发事务回滚;默认为 false。
@ApplicationException(rollback = true)
public class MyException extends Exception {
// 自定义异常
}
===
4. @EJB
作用:用于注入 EJB 实例。
类全称:javax.ejb.EJB
说明:虽然不直接用于事务管理,但在 EJB 中,事务通常是通过容器管理的,因此注入的 EJB 实例会继承容器的事务行为。
@Stateless
public class MyEJB {
@EJB
private AnotherEJB anotherEJB;
public void doSomething() {
anotherEJB.doSomethingElse();
}
}
===
5. @Stateless 和 @Stateful
作用:定义 EJB 的类型(无状态或有状态)。
类全称:
javax.ejb.Stateless
javax.ejb.Stateful
说明:事务行为通常与 EJB 的类型相关。无状态 Bean(@Stateless)通常更适合容器管理事务。
@Stateless
public class MyStatelessEJB {
// 业务逻辑
}
@Stateful
public class MyStatefulEJB {
// 业务逻辑
}
---
5. 补充说明-★★★EJB中的有状态与无状态(类似单例模式)★★★:
1.Stateful session bean的每个用户都有自己的一个实例,所以两者对stateful session bean的操作不会影响对方。另外注意:如果后面需要操作某个用户的实例,你必须在客户端缓存Bean的Stub对象(JSP通常的做法是用Session缓存),这样在后面每次调用中,容器才知道要提供相同的bean实例。
2.Stateless Session Bean不负责记录使用者状态,Stateless Session Bean一旦实例化就被加进会话池中,各个用户都可以共用。如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响。
红字部分的内容,已经在实际代码中得到检证,相当于在单例模式的类中,定义全局变量。
3.从内存方面来看,Stateful Session Bean与Stateless Session Bean比较,Stateful Session Bean会消耗J2EE Server 较多的内存,然而Stateful Session Bean的优势却在于他可以维持使用者的状态。
====
JPA、EJB、事务管理、WebSphere ---相关内容整理_ejb jpa-优快云博客
==
==
5.【使用 @Stateful 时,出现 passivation capable dependencies 】
===
passivation capable dependencies
========
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException:
Passivation scoped defined bean must be passivation
capable, but bean : Name:myCDIBean,WebBeans Type:MANAGED,API
Types:[com.ibm.websphere.samples.myCDIBean java.io.Serializable,java.lang.
Object,com.ibm.websphere.samples.myLocalIface],
Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.
Default,javax.inject.Named] is not passivation capable
========
passivation 英 / ˌpæsɪˈveɪʃən / n. 钝化;钝化处理
========
Passivation scoped是指在EJB中,当Stateful Session Bean不被使用时,容器将其序列化到磁盘或其他持久化媒体以释放内存,并在需要时将其恢复。这个过程被称为Passivation。Passivation是为了减少内存消耗,当Stateful Session Bean没有被活跃使用时,将其序列化和移除内存,节省资源
========
capable 有能力的;有本领的,能干的;可以……的,容许……的
dependencies 依赖性,相关性;管理
JavaEE使い方メモ(EJB) #glassfish - Qiita
=================
@Stateful
public class StatefulSessionBean implements Serializable{
=================
===
6. @PostConstruct 和 @PreDestroy
作用:用于定义 Bean 的生命周期回调方法。
类全称:
javax.annotation.PostConstruct
javax.annotation.PreDestroy
说明:虽然不直接用于事务管理,但这些方法可以在事务开始前或结束后执行一些逻辑
@Stateless
public class MyEJB {
@PostConstruct
public void init() {
// 初始化逻辑
}
@PreDestroy
public void cleanup() {
// 清理逻辑
}
}
7.不使用容器管理事务时,可以使用 @Stateless 吗
在 EJB(Enterprise JavaBeans) 中,@Stateless 注解通常与 容器管理事务(Container-Managed Transactions, CMT) 一起使用,因为无状态 Bean(@Stateless)的设计初衷是让容器管理其生命周期和事务行为。
然而,EJB 规范 也允许在 @Stateless Bean 中使用 Bean 管理事务(Bean-Managed Transactions, BMT),但这并不是推荐的做法。
1. @Stateless 与事务管理的关系
默认行为:@Stateless Bean 默认使用 容器管理事务(CMT),即事务由容器自动管理,开发者无需显式控制事务的开始、提交或回滚。
Bean 管理事务(BMT):如果显式指定为 Bean 管理事务(通过 @TransactionManagement(TransactionManagementType.BEAN)),则开发者需要手动管理事务(使用 UserTransaction)。
2. 使用 @Stateless 并启用 Bean 管理事务
虽然技术上可行,但在 @Stateless Bean 中使用 Bean 管理事务(BMT)并不推荐,原因如下:
无状态性:@Stateless Bean 是无状态的,容器可能会在方法调用之间重用 Bean 实例。如果手动管理事务,可能会导致事务状态不一致。
复杂性:手动管理事务会增加代码的复杂性,容易引入错误(如忘记提交或回滚事务)。
性能问题:手动管理事务可能会导致事务持续时间过长,影响性能。
3. 如何在 @Stateless 中使用 Bean 管理事务
如果确实需要在 @Stateless Bean 中使用 Bean 管理事务,可以按照以下步骤实现:
步骤 1:指定事务管理方式为 BEAN
使用 @TransactionManagement(TransactionManagementType.BEAN) 注解显式指定事务管理方式为 Bean 管理事务。
步骤 2:注入 UserTransaction通过 @Resource 注解注入 UserTransaction 对象,用于手动控制事务。
步骤 3:手动管理事务在方法中显式调用 UserTransaction 的 begin()、commit() 和 rollback() 方法。
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.transaction.UserTransaction;
@Stateless
@TransactionManagement(TransactionManagementType.BEAN) // 指定为 Bean 管理事务
public class MyStatelessBean {
@Resource
private UserTransaction userTransaction; // 注入 UserTransaction
public void doSomething() {
try {
// 开始事务
userTransaction.begin();
// 业务逻辑
// ...
// 提交事务
userTransaction.commit();
} catch (Exception e) {
try {
// 回滚事务
userTransaction.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
4. 推荐做法
优先使用容器管理事务(CMT):对于 @Stateless Bean,推荐使用容器管理事务,因为容器可以更好地管理事务的生命周期,减少代码复杂性。
仅在必要时使用 Bean 管理事务(BMT):如果确实需要更细粒度的事务控制(例如跨多个方法的事务),可以考虑使用 @Stateful Bean 并启用 Bean 管理事务。
5. @Stateful 与 Bean 管理事务
如果需要在 Bean 中手动管理事务,通常更推荐使用 @Stateful Bean,因为有状态 Bean 可以更好地维护事务状态。
==
import javax.annotation.Resource;
import javax.ejb.Stateful;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.transaction.UserTransaction;
@Stateful
@TransactionManagement(TransactionManagementType.BEAN) // 指定为 Bean 管理事务
public class MyStatefulBean {
@Resource
private UserTransaction userTransaction; // 注入 UserTransaction
public void doSomething() {
try {
// 开始事务
userTransaction.begin();
// 业务逻辑
// ...
// 提交事务
userTransaction.commit();
} catch (Exception e) {
try {
// 回滚事务
userTransaction.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
==
8.EJP, 使用原生JPA连接数据库,如何设置事务隔离级别
===
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
public class MyService {
@PersistenceContext
private EntityManager entityManager;
public void performOperation() {
// 设置隔离级别
Query query = entityManager.createNativeQuery("SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
query.executeUpdate();
// 执行业务逻辑
// ...
}
}
===
9.介绍一下 EJB 的 CMT 和 BMT
===
特性 | CMT | BMT |
---|---|---|
事务管理 | 由容器自动管理 | 由开发者手动管理 |
代码复杂度 | 低 | 高 |
灵活性 | 较低 | 较高 |
适用场景 | 简单业务逻辑 | 复杂业务逻辑 |
事务传播 | 自动处理 | 需要手动控制 |
事务边界 | 方法级别 | 方法内部任意位置 |
事务属性 | 支持声明式配置 | 不支持声明式配置 |
===
EJB(Enterprise JavaBeans) 是 Java EE 平台的一部分,用于构建分布式、可扩展的企业级应用程序。EJB 提供了两种事务管理方式:容器管理事务(CMT,Container-Managed Transactions) 和 Bean 管理事务(BMT,Bean-Managed Transactions)。
以下是它们的详细介绍:1. 容器管理事务(CMT,Container-Managed Transactions)
概述
CMT 是 EJB 的默认事务管理方式。事务的生命周期由 EJB 容器(如 WildFly、GlassFish 等)自动管理。
开发者无需编写显式的事务管理代码,只需通过注解或部署描述符(ejb-jar.xml)声明事务行为。
特点简单易用:开发者只需关注业务逻辑,事务管理由容器负责。
声明式事务:通过注解或 XML 配置声明事务属性。
事务传播:容器自动处理事务的传播行为(如 REQUIRED、REQUIRES_NEW 等)。
事务属性EJB 提供了以下事务属性(通过 @TransactionAttribute 注解或 XML 配置):
REQUIRED:如果当前存在事务,则加入该事务;否则,创建一个新事务。
REQUIRES_NEW:总是创建一个新事务,如果当前存在事务,则挂起该事务。
MANDATORY:必须在一个已有的事务中执行,否则抛出异常。
SUPPORTS:如果当前存在事务,则加入该事务;否则,以非事务方式执行。
NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起该事务。
NEVER:必须在一个非事务上下文中执行,否则抛出异常。
2. Bean 管理事务(BMT,Bean-Managed Transactions)
概述
BMT 由开发者手动管理事务。
开发者需要显式地获取 UserTransaction 对象,并在代码中控制事务的开始、提交和回滚。
特点灵活性高:开发者可以完全控制事务的生命周期。
手动管理:需要显式调用事务 API(如 begin、commit、rollback)。
适合复杂场景:适用于需要精细控制事务的场景。
4. 选择 CMT 还是 BMT?
选择 CMT:如果你的业务逻辑相对简单,且不需要精细控制事务,推荐使用 CMT。
选择 BMT:如果你的业务逻辑复杂,需要手动控制事务的开始、提交和回滚,或者需要跨多个方法管理事务,推荐使用 BMT。
5. 注意事项
事务超时:在 CMT 中,可以通过配置设置事务超时时间;在 BMT 中,可以通过 UserTransaction.setTransactionTimeout 方法设置。
异常处理:在 CMT 中,默认情况下,系统异常(RuntimeException)会触发事务回滚;在 BMT 中,需要手动调用 rollback。
性能影响:BMT 的事务管理开销较大,可能影响性能。
总结
CMT 是 EJB 的默认事务管理方式,适合简单业务场景,事务由容器自动管理。BMT 提供更高的灵活性,适合复杂业务场景,事务由开发者手动管理。
根据具体需求选择合适的事务管理方式。
===
10.什么时候能发生 EJBTransactionRollbackException
EJBTransactionRollbackException 是 Java EE (Jakarta EE) 中与 EJB(Enterprise JavaBeans)相关的一个异常,通常发生在 EJB 事务管理过程中。它表示当前事务被标记为回滚(rollback),并且事务无法提交。以下是可能导致 EJBTransactionRollbackException 的常见场景:
1. 手动标记事务为回滚
在 EJB 中,可以通过调用 EJBContext.setRollbackOnly() 方法手动将当前事务标记为回滚。如果事务被标记为回滚,后续尝试提交事务时就会抛出 EJBTransactionRollbackException。
@Stateless
public class MyService {
@Resource
private EJBContext ejbContext;
public void performOperation() {
try {
// 业务逻辑
if (someErrorCondition) {
ejbContext.setRollbackOnly(); // 标记事务为回滚
}
} catch (Exception e) {
ejbContext.setRollbackOnly(); // 异常时标记事务为回滚
throw e;
}
}
}
2.如果在 EJB 方法中抛出未捕获的异常(RuntimeException 或其子类),EJB 容器会自动将当前事务标记为回滚,并抛出 EJBTransactionRollbackException。
@Stateless
public class MyService {
public void performOperation() {
// 业务逻辑
if (someErrorCondition) {
throw new RuntimeException("An error occurred"); // 未捕获的异常
}
}
}
3. 应用异常(Application Exception)
如果 EJB 方法中抛出了被标记为应用异常(@ApplicationException)的自定义异常,默认情况下事务会回滚,并抛出 EJBTransactionRollbackException。
@ApplicationException(rollback = true) // 默认 rollback = true
public class MyCustomException extends Exception {
// 自定义异常
}
@Stateless
public class MyService {
public void performOperation() throws MyCustomException {
// 业务逻辑
if (someErrorCondition) {
throw new MyCustomException("An application error occurred");
}
}
}
4. 事务超时
如果事务执行时间超过了配置的事务超时时间,EJB 容器会自动回滚事务,并抛出 EJBTransactionRollbackException。
11.EJB容器控制事务时,方法中抛出什么异常,事务才能回滚
在EJB(Enterprise JavaBeans)容器中,事务管理通常由容器自动处理。当你在EJB方法中抛出某些异常时,事务会自动回滚。具体来说,EJB容器会根据抛出的异常类型来决定是否回滚事务。
以下是在EJB方法中抛出哪些异常会导致事务回滚的规则:
RuntimeException及其子类:
如果方法抛出RuntimeException或其子类(例如NullPointerException、IllegalArgumentException等),容器会自动回滚事务。
Error及其子类:
如果方法抛出Error或其子类(例如OutOfMemoryError等),容器也会自动回滚事务。
应用异常(Application Exception):
应用异常通常是指那些继承自Exception但不继承自RuntimeException的异常。默认情况下,应用异常不会导致事务回滚。但是,你可以通过在异常类上使用
@ApplicationException注解,并设置rollback=true来指定该异常应该触发事务回滚
@ApplicationException(rollback=true)
public class MyAppException extends Exception {
// ...
}
这样,当MyAppException被抛出时,事务会自动回滚。
javax.ejb.ApplicationException
===
总结1
EJB 提供了 @TransactionManagement 和 @TransactionAttribute 等注解来控制事务行为。
事务管理方式可以是容器管理(默认)或 Bean 管理。
事务传播行为通过 TransactionAttributeType 枚举类来配置。
EJB 的事务管理与 Spring 的事务管理类似,但 EJB 更依赖于容器(如 Java EE 应用服务器)。
===
总结2
@Stateless Bean 可以使用 Bean 管理事务(BMT),但不推荐这样做,因为无状态 Bean 的设计初衷是让容器管理事务。
推荐使用容器管理事务(CMT),因为它更简单、更安全。
如果需要手动管理事务,建议使用 @Stateful Bean。
如果你有更多问题或需要进一步的帮助,请告诉我!
===
■扩展
1.Spring管理事务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 使用 REQUIRED 传播行为和 READ_COMMITTED 隔离级别
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public void createUser(String name, String email) {
User user = new User();
user.setName(name);
user.setEmail(email);
userRepository.save(user);
// 模拟异常,触发回滚
if (email == null) {
throw new RuntimeException("Email cannot be null");
}
}
// 使用 REQUIRES_NEW 传播行为
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(Long id, String newEmail) {
User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
user.setEmail(newEmail);
userRepository.save(user);
}
// 自定义回滚规则
@Transactional(rollbackFor = {Exception.class})
public void deleteUser(Long id) throws Exception {
userRepository.deleteById(id);
if (id == null) {
throw new Exception("Invalid user ID");
}
}
}
==