EJB如何管理事务

目录

参考文章

前言:

1. @TransactionManagement

2. @TransactionAttribute

3. @ApplicationException

4. @EJB

5. @Stateless 和 @Stateful

5. 补充说明-★★★EJB中的有状态与无状态(类似单例模式)★★★:

5.【使用 @Stateful 时,出现 passivation capable dependencies  】

6. @PostConstruct 和 @PreDestroy

7.不使用容器管理事务时,可以使用 @Stateless 吗

1. @Stateless 与事务管理的关系

2. 使用 @Stateless 并启用 Bean 管理事务

3. 如何在 @Stateless 中使用 Bean 管理事务

4. 推荐做法

5. @Stateful 与 Bean 管理事务

8.EJP, 使用原生JPA连接数据库,如何设置事务隔离级别

9.介绍一下 EJB 的 CMT 和 BMT

10.什么时候能发生 EJBTransactionRollbackException

11.EJB容器控制事务时,方法中抛出什么异常,事务才能回滚

RuntimeException及其子类:

Error及其子类:

应用异常(Application Exception):

总结1

总结2

■扩展

1.Spring管理事务


===

参考文章

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

IBM Documentation

========
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

===

特性CMTBMT
事务管理由容器自动管理由开发者手动管理
代码复杂度
灵活性较低较高
适用场景简单业务逻辑复杂业务逻辑
事务传播自动处理需要手动控制
事务边界方法级别方法内部任意位置
事务属性支持声明式配置不支持声明式配置

===


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");
        }
    }
}

==

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值