目录
一、Spring整合Junit
方便我们取出对象和读取配置文件,不用我们每次去都要获取配置文件获取bean。可以直接通过注入的方式获取对象。
1.导入依赖
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- spring整合junit的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
2. 编写测试类
在测试类上加上
@RunWith(SpringJUnit4ClassRunner.class)注解,指定让测试运行于Spring环境
@ContextConfiguration注解,指定Spring容器创建需要的配置文件或者配置类
@RunWith(SpringJUnit4ClassRunner.class)//让测试运行与Spring测试环境
@ContextConfiguration(locations = "classpath:配置文件1.xml")//设置Spring配置文件或者配置类
//@ContextConfiguration(classes = SpringConfig.class)
public class SpringTest {}
3.注入对象进行测试
在测试类中注入要测试的对象,定义测试方法,在其中使用要测试的对象。
@RunWith(SpringJUnit4ClassRunner.class)//让测试运行与Spring测试环境
@ContextConfiguration(locations = "classpath:配置文件1.xml")//设置Spring配置文件或者配置类
public class SpringTest {
// 想测哪个对象,就注入哪个对象
@Autowired
private UserService userService;
//定义测试方法
@Test
public void testUserService() {
userService.findById(10);
}
}
二、Spring声明式事务
1.事务的概念
保证一组数据库的操作,要么同时成功,要么同时失败
2.四大特性
- 隔离性
多个事务之间要相互隔离,不能互相干扰 - 原子性
指事务是一个不可分割的整体,类似一个不可分割的原子 - 一致性
保障事务前后这组数据的状态是一致的。要么都是成功的,要么都是失败的。 - 持久性
指事务一旦被提交,这组操作修改的数据就真的的发生变化了。即使接下来数据库故障也不应该对其有影响。
3.实现声明式事务
如果我们自己去对事务进行控制的话我们就需要值原来核心代码的基础上加上事务控制相关的代码。而在我们的实际开发中这种事务控制的操作也是非常常见的。所以Spring提供了声明式事务的方式让我们去控制事务。
只要简单的加个注解(或者是xml配置)就可以实现事务控制,不需要事务控制的时候只需要去掉相应的注解即可。
3.1 注解实现
1.配置事务管理器和事务注解驱动
在spring的配置文件中添加如下配置:
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--设置数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务的注解驱动
将使用@Transactional注解所标识的方法或类中所有的方法使用事务进行管理
transaction-manager属性设置事务管理器的id
若事务管理器的bean的id默认为transactionManager,则该属性可以不写
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
2.添加注解
在需要进行事务控制的方法或者类上添加@Transactional注解就可以实现事务控制。
@Transactional
public void transfer(Integer outId, Integer inId, Double money) {
//增加
accoutDao.updateMoney(inId,money);
// System.out.println(1/0);
//减少
accoutDao.updateMoney(outId,-money);
}
注意:如果加在类上,这个类的所有方法都会受事务控制,如果加在方法上,就是那一个方法受事务控制。
注意,因为声明式事务底层是通过AOP实现的,所以最好把AOP相关依赖都加上。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
3.2 xml方式实现
1.配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--设置数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2.配置事务切面
<!--配置事务通知-->
<tx:advice id="tx" transaction-manager="transactionManager">
<tx:attributes>
<!--
name="getUser" 代表给getUser方法加上事务处理。
也可以用通配符的方法,例如get*就是给所有get开头的方法加上事务处理
-->
<tx:method name="getUser" timeout="3"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="tx" pointcut="execution(* com.lx.servcie.impl.*.*(..))"></aop:advisor>
</aop:config>
4.属性配置
4.1事务传播行为propagation
当事务方法嵌套调用时,需要控制是否开启新事务,可以使用事务传播行为来控制。
测试案例:
@Service
public class TestServiceImpl {
@Autowired
AccountService accountService;
@Transactional
public void test(){
accountService.transfer(1,2,10D);
accountService.log();
}
}
public class AccountServiceImpl implements AccountService {
//...省略其他不相关代码
@Transactional
public void log() {
System.out.println("打印日志");
int i = 1/0;
}
}
属性 | 行为 |
---|---|
REQUIRED(必须要有) | 外层方法有事务,内层方法就加入。外层没有,内层就新建 |
REQUIRES_NEW(必须要有新事务) | 外层方法有事务,内层方法新建。外层没有,内层也新建 |
SUPPORTS(支持有) | 外层方法有事务,内层方法就加入。外层没有,内层就也没有 |
NOT_SUPPORTED(支持没有) | 外层方法有事务,内层方法没有。外层没有,内层也没有 |
MANDATORY(强制要求外层有) | 外层方法有事务,内层方法加入。外层没有。内层就报错 |
NEVER(绝不允许有) | 外层方法有事务,内层方法就报错。外层没有。内层就也没有 |
例如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void transfer(Integer outId, Integer inId, Double money) {
//增加
accoutDao.updateMoney(inId,money);
//减少
accoutDao.updateMoney(outId,-money);
}
4.2 隔离级别isolation
- Isolation.DEFAULT 使用数据库默认隔离级别
- Isolation.READ_UNCOMMITTED (读未提交)
- Isolation.READ_COMMITTED (读已提交)
- Isolation.REPEATABLE_READ (可重复读)
- Isolation.SERIALIZABLE (串行化)
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
public void transfer(Integer outId, Integer inId, Double money) {
//增加
accoutDao.updateMoney(inId,money);
//减少
accoutDao.updateMoney(outId,-money);
}
4.3 只读readOnly
如果事务中的操作都是读操作,没涉及到对数据的写操作可以设置readOnly为true。这样可以提高效率。
@Transactional(readOnly = true)
public void log() {
System.out.println("打印日志");
int i = 1/0;
}