做什么事儿都要稳住心态,切勿浮躁!
1.事务概念
什么是事务?
事务是数据库操作最基本的单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
典型场景: 银行转账
事务四个特性:
- 原子性:要么成功,要么失败
- 一致性:总量不变
- 隔离性:多事务操作的时候,事务与事务之间不受影响
- 持久性:事务提交后,数据库中的数据也会相应变化
2.事务操作–搭建事务操作环境
数据库操作 ---- 创建两个方法
- 少钱的方法
- 多钱的方法
业务操作 ---- 创建转账的方法
调用数据库中的两个方法
(1) 创建数据库表,添加记录
(2)创建service,搭建dao,完成对象创建和注入关系
- service注入dao,在dao中注入JdbcTemplate,在JdbcTemplate注入DateSource
(3)在dao创建两个方法:多钱和少钱,在service创建转账的方法
代码:
dao:
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
daoimpl:
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
//少钱 lucyz转账100给mary
@Override
public void reduceMoney() {
String sql = "update t_account set money= money- ? where username = ?";
jdbcTemplate.update(sql,100,"lucy");
}
//多钱
@Override
public void addMoney() {
String sql = "update t_account set money= money+ ? where username = ?";
jdbcTemplate.update(sql,100,"mary");
}
}
service;
@Service
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//转账方法
public void accountMoney(){
//lucy少一百
userDao.reduceMoney();
//mary多一百
userDao.addMoney();
}
}
配置文件:
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.cwy.txdemo" ></context:component-scan>
<!-- 配置连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:13306/user_db"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
上面代码会有一个问题,就是当执行完少钱的方法,此时出现异常,那么多钱的方法就无法执行,这就出问题了。
那么如何解决呢?
使用事务解决。
-
事务添加到java ee三层结构里面的Service层(业务逻辑层)
-
在Spring进行事务管理操作
- 有两种方式:编程式事务管理和声明式事务管理(使用)
-
声明式事务管理
- 基于注解方式(使用)
- 基于xml配置文件方式
-
在Spring进行声明式事务管理,底层就是使用AOP
-
Spring事务管理API
- 提供一个接口,代码事务管理器,这个接口针对不同的框架提供不同的实现类。
注解声明式事务管理
-
在Spring配置文件中配置事务管理器
<!-- 创建事务管理器--> <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
-
在Spring配置文件,开始事务注解
-
引入名称空间
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
-
开始事务注解
<!-- 创建事务管理器--> <tx:annotation-driven transaction-manager="TransactionManager"></tx:annotation-driven>
-
在Service类上面(Service类里面的方法上面)添加事务注解
-
@Transactional,这个注解添加到类上面,也可以添加方法上面
-
如果把这个注解添加到类上面,这个类里面的所有方法都添加事务
-
如果把这个类添加到方法上面,为这个方法添加事务
@Service @Transactional public class UserService {}
-
-
-
运行test类,发现数据库中的数据不变,当出现异常,事务回滚。
参数
- 在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
-
propagation:事务传播行为
- 多事务方法直接进行调用,这个过程中事务是如何进行管理的
- 多事务方法直接进行调用,这个过程中事务是如何进行管理的
-
ioslation:事务隔离级别
事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题:有三个读问题:脏读、不可重复读、虚(幻)读。
脏读:一个未提交事务读取到另一个未提交事务的数据
不可重复读:一个未提交事务读取到另一提交事务修改数据(但是修改完还没有提交就被未提交的事务读取了)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bsh6fIFb-1649656231385)(Spring概述.assets/image-20220410231055935.png)]
虚读:一个未提交事务读取到另一提交事务添加数据
解决:通过设置事务隔离级别,解决读问题
-
timeout:超时时间
- 事务在一定的时间内,需要提交,如果不提交就进行回滚
- 默认值是-1,设置时间以秒为单位
-
readOnly:是否只读
- 读:查询操作,写:添加修改删除操作
- readOnly默认值false,表示可以查询,可以添加修改删除操作
- 设置readOnly值是true,设置成true之后,只能查询
-
rollbackFor:回滚
- 设置出现哪些异常进行事务回滚
-
noRollbackFor:不回滚
- 设置出现哪些异常不进行事务回滚
XML声明式事务管理
在Spring配置文件中配置
-
配置事务管理器
<!-- 1.创建事务管理器--> <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
-
配置通知
<!-- 2.配置通知--> <tx:advice id="txadvice"> <!--配置事务参数--> <tx:attributes> <!--指定哪种规则的方法上面添加事务--> <tx:method name="accountMoney" propagation="REQUIRED"/><!--方法名可以是account* 即代表此方法--> </tx:attributes> </tx:advice>
-
配置切入点和切面
<!-- 3.配置切入点和切面--> <aop:config> <!-- 配置切入点--> <aop:pointcut id="pt" expression="execution(* com.cwy.txdemo.service.UserService.*(..))"/> <!-- 配置切面--> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor> </aop:config>
完全注解声明式事务管理
创建配置类,代替xml文件配置
@Configurable //配置类
@ComponentScan(basePackages = "com.cwy") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:13306/user_db");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){//从IOC容器中,找DataSource类型的作为参数输入
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getdataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}