Spring-TX

1.Spring-TX-传播行为

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    /**
     * 转账
     */
     @Transactional(propagation = Propagation.REQUIRED)
    public void  transfer(){
        
        userDao.reduceMoney(); // -100

        int i = 10/0;

        userDao.addMoney();   //  +100
    }

}

 propagation : 事务传播行为

事务方法 : 对数据库表数据进行变化的操作.

@Transactinal
public void add(){
    //调用update方法
    update();
}
public void update(){
    
}

Spring框架事务传播行为共有7种

REQUIRED :  如果add方法本身有事务 , 调用update方法之后 , update使用当前add方法里面事务,如果add方法本身没有事务 , 调用update方法之后 , 创建新事务 

REQUIRED_NEW :  使用add方法调用update方法 , add方法无论是否有事务 , 都创建新的事务

2.Spring-TX-隔离级别

事务有隔离性 , 多事务操作之间不会产生影响. 不考虑隔离性会产生很多问题.

有三个读问题 : 脏读 , 不可重复度 , 幻读.

2.1 脏读

一个未提交的事务读取到另一个未提交的事务的数据.

 

读到了回滚前的数据

2.2 不可重复读

一个未提交的事务读取到了另一个提交事务修改的数据.

2.3 幻读

一个未提交的事务读取到另一个提交事务添加的数据.

2.4 隔离级别

通过设置事务的隔离级别 , 解决读问题

 

 

@Transactional(propagation = Propagation.REQUIRED , isolation = Isolation.REPEATABLE_READ)

3.Spring-TX-其他参数

3.1 timeout

事务需要在一定时间内进行提交 , 如果不提交则进行回滚.

默认为 -1 , 设置时间以秒为单位进行计算.

 @Transactional(propagation = Propagation.REQUIRED , 
            isolation = Isolation.REPEATABLE_READ,
            timeout = 5
    )

3.2 readOnly

readOnly 默认值为 false , 表示可以查询 , 可以进行事务操作.

设置readOnly 为 true , 只能查询

 @Transactional(propagation = Propagation.REQUIRED ,
            isolation = Isolation.REPEATABLE_READ,
            timeout = 5,
            readOnly = false
    )

3.3 rollbackFor

设置出现哪些异常进行事务回滚.

3.4 noRollbackfor

设置出现哪些异常不进行事务回滚.

4.Spring-TX-完全注解开发

bean.xml

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql://192.168.64.140:3306/user_db?serverTimezone=UTC"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <context:component-scan base-package="com.nanoswarm"></context:component-scan>


    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

Config.class

@Configuration
@ComponentScan(basePackages = "com.nanoswarm.spring5")
@EnableTransactionManagement
public class SpringConfig {

    @Bean
    public DruidDataSource dataSource(){

        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://192.168.64.140:3306/user_db");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DruidDataSource dataSource){

        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager transactionManager(DruidDataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

TestMain.class

public class TestMain {

    @Test
    public void transfer(){

        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

        UserService userService = context.getBean("userService", UserService.class);
        userService.transfer();

    }
}

5.Spring-TX-整合日志框架

Spring5.0框架自带了通用的日志封装.

Spring5已经移除Log4jConfigListener , 官方建议使用Log4j2

5.1 Spring框架整合Log4j2

步骤一 : 引入jar包

 步骤二 : 创建log4j2.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

6.Spring-@Nullable注解和函数式注册对象

6.1 @Nullable

@Nullable注解可以使用在方法上面 , 属性上面 , 表示方法返回值可以为空 , 属性值可以为空 , 参数值可以为空.

6.2 函数式创建对象

@Test
    public void testGenericApplicationContext(){
        //创建GenericApplicationContext对象
        GenericApplicationContext context = new GenericApplicationContext();
        //调用context的方法对象注册
        context.refresh();
        context.registerBean("userBean", User.class,()->new User());
        //获取bean
        User userBean = context.getBean("userBean", User.class);
        System.out.println(userBean);
    }

7.Spring-WebFlux基本概念

  • Spring5添加的新的模块 , 用于web开发 , 功能和SpringMVC类似 , WebFlux使用当前一种比较流行的响应式编程出现的框架.

  • 使用传统web框架 , 比如 SpringMVC , 这些基于Servlet的容器 , Webflux是一种异步非阻塞的框架 , 核心是基于Reactor的相关API实现的.

  • 异步非阻塞 : 被调用者收到请求之后 , 完成请求任务之后才给出反馈就是阻塞, 受到请求之后马上给出反馈然后再去执行请求任务则为非阻塞.

7.1 WebFlux优势

  • 非阻塞式 : 在有限的资源下 , 提高系统吞吐量和伸缩性 , 以Reactor为基础实现响应式编程.

  • 函数式编程

7.2 与WebMVC的区别

  • SpringMVC采用命令式编程 , WebFlux异步响应式编程.

  • 两者都可以使用注解方式,都运行在Tomcat等容器中.

8.WebFlux-Code

8.1 响应式编程

电子表格程序就是响应式编程的一个例子 , 单元格可以包含字面值或者类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化.

8.2 观察者模式

java8提供的观察者模式中的两个类Observer和Observable

public class ObserveDemo extends Observable {
    public static void main(String[] args) {
        ObserveDemo observer = new ObserveDemo();
        //添加观察者
        observer.addObserver((ob,arg)-> System.out.println("发送变化A"));
        observer.addObserver((ob,arg)-> System.out.println("发送变化B"));
        
        observer.setChanged(); //数据变化
        observer.notifyObservers(); //通知
        
    }
}

9.webFlux-Reactor

  • 响应式编程操作中 , Reactor是满足Reactive规范的框架.

  • Reactor有两个核心类 , Mono和Flux , 这两个类实现接口Publisher , 提供丰富操作 , Flux对象实现发布者 , 返回N个元素 , Mono实现发布者 , 返回0或者1个元素.

  • Flux和Mono都是数据流的发布者 , 使用Flux和Mono都可以发出三种数据信号

    • 元素值

    • 错误信号

    • 完成信号

      • 错误信号和完成信号都代表终止信号 , 终止信号用于告诉订阅者数据流结束了 , 错误信号终止数据流同事把错误传递给订阅者.

  • 错误信号和完成信号都是终止信号 , 不能共存.

  • 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流.

  • 如果没有错误信号,没有完成信号,表示是无限数据流.

9.1 Code

pom

  <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>3.3.16.RELEASE</version>
        </dependency>

psvm

public class TestReactor {
    public static void main(String[] args) {
        //Object
        Flux.just(1,2,3,4);
        Mono.just(1);

        //数组
        Integer[] array = {1,2,3,4};
        Flux.fromArray(array);

        //集合
        List<Integer> list = Arrays.asList(array);
        Flux.fromIterable(list);

        //流
        Stream<Integer> stream = list.stream();
        Flux.fromStream(stream);
    }
}

发布订阅

public class TestReactor {
    public static void main(String[] args) {
        //Object
        Flux.just(1,2,3,4).subscribe((o)-> System.out.println(o));
        Mono.just(1).subscribe((o)-> System.out.println(o));
    }
}

调用just或者其他方法只是声明数据流 , 数据流并没有发出 , 只有进行订阅之后才会触发数据流 , 不订阅什么都不会发生.

9.2 操作符

  • map元素映射为新的元素

  •  flatMap元素映射为流

 把每个元素转换成流 , 把转换之后多个流合并成大的流.

10.WebFlux-执行流程和核心API

SpringWebflux 基于 Readctor , 默认使用容器是Netty , Netty是高性能的NIO框架 , 异步非阻塞的框架.

NIO

 

10.1 执行流程

SpringWebFlux核心控制器DispatchHandler , 实现接口WebHandler.

10.2 核心API

SpringWebflux 里面 DispatcherHandler , 负责请求的处理.

HandlerMapping : 请求查询到处理的方法.

HandlerAdapter : 真正负责请求处理.

HandlerResultHandler L相应结果处理.

  • SpringWebflux 实现函数式编程 , 两个接口 : RounterFunction (路由处理) 和 HandlerFunction(处理函数)

11.WebFlux-注解编程模型

SpringWebflux 实现方式有两种 , 注解编程模型和函数式编程模型.

使用注解编程模型方式和之前SpringMVC使用相似 , 只需要把相关依赖配置到项目中, SpringBoot自动配置相关运行容器 ,

默认情况下使用Netty服务器.

pom

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
  </dependency>

UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

    private final  Map<Integer,User> userMap = new HashMap<>();

    public UserServiceImpl() {
        userMap.put(1,new User("wwn","m",50));
        userMap.put(2,new User("gnx","f",60));
        userMap.put(3,new User("xjp","m",70));
    }

    @Override
    public Mono<User> findById(Integer id) {
        return Mono.justOrEmpty(this.userMap.get(id));
    }

    @Override
    public Flux<User> findAll() {
        return Flux.fromIterable(this.userMap.values());
    }

    @Override
    public Mono<Void> saveUser(Mono<User> userMono) {

        return userMono.doOnNext(user ->{
            int id = userMap.size() + 1;
            userMap.put(id,user);
        }).then(Mono.empty());//终止信号
    }
}

UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/info/{id}")
    public Mono<User> getById(@PathVariable("id") Integer id){
        return userService.findById(id);
    }

    @GetMapping("/all")
    public Flux<User> getAll(){
        return userService.findAll();
    }

    @PostMapping("/save")
    public Mono<Void> saveUser(@RequestBody User user){
        Mono<User> mono = Mono.just(user);
        return userService.saveUser(mono);
    }
}

11.1 区别

  • SpringMVC方式实现 , 同步阻塞的方式 , 基于 SpringMVC + Servlet + Tomcat

  • SpringWebFlux 方式实现 , 异步非阻塞的方式 , 基于 SpringWebflux + Reactor + Netty

12.Webflux-函数式编程模型(Handler)

  • 在使用函数式编程模型的时候 , 需要自己初始化服务器.

  • 基于函数式编程模型的时候 , 有两个核心接口 : RouterFunction (实现路由功能 , 请求转发给对应的handler) 和 HandlerFunction(处理请求生成响应的函数).核心任务定义两个函数式接口的实现并且启动需要的服务器.

  • SpringWebFlux请求和响应不再是ServletRequestServletResponse 而是 ServerRequest 和 ServerResponse

12.1 HandlerFunction

public class UserHandler {

    private final UserService userService;

    public UserHandler(UserService userService) {
        this.userService = userService;
    }

    /**
     * find by id
     */
    public Mono<ServerResponse> findById(ServerRequest  request){
        int userId = Integer.parseInt(request.pathVariable("id"));
        //空值判断
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();
        Mono<User> userMono = userService.findById(userId);
        //转换成流
        return userMono.flatMap(user ->ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(user))).switchIfEmpty(notFound);
    }

    /**
     * find all
     * @return
     */
    public Mono<ServerResponse> findAllUser(){
        Flux<User> users = this.userService.findAll();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class);
    }


    /**
     * add User
     */
    public Mono<ServerResponse> saveUser(ServerRequest request){
        Mono<User> userMono = request.bodyToMono(User.class);
        return ServerResponse.ok().build(this.userService.saveUser(userMono));
    }
}

12.2 HandlerFunction

public class Server {

    //创建Rounter路由
    public RouterFunction<ServerResponse> routingFunction(){

        //创建handler对象
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);
        //设置路由
        return RouterFunctions.route(
            GET("/user/{id}").and(accept(MediaType.APPLICATION_JSON)),userHandler::findById).andRoute(
                                      GET("/user").and(accept(MediaType.APPLICATION_JSON)),userHandler::findAllUser);
    }

}

12.3 服务器适配


    //创建服务器完成适配
    public void createReactorServer(){
        
        //路由和handler适配
        RouterFunction<ServerResponse> route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }
public class Server {

    //创建Rounter路由
    public RouterFunction<ServerResponse> routingFunction(){

        //创建handler对象
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);
        //设置路由
        return RouterFunctions.route(GET("/user/{id}").and(accept(MediaType.APPLICATION_JSON)),userHandler::findById).andRoute(
                                     GET("/user").and(accept(MediaType.APPLICATION_JSON)),userHandler::findAllUser);
    }

    //创建服务器完成适配
    public void createReactorServer(){

        //路由和handler适配
        RouterFunction<ServerResponse> route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }

}

psvm

 public static void main(String[] args) throws IOException {
        Server server = new Server();
        server.createReactorServer();
        System.out.println("enter to exit");
        System.in.read();
    }
package com.nanoswarm.webfluxdemo.server;

import com.nanoswarm.webfluxdemo.handler.UserHandler;
import com.nanoswarm.webfluxdemo.service.UserService;
import com.nanoswarm.webfluxdemo.service.impl.UserServiceImpl;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;


import java.io.IOException;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;

public class Server {

    public static void main(String[] args) throws IOException {
        Server server = new Server();
        server.createReactorServer();
        System.out.println("enter to exit");
        System.in.read();
    }


    //创建Rounter路由
    public RouterFunction<ServerResponse> routingFunction(){

        //创建handler对象
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);
        //设置路由
        return RouterFunctions.route(GET("/user/{id}").and(accept(MediaType.APPLICATION_JSON)),userHandler::findById).andRoute(
                                     GET("/user").and(accept(MediaType.APPLICATION_JSON)),userHandler::findAllUser);
    }

    //创建服务器完成适配
    public void createReactorServer(){

        //路由和handler适配
        RouterFunction<ServerResponse> route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }

}

13 webClient-调用

public class Client {
    public static void main(String[] args) {
        //调用服务器地址
        WebClient webClient = WebClient.create("http://127.0.0.1:63676");

        //根据id查询
        String id = "1";
        User userResult = webClient.get().uri("/user/{id}", id).
                accept(MediaType.APPLICATION_JSON).
                retrieve()
                .bodyToMono(User.class)
                .block();
        System.out.println(userResult.getName());

        //查询所有
        Flux<User> usersResult = webClient.get().uri("/user").
                accept(MediaType.APPLICATION_JSON).
                retrieve()
                .bodyToFlux(User.class);

        usersResult.map(user -> user.getName()).buffer().doOnNext(System.out::println).blockFirst();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值