@order注解_Java源码分析在 Spring 中,如何基于注解来配置事务详解

点关注,不迷路;持续更新Java相关技术

32a070d3aa3956d89a906e320e9c3384.png

Spring 提供了基于注解的事务配置,即对需要事务增强的 Bean 接口 、 实现类或者方法进行标注@Transactional,然后在容器中配置基于注解的事务增强驱动,即可使用基于注解的声明式事务 。

1 配置事务示例

我们使用 @Transactional 来为业务类配置事务:

@Service@Transactionalpublic class UserService { @Autowired private UserDao userDao; /** * 新增 * * @param user */ public int addUser(final User user) { return userDao.save(user); } /** * 依据 Id,获取账号 * * @param userId * @return */ public User getUser(Long userId) { return userDao.get(userId); } /** * 更新账号所对应的密码 * @param userId * @param pwd */ public int update(Long userId, String pwd) { return userDao.update(userId, pwd); }}

接着在 Spring 配置文件中, 告知 Spring 容器对标注了 @Transactional 注解的 Bean,织入事务管理切面:

在默认情况下, 会自动使用名为 transactionManager 的事务管理器, 所以,如果我们的事务管理器就叫做 transactionManager ,那么就可以进一步简化为

拥有以下属性:

属性 默认值 说明 transaction-manager transactionManager 事务管理器 Bean ID proxy-target-class false true 表示将通过创建子类来代理业务类(需要在类路径中添加 CGlib.jar 类库); false 表示使用基于接口来代理 。 order - 如果业务类除了需要事务切面之外,还需要织入其他切面,那么可以通过该属性,来控制事务切面在目标连接点中的织入顺序。 单元测试:

public class UserServiceTest { ApplicationContext context; @BeforeMethod public void setUp() throws Exception { context = new ClassPathXmlApplicationContext("spring_anno.xml"); } @Test public void testAddUser() throws Exception { UserService userService = (UserService) context.getBean("userService"); final User user = new User("deniro"); userService.addUser(user); }}

运行日志:

ff48b173ee7a2dbbfeb4b58ee143da57.png

从日志中可以看出,Spring 容器为这个类的所有方法,都织入了事务管理功能。

2 @Transactional 属性

@Transactional 拥有以下这些属性:

属性 默认值 说明

propagation PROPAGATION_REQUIRED 事务传播行为。

可通过org.springframework.transaction.annotation.Propagation枚举类,来提供合法值,

例:@Transactional(propagation=Propagation.SUPPORTS) isolation ISOLATION_DEFAULT 事务隔离级别。

可通过 org.springframework.transaction.annotation.Isolation 枚举类,来提供合法值,例:@Transactional(isolation=Isolation.READ_UNCOMMITTED) readOnly false 是否可读写事务。

例:@Transactional(readOnly=true) timeout 使用底层事务系统的默认值 超时时间,单位为秒。

例: @Transactional(timeout=3) rollbackFor 回滚所有运行期异常。 需要回滚的一组异常类,类型为 Class[], 多个异常类使用逗号分隔。

例:@Transactional(rollbackFor={SQLException,class}) 。 rollbackForClassName {} 需要回滚的一组异常类,类型为 String[]。

例:@Transactional(rollbackForClassName={“xxxException”}) noRollbackFor {} 不需要回滚的一组异常类,类型为 Class extends Throwable>[]。 noRolbackForClassName {} 不需要回滚的一组异常类,类型为 String[]。

3 标注位置

@Transactional 注解可以被标注于接口定义、接口方法 、 类定义和类的 Public 方法上 。

但如果 @Transactional 注解被标注在业务接口上,那么如果启用了子类代理:

那么被代理的业务类并不会织入事务增强,仍然工作在非事务环境下。这显然不是我们想看到的。

建议在具体业务类上使用 @Transactional 注解,这样不管是否开启子类代理模式,业务类都会织入事务增强。

也可以在直接在方法上定义注解。

方法上定义的注解会覆盖类定义的注解,比如有些方法需要使用到特殊的事务属性,那么就可以直接在方法上定义注解。

在以下示例中,我们在 getUser() 方法上设置了只读事务属性:

@Service@Transactionalpublic class UserService { @Autowired private UserDao userDao; /** * 依据 Id,获取账号 * * @param userId * @return */ @Transactional(readOnly = true) public User getUser(Long userId) { return userDao.get(userId); } ...}

单元测试:

 @Test public void testGetUser() throws Exception { UserService userService = (UserService) context.getBean("userService"); User user = userService.getUser(1l); logger.info("user={}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值