事务
事务概念
1、什么是事务
事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败。
2、事务的四个特性(ACID)
(1)原子性:要么都成功,如果有一个失败所有操作都失败。
(2)一致性:事务必须是使数据库从一个一致性状态变到另一个一致性状态。
(3)隔离性:多事务操作彼此之间不会产生影响
(4)持久性:事务提交后表中数据发生持久变化
3、不同事务
编程式:自己写代码实现功能
声明式:通过配置让框架实现功能
事务操作
JavaEE三层结构:
Web层:视图
Service层:业务操作
Dao层:数据库操作,不写业务
1、创建数据库表,添加记录
2、创建service,搭建dao,完成对象创建和注入
(1)在service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入Datasource
3、在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney() {
String sql="update t_account set money=money+? where username=?";
jdbcTemplate.update(sql,100,"lucy");
}
@Override
public void reduceMoney() {
String sql="update t_account set money=money-? where username=?";
jdbcTemplate.update(sql,100,"mary");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void shift(){
userDao.reduceMoney();
userDao.addMoney();
}
}
4、如果上面的代码出现了异常,则会出现数据不一致问题
Spring事务操作
1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)
2、在Spring进行事务管理操作有两种方式:编程式事务管理和声明式事务管理(常用)
*编程式 *
- 第一步 开启事务
- 第二步 进行业务操作
- 第三步 没有发生异常,提交事务
- 第四步 出现异常 事务回滚
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP
5、Spring事务管理API
(1)提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同实现类。
事务操作(注解声明式事务管理)
1、在spring配置文件配置事务管理器
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2、在spring配置文件,开启事务注解
(1)在spring配置文件中引入新的名称空间tx(maven不用做这一步)
<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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
(2)开启事务注解
<!--创建事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务注解
将使用@Transactional注解所标识的方法或类中所有的方法使用事务进行管理
transaction-manager属性设置事务管理器的id
-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
3、在service类上面(或者service类里面的方法)添加事务注解@Transactional
(1)@Transactional,这个注解既可以添加到类上面,也可以添加到方法上面
(2)如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加到方法上面,则只是为这个方法添加事务
事务操作(声明式事务管理参数配置)
1、propagation:事务传播行为
当一个事务方法被另一个事务方法调用时候,这个事务方法如何进行。
事务方法A内调用事务方法B
**REQUIRED:**使用调用者的事务
**REQUIRED_NEW:**使用自己的事务
A开启外层事务T1,B开启T2内层事务,如果在T2执行完成后T1出现异常,T2不会回滚,依然正常提交。
SUPPORTS:
如果方法B单独执行,可以不开启事务。但如果方法A调用了方法B,B需要在A的事务中运行。
2、ioslation:事务隔离级别
(1)数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。事务有特效称为隔离性,多事务操作之间不会产生影响。不考虑隔离性会产生很多问题。
(2)有三个读问题:脏读、不可重复读、虚(幻)读
- 脏读:一个未提交的事务读取到了另一个未提交事务的数据(两个人同时操作一条记录,)
- 不可重复读:一个未提交的事务读取到了另一个事务提交修改的数据 (一个事务多次读取数据不一样)update
- 虚度:一个未提交事务读取到另一提交事务添加数据insert(记录数不一样)
(3)通过事务的隔离性解决读问题
msql默认REPEATABLE READ
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
3、timeout:事务需要在一定时间内进行提交,如果不提交则进行回滚。默认-1,表示一直等待事务提交,设置时间以秒为单位 timeout = 3
4、readOnly:是否只读 readOnly=false
(1)读:查询操作,写:添加修改删除操作
(2)readOnly默认false,表示可以查询,可以添加修改删除操作
(3)设置readOnly是true以后,就只能查询
5、rollback:回滚
(1)设置出现哪些异常进行事务回滚,默认不设置时所有异常都会回滚
6、noRollbackFor:不回滚
(1)noRollbackFor设置出现哪些异常时不进行事务回滚
@Transactional(
noRollbackFor = ArithmeticException.class
)
(2)noRollbackForClassName:要写异常对应的全类名
@Transactional(
noRollbackForClassName = "java.lang.ArithmeticException"
)
事务操作(XML声明式事务管理)
需要引入aspectJ的依赖
1、在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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.ayu.spring"/>
<!--数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://127.0.0.1:3305/user_db"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--1 创建事务管理器(这个地方id不能随意取)-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--2 配置通知-->
<tx:advice id="txadvice" >
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="shift" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3 配置切入点-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.ayu.spring.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
</beans>
事务操作(完全注解开发声明式事务管理)
1、创建配置类,使用配置类替代xml配置文件
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "com.ayu.spring.*")
public class TxConfig {
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://127.0.0.1:3305/user_db");
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource dataSource){
//到ioc容器中根据类型找到dataSource
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
//注入dataSource
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
@Bean
public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
}
@Test
public void test3(){
ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.shift();
}
Spring5框架新功能
1、整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
2、Spring5框架自带了通用的日志封装
(1)Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
(2)Spring5框架整合Log4j2
第一步 引入jar包
第二步 创建log4j2.xml(名字不可改)配置文件
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<Configuration status="INFO" monitorInterval="60">
<!-- <!– 变量配置 –>-->
<!-- appender配置 -->
<Appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %5p %X{traceId} -- %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
package com.ayu.spring.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Userlog {
public static final Logger log = LoggerFactory.getLogger(Userlog.class);
public static void main(String[] args) {
log.info("hello lxy");
log.warn("hello ayu");
}
}
3、支持@Nullable注解
(1)@Nullable可以使用在方法(方法返回值可以为空)、属性(属性可以为空)、参数上面(参数可以为空)。
4、Spring5核心容器支持函数式风格GenericApplicationContext
//函数式风格创建对象,交给spring进行管理
@Test
public void testApplicationContext(){
//1 创建GenericApplicationContext对象
GenericApplicationContext context = new GenericApplicationContext();
//2 调用context的方法对象注册
context.refresh();// 不需要参数,返回值为new User()
context.registerBean("user1",User.class,()->new User());
//3 获取在spring注册的对象
User user =context.getBean("user1",User.class);
System.out.println(user);
}
5、Spring5支持整合JUnit5
(1)整合JUnit4
第一步 引入Spring相关针对测试的依赖
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean.xml")
public class JTest4 {
@Autowired
private UserService userService;
@Test
public void mytest(){
userService.shift();
}
}
(2)Spring5整合JUnit5
第一步 引入JUnit5的jar包
第二步 创建测试类,使用注解完成
@SpringJUnitConfig(locations = "classpath:bean.xml")
Webflux
1、什么是Webflux
2、响应式编程
3、Webflux执行流程和核心API
4、SpringWebflux(基于注解编程模型)
5、4、SpringWebflux(基于函数式编程模型)