【spring使用@Async註解異步處理】

1. 何爲異步調用?
在解釋異步調用之前,我們先來看同步調用的定義;同步就是整個處理過程順序執行,當各個過程都執行完畢,並返回結果。 異步調用則是隻是發送了調用的指令,調用者無需等待被調用的方法完全執行完畢;而是繼續執行下面的流程。例如, 在某個調用中,需要順序調用 A, B, C三個過程方法;如他們都是同步調用,則需要將他們都順序執行完畢之後,方算作過程執行完畢; 如B爲一個異步的調用方法,則在執行完A之後,調用B,並不等待B完成,而是執行開始調用C,待C執行完畢之後,就意味着這個過程執行完畢了。

2. 常規的異步調用處理方式
在Java中,一般在處理類似的場景之時,都是基於創建獨立的線程去完成相應的異步調用邏輯,通過主線程和不同的線程之間的執行流程,從而在啓動獨立的線程之後,主線程繼續執行而不會產生停滯等待的情況。

3. @Async介紹
在Spring中,基於@Async標註的方法,稱之爲異步方法;這些方法將在執行的時候,將會在獨立的線程中被執行,調用者無需等待它的完成,即可繼續其他的操作。

分爲不帶參數的異步調用;帶參數的異步調用;調用返回Future的異步線程

4. @Async調用中的事務處理機制
在@Async標註的方法,同時也適用了@Transactional進行了標註;在其調用數據庫操作之時,將無法產生事務管理的控制,原因就在於其是基於異步處理的操作。 那該如何給這些操作添加事務管理呢?可以將需要事務管理操作的方法放置到異步方法內部,在內部被調用的方法上添加@Transactional. 例如: 方法A,使用了@Async/@Transactional來標註,但是無法產生事務控制的目的。 方法B,使用了@Async來標註, B中調用了C、D,C/D分別使用@Transactional做了標註,則可實現事務控制的目的。

5. 配合使用@EnableAsync

@EnableAsync
在啓動類或者Control類加上 @EnableAsync 註解

@EnableAsync註解的意思是可以異步執行,就是開啓多線程的意思。可以標註在方法、類上。@Async所修飾的函數不要定義爲static類型,這樣異步調用不會生效

如下:

@SpringBootApplication
@EnableAsync
public class Application
{
    public static void main( String[] args )
    {
        SpringApplication.run(Application.class, args);
    }
}

或者:

@EnableAsync
@RestController
public class HelloController {
    
    @Autowired
    TestAsyncService testAsyncService;

}

  

6. 舉例:

兩張表:user_info和order_table 插入user_info數據時候用同步,插入order_table用異步。

在controller類中創建一個方法 同時保存user_info和order_table表。保存order_table用異步(對應service方法中用@Async標註

(1)domain文件夾中創建Entity類

package com.cfj.ceshi.async.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;


@Entity
@Table(name="order_table")
public class OrderTable implements Serializable {
    
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    
    @Column(name = "order_name")
    private String orderName;
    
    @Column(name = "user_id")
    private Integer userId; 
    
    @Column(name = "create_date")
    private Date createDate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
    
    
    
    
    

}

  

package com.cfj.ceshi.async.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="user_info")
public class UserInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String userName;
    private String age;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "UserInfo [id=" + id + ", userName=" + userName + ", age=" + age + "]";
    }    

}

  (2)創建repository層操作數據庫。如果是普通保存方法,只需要接口繼承JpaRepository,不需要寫具體方法

package com.cfj.ceshi.async.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cfj.ceshi.async.domain.OrderTable;

public interface OrderRepository extends JpaRepository<OrderTable, Integer> {

}

  

package com.cfj.ceshi.async.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cfj.ceshi.async.domain.UserInfo;

public interface UserRepository extends JpaRepository<UserInfo, Integer> {
    
        

}

  (3)service層 其中order的實現層保存方法加上@Async

package com.cfj.ceshi.async.service;

public interface OrderService {
    
    public void saveOrder(Integer UserId,String name);

}

  

package com.cfj.ceshi.async.service;

import java.util.List;

import com.cfj.ceshi.async.domain.UserInfo;

public interface UserService {
    
    public Integer save(UserInfo user);
    
    

}

  

package com.cfj.ceshi.async.service.impl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.cfj.ceshi.async.domain.OrderTable;
import com.cfj.ceshi.async.repository.OrderRepository;
import com.cfj.ceshi.async.service.OrderService;

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    OrderRepository orderRepository;
    
    /**
     * 異步保存
     */
    @Async
    @Override
    public void saveOrder(Integer UserId,String name) {
        System.out.println("UserId:"+UserId);
        System.out.println("=====" + Thread.currentThread().getName() + "=========");
        OrderTable orderTable = new OrderTable();
        
        orderTable.setOrderName(name+"訂單");
        orderTable.setUserId(UserId);
        orderTable.setCreateDate(new Date());
        orderRepository.save(orderTable);
        

    }

}

  

package com.cfj.ceshi.async.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cfj.ceshi.async.domain.UserInfo;
import com.cfj.ceshi.async.repository.UserRepository;
import com.cfj.ceshi.async.service.UserService;

@Service
@Transactional
public class UserServiceImpl implements UserService{
    
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public Integer save(UserInfo user) {
        System.out.println("=====" + Thread.currentThread().getName() + "=========");
        return userRepository.save(user).getId();
    }    
    

}

  (4) control層,control類中添加@EnableAsync註解

package com.cfj.ceshi.async.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cfj.ceshi.async.domain.UserInfo;
import com.cfj.ceshi.async.service.OrderService;
import com.cfj.ceshi.async.service.UserService;

@EnableAsync
@RestController
@RequestMapping("/tesasyc")
public class AsycWeb {
    
    @Autowired
    UserService userService;
    @Autowired
    OrderService orderService;
    
    
    
    /**
     *    請使用 postman測試    方式選擇post  http://localhost:8081/tesasyc/save-one
     *  body 中選擇form-data 或者x-wwww-form-urlencoded  輸入對應鍵值對
     * @param name
     * @param age
     * @return
     */
    @PostMapping(value = "/save-one") //相當於@RequestMapping(value = "/save-one", method = RequestMethod.POST)
    public String postOne(String name,String age) {
        UserInfo user = new UserInfo();
        user.setUserName(name);
        user.setAge(age);
        Integer id = userService.save(user);
        orderService.saveOrder(id,name);
        return id.toString();
        
    }

}

  

 

 參考:  

    https://www.cnblogs.com/memoryXudy/p/7737418.html
    https://segmentfault.com/a/1190000013974727
    https://www.cnblogs.com/andyfengzp/p/6824253.html
    https://www.cnblogs.com/benefitworld/p/5877423.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章