![]() |
Java源码分析在 Spring 中,如何基于注解来配置事务详解 |
珠江路在线
2019年9月9日
【
转载
】来一杯82年的Jav 编辑:
|
|
Spring 提供了基于注解的事务配置,即对需求事务加强的 Bean 接口 、 实现类或者步骤进行标注@Transactional,而后在容器中配置基于注解的事务加强驱动,即可使用基于注解的申明式事务 。
1 配置事务示例
我们使用 @Transactional 来为业务类配置事务:
@Service @Transactional public 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); } }
运行日志:
从日志中能够看出,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 @Transactional public 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={}", user); }
操纵台输出后果:
从输出后果中我们能够看出,在调用该步骤时,事务加入了只读属性 。
本文到这里就结束了,喜爱的朋友能够帮忙转发和关注一下,感激支撑!