Spring中事务的理解
什么是事务?
数据库操作最基本单元,逻辑上一组操作,要么都成功,否则失败。典型场景:银行转账。
四大特性:原子、一致、隔离、持久性。ACID特性。
原子性:要么都成功,不可分割,一个失败都都失败。
一致性:操作前后总量不变。比如两人都有100块钱,一共200,一个人转给另一个人后总量还是200
隔离性:多事务操作相互不会产生影响。比如两人都去操作同一条记录,两人间互不应影响。
持久性:提交之后,表中数据真正发生变化。
事务操作(搭建操作环境,以转账为例)
示例图:
步骤:
1、创建数据库,添加记录
2、创建service和dao,完成对象创建和注入关系
service:
//转账 public void account() { userDao.reduce(); userDao.addmoney(); }
dao:
public interface UserDao { public void update(); public void addmoney(); public void reduce(); }
@Override public void addmoney() { String sql="update count set money=money+? where username=?"; jdbcTemplate.update(sql,100,"李四"); } @Override public void reduce() { String sql="update count set money=money-? where username=?"; jdbcTemplate.update(sql,100,"张三"); }
3:问题:如果上述过程出现异常,会出现问题
如何用事务解决:
事务操作(Spring事务管理介绍)
1、一般添加到service层
2、在spring中进行事务管理操作
1、声明式事务管理(常用)
2、编程式事务管理
3、声明式事务管理
1、基于注解
2、基于配置文件
4、在Spring进行声明事务管理,底层使用AOP思想。
5、事务管理API
(1)、提供一个接口,代表事务管理器,这个接口提供不同框架的不同实现类
事务操作(注解式)
1、在配置文件中配置事务管理器
<!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean>
2、开启事务注解
1、配置文件中引入tx命名空间
2、开启事务注解
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service类或方法上加事务注解:@Transactional
事务操作(声明式事务管理参数配置)
1、
2、propagation:事务传播行为
1、多事务方法直接进行调用,这个过程中事务是如何进行管理的
3、isolation:事务隔离级别
不考虑隔离性会出现三个问题
1、脏读:一个未提交事务读取到了另一个未提交事务的数据
2、不可重复读:一个未提交事务读取到了另一个提交事务的数据
3、幻读:一个未提交事务读取到了另一个提交事务的添加数据
设置事务隔离级别:Mysql默认用的是可重复读
4、timeout:超时时间
5、readOnly:是否只读
6、rollbackFor:回滚
7、norollbackFor:不回滚
事务操作(完全注解,使用配置类)
1、创建配置类
@Configuration @ComponentScan(basePackages = "org.zhaojianhui.Spring") @EnableTransactionManagement//开启事务 public class txConfig { //创建数据库连接池 @Bean public DruidDataSource getDruid(){ DruidDataSource druidDataSource=new DruidDataSource(); druidDataSource.setDriverClassName(""); druidDataSource.setUrl(""); druidDataSource.setUsername(""); druidDataSource.setPassword(""); return druidDataSource; } }
整合日志框架
Spring5建议使用log4j2,整合如下:
1、引入依赖:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.11.2</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency>
2、根目录下创建log4j2.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration status="INFO"> <appenders> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </console> </appenders> <loggers> <root level="info"> <appenderRef ref="Console"/> </root> </loggers> </configuration>
@Nullable注解
1、可以使用在方法、属性、参数上面,表示方法返回可以为空、属性值可以为空、参数值可以为空。
2、
Spring5整合Junit4
1、引入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.0.RELEASE</version> </dependency>
2、创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class)//单元测试框架 @ContextConfiguration("classpath:bean2.xml")//加载配置文件 public class Test4 { @Autowired private UserService userService; @Test public void test1() { userService.account(); } }
Spring5整合Junit5
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean2.xml")//加载配置文件
//@SpringJUnitConfig(locations = "classpath:bean2.xml") 上面的一种简化
public class Test4 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.account();
}
}