JDBCTemplate
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O27BTim6-1640144673736)(.\img\009.jpg)]
xml配置 JDBCTemplate
<!--对JdbcTemplate进行IOC-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入数据源对象-->
<property name="dataSource" ref="dataSource"/>
</bean>
装配JDBCTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
增改查操作
String sql = "insert into t_emp (emp_name,emp_salary) values (?,?)";
jdbcTemplate.update(sql,"aobama",3000d);
String sql = "update t_emp set emp_name=?,emp_salary=? where emp_id=?";
jdbcTemplate.update(sql,"aolafu",6000d,1);
//查询员工的个数
String sql = "select count(emp_id) from t_emp";
Long count = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(count);
查询返回实体类
封装实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
}
借助RowMapper完成查询
在查询返回单列数据的时候,就该使用这个RowMapper
//查询多个员工信息,封装到List<Employee>中
String sql = "select emp_id empId,emp_name empName, emp_salary empSalary from t_emp";
List<Employee> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Employee.class));
System.out.println(list);
声明式事务的概述
配置事务管理器
在spring的xml配置文件中我们需要配置事务管理器
<!--对事务管理者做IOC配置-->
<!--
要开启注解方式声明式事务的支持
transaction-manager属性:表示使用哪个事务管理器对象来管理事务
如果你的事务管理器的id是transactionManager的话,可以省略该属性
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
注意:导入名称空间时有好几个重复的,我们需要的是 tx 结尾的那个。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2pkFDsR3-1640144673739)(.\img\008.jpg)]
在需要事务的方法上使用注解@Transactional就可以使用事务功能了
@Transactional
@Override
public void transfer(Integer fromId, Integer toId, Double money) {
//1. 转出账户扣款
accountDao.updateAccountMoney(fromId,-money);
int num = 10/0;
//2. 转入账户收款
accountDao.updateAccountMoney(toId,money);
}
debug查看事务管理器中的关键方法
事务属性
只读属性
对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。但是如果你的方法中执行写操作,那么就会报错
@Transactional(read-only=true)//read-only属性表示事务是否只读:默认值是false,如果设置为true那么当前事务中只能做数据库的读操作,不能做写操作
@Override
public void transfer(Integer fromId, Integer toId, Double money) {
//1. 转出账户扣款
accountDao.updateAccountMoney(fromId,-money);
//int num = 10/0;
//2. 转入账户收款
accountDao.updateAccountMoney(toId,money);
}
如果在设置了只读的事务中进行写操作会抛出下面异常:
Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
如果将@Transactional注解放在类上
@Transactional注解在类级别标记,会影响到类中的每一个方法。同时,类级别标记的@Transactional注解中设置的事务属性也会延续影响到方法执行时的事务属性。除非在方法上又设置了@Transactional注解。
,离它最近的@Transactional注解中的事务属性设置生效。
PS:Spring 环境下很多场合都有类似设定,一个注解如果标记了类的每一个方法那么通常就可以提取到类级别。但是,如果不是类中的所有方法都需要用到事务,则绝不允许将@Transaction注解放在类上
超时属性
事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。
此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。
概括来说就是一句话:超时回滚,释放资源。
回滚和不回滚的异常属性
默认情况
@Transactional
@Override
public void transfer(Integer fromId, Integer toId, Double money) throws ClassNotFoundException{
//1. 转出账户扣款
accountDao.updateAccountMoney(fromId,-money);
//什么是运行时异常:不需要在编译时处理的异常
//什么是编译时异常:需要在编译时就进行处理的异常
//默认情况是遇到运行时异常才回滚:
Class.forName("com.mysql.jdbc.Driveraaaaaa");
int num = 10/0;
//2. 转入账户收款
accountDao.updateAccountMoney(toId,money);
}
设置回滚的异常
- rollbackFor属性:需要设置一个Class类型的对象
- rollbackForClassName属性:需要设置一个字符串类型的全类名
@Transactional(rollbackFor = Exception.class)
设置不回滚的异常
在默认设置和已有设置的基础上,再指定一个异常类型,碰到它不回滚。
@Transactional(
noRollbackFor = FileNotFoundException.class
)
如果回滚和不回滚异常同时设置
当两者范围不同
不管是哪个设置范围大,都是在大范围内在排除小范围的设定。例如:
- rollbackFor = Exception.class
- noRollbackFor = FileNotFoundException.class
意思是除了 FileNotFoundException 之外,其他所有 Exception 范围的异常都回滚;但是碰到 FileNotFoundException 不回滚。
事务隔离级别属性
事务特性
事务包括四大特性:ACID
- A:原子性:事务是最小的工作单元,不可再分。
- B:一致性:事务必须保证多条DML语句同时成功或者同时失败。
- C:隔离性:事务A与事务B之间具有隔离。
- D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。
事务隔离级别
事务隔离性村子啊隔离级别,理论上隔离级别包括4个:
- 第一级别:读未提交(READ UNCOMMITTED):对方事务还没有提交,我们那当前事务就可以读取到对方未提交的数据。读未提交存在脏读现象:表示读到了脏的数据。
- 第二级别:读已提交(READ COMMITTED):对方事务提交之后的数据我方可以读取到。这种隔离级别解决了脏读现象。存在的问题:不可重复读。
- 第三级别:可重复读(REPEATABLE READ)这种隔离级别解决了:不可重复读问题。存在问题:读取到的数据是幻象。
- 第四级别:序列化/串行话读(SERIALIZABLE),解决所有的问题,但效率低。需要事务排队。
级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认隔离级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
2 | 读已提交 | read committed | 否 | 是 | 是 | Oracle |
3 | 可重复读 | repeatable read | 否 | 否 | 是 | MySQL |
4 | 串行化 | serializable | 否 | 否 | 否 | 最高的隔离级别 |
设置方式
在 @Transactional 注解中使用 isolation 属性设置事务的隔离级别。 取值使用 org.springframework.transaction.annotation.Isolation 枚举类提供的数值。
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
事务传播行为属性
事务的传播行为要研究的是是当两个方法嵌套执行的时候,外层方法的事务能否传播到内层方法以及怎么传播到外层方法
propagation属性
@Transactional 注解通过 propagation 属性设置事务的传播行为。它的默认值是:
Propagation propagation() default Propagation.REQUIRED;
propagation 属性的可选值由 org.springframework.transaction.annotation.Propagation 枚举类提供:
名称 | 含义 |
---|---|
REQUIRED 默认值 | 当前方法必须工作在事务中 如果当前线程上有已经开启的事务可用,那么就在这个事务中运行 如果当前线程上没有已经开启的事务,那么就自己开启新事务,在新事务中运行 所以当前方法有可能和其他方法共用事务 在共用事务的情况下:当前方法会因为其他方法回滚而受连累 |
REQUIRES_NEW 建议使用 | 当前方法必须工作在事务中 不管当前线程上是否有已经开启的事务,都要开启 |
在业务层中声明两个内层方法
@Transactional(propagation = Propagation.REQUIRED)
测试 REQUIRED 模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5kx2tTwm-1640144673741)(./img/015.png)]
效果:内层方法A、内层方法B所做的修改都没有生效,总事务回滚了。
过滤器或拦截器等类似组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MQSnTQAU-1640144673744)(./img/018.png)]
Spring5的新特性
相关注解
注解名称 | 含义 | 可标记位置 |
---|---|---|
@Nullable | 可以为空 | @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) |
@NonNull | 不应为空 | @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) |
@NonNullFields | 在特定包下的字段不应为空 | @Target(ElementType.PACKAGE) @TypeQualifierDefault(ElementType.FIELD) |
@NonNullApi | 参数和方法返回值不应为空 | @Target(ElementType.PACKAGE) @TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER}) |
整合junit5
导入依赖
在原有环境基础上增加如下依赖:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.1</version>
</dependency>
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AtguiguSpringConfiguration.class)
使用复合注解
@SpringJUnitConfig(AtguiguSpringConfiguration.class)
总结
1 、Spring 框架概述
(1)轻量级开源 JavaEE 框架,为了解决企业复杂性,两个核心组成:IOC 和 AOP
(2)Spring5.2.6 版本
2 、IOC 容器
(1)IOC 底层原理(工厂、反射等)
(2)IOC 接口(BeanFactory)
(3)IOC 操作 Bean 管理(基于 xml)
(4)IOC 操作 Bean 管理(基于注解)
3 、Aop
(1)AOP 底层原理:动态代理,有接口(JDK 动态代理),没有接口(CGLIB 动态代理)
(2)术语:切入点、增强(通知)、切面
(3)基于 AspectJ 实现 AOP 操作
4 、JdbcTemplate
(1)使用 JdbcTemplate 实现数据库 curd 操作
(2)使用 JdbcTemplate 实现数据库批量操作
5 、事务管理
(1)事务概念
(2)重要概念(传播行为和隔离级别)
(3)基于注解实现声明式事务管理
(4)完全注解方式实现声明式事务管理
6 、Spring5 新功能
(1)整合日志框架
(2)@Nullable 注解
(3)函数式注册对象
(4)整合 JUnit5 单元测试框架
(5)SpringWebflux 使用