最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案

 更新時(shí)間:2023年06月11日 08:56:12   作者:ITender  
本文主要介紹了@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

背景

項(xiàng)目中使用了MySQL數(shù)據(jù)庫(kù),并按照功能模塊采用了分庫(kù)的策略。因此,一個(gè)業(yè)務(wù)邏輯類(lèi)中可能涉及多個(gè)MySQL數(shù)據(jù)庫(kù)的操作。
我們項(xiàng)目中是采用@DS("xxx")來(lái)實(shí)現(xiàn)數(shù)據(jù)源切換。

當(dāng)注解添加到類(lèi)上,意味著此類(lèi)里的方法都使用此數(shù)據(jù)源; 當(dāng)注解添加到方法上時(shí),意味著此方法上使用的數(shù)據(jù)源優(yōu)先級(jí)高于其他一切配置;

問(wèn)題分析

代碼

依賴(lài)

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

yml配置

spring:
  datasource:
    dynamic:
      primary: master #設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為master
      strict: false #嚴(yán)格匹配數(shù)據(jù)源,默認(rèn)false. true未匹配到指定數(shù)據(jù)源時(shí)拋異常,false使用默認(rèn)數(shù)據(jù)源
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/demo_01?useSSL=false&autoReconnect=true&characterEncoding=utf8
          username: root
          password: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0開(kāi)始支持SPI可省略此配置
        slave:
          url: jdbc:mysql://172.23.168.70:3306/dynamic?useSSL=false&autoReconnect=true&characterEncoding=utf8
          username: root
          password: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver

對(duì)象實(shí)體

/**
 * @author itender
 * @date 2023/4/28 11:01
 * @desc
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_dynamic_template")
public class DynamicTemplateEntity {
?
    @TableId(type = IdType.AUTO)
    private Integer id;
?
    /**
     * 語(yǔ)言
     */
    private String language;
?
    /**
     * 語(yǔ)言編碼
     */
    @TableField("language_code")
    private String languageCode;
?
    /**
     * 創(chuàng)建時(shí)間
     */
    @TableField("created_time")
    private Date createdTime;
?
    /**
     * 創(chuàng)建人
     */
    @TableField("created_by")
    private Integer createdBy;
?
    /**
     * 創(chuàng)建人名稱(chēng)
   */
    @TableField("created_by_name")
    private String createdByName;
}
/**
 * @author itender
 * @date 2023/4/28 10:57
 * @desc
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("t_user")
public class UserEntity {
?
    /**
     * 主鍵id
     */
    @TableId(type = IdType.AUTO)
    private Integer id;
?
    /**
     * 用戶(hù)名稱(chēng)
     */
    private String username;
}
?

controller代碼

/**
 * @author itender
 * @date 2023/4/28 10:34
 * @desc
 */
@RestController
@RequestMapping("template")
public class DynamicTemplateController {
?
    private final DynamicTemplateService dynamicTemplateService;
?
    @Autowired
    public DynamicTemplateController(DynamicTemplateService dynamicTemplateService) {
        this.dynamicTemplateService = dynamicTemplateService;
    }
?
    @GetMapping
    public List<DynamicTemplateEntity> list() {
        return dynamicTemplateService.list();
    }
?
    @PostMapping
    public Integer add(@RequestBody DynamicTemplateEntity template) {
        return dynamicTemplateService.add(template);
    }
}

service

/**
 * @author itender
 * @date 2023/4/28 10:36
 * @desc
 */
public interface DynamicTemplateService {
?
    /**
     * 查詢(xún)模板集合
     *
     * @return
     */
    List<DynamicTemplateEntity> list();
?
    /**
     * 添加模板
     *
     * @param template
     * @return
     */
    Integer add(DynamicTemplateEntity template);
}

mapper

/**
 * @author itender
 * @date 2023/4/28 11:09
 * @desc
 */
@DS("slave")
@Mapper
@Repository
public interface DynamicTemplateMapper extends BaseMapper<DynamicTemplateEntity> {
}
/**
 * @author itender
 * @date 2023/4/28 11:08
 * @desc
 */
@Mapper
@Repository
@DS("master")
public interface UserMapper extends BaseMapper<UserEntity> {
}

業(yè)務(wù)代碼

/**
?* @author itender
?* @date 2023/4/28 11:15
?* @desc
?*/
@Service
public class DynamicTemplateServiceImpl implements DynamicTemplateService {
? ? private final DynamicTemplateMapper dynamicTemplateMapper;
? ? private final UserMapper userMapper;
? ? private final UserService userService;
? ? @Autowired
? ? public DynamicTemplateServiceImpl(DynamicTemplateMapper dynamicTemplateMapper, UserMapper userMapper, UserService userService) {
? ? ? ? this.dynamicTemplateMapper = dynamicTemplateMapper;
? ? ? ? this.userMapper = userMapper;
? ? ? ? this.userService = userService;
? ? }
? ? @Override
? ? public List<DynamicTemplateEntity> list() {
? ? ? ? List<DynamicTemplateEntity> templateList = dynamicTemplateMapper.selectList(new QueryWrapper<>());
? ? ? ? if (CollectionUtils.isEmpty(templateList)) {
? ? ? ? ? ? return Lists.newArrayList();
? ? ? ? }
? ? ? ? List<UserEntity> userList = userMapper.selectList(new QueryWrapper<>());
? ? ? ? if (CollectionUtils.isEmpty(userList)) {
? ? ? ? ? ? return templateList;
? ? ? ? }
? ? ? ? Map<Integer, String> userMap = userList.stream().collect(Collectors.toMap(UserEntity::getId, UserEntity::getUsername, (key1, key2) -> key1));
? ? ? ? templateList.forEach(template -> template.setCreatedByName(userMap.get(template.getCreatedBy())));
? ? ? ? return templateList;
? ? }
? ? @Transactional(rollbackFor = Exception.class)
? ? @Override
? ? public Integer add(DynamicTemplateEntity template) {
? ? ? ? List<UserEntity> userList = userMapper.selectList(new QueryWrapper<>());
? ? ? ? if (CollectionUtils.isEmpty(userList)) {
? ? ? ? ? ? template.setCreatedByName("");
? ? ? ? }
? ? ? ? Map<Integer, String> userMap = userList.stream().collect(Collectors.toMap(UserEntity::getId, UserEntity::getUsername, (key1, key2) -> key1));
? ? ? ? template.setCreatedByName(userMap.get(template.getCreatedBy()));
? ? ? ? template.setCreatedTime(new Date());
? ? ? ? dynamicTemplateMapper.insert(template);
? ? ? ? return template.getId();
? ? }
}

測(cè)試

當(dāng)方法沒(méi)有@Transactional注解時(shí),可以正常切換數(shù)據(jù)源

[    {        "id": 1,        "language": "中文",        "languageCode": "chinese",        "createdTime": "2023-04-27T18:56:25.000+00:00",        "createdBy": 1,        "createdByName": "itender"    }]

可以正常切換數(shù)據(jù)源。

當(dāng)方法有@Transactional注解時(shí),切換數(shù)據(jù)源失敗

### Error updating database.  Cause: java.sql.SQLSyntaxErrorException: Table 'demo_01.t_dynamic_template' doesn't exist
### The error may exist in com/itender/threadpool/mapper/DynamicTemplateMapper.java (best guess)
### The error may involve com.itender.threadpool.mapper.DynamicTemplateMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO t_dynamic_template  ( language, language_code, created_time, created_by, created_by_name )  VALUES  ( ?, ?, ?, ?, ? )
### Cause: java.sql.SQLSyntaxErrorException: Table 'demo_01.t_dynamic_template' doesn't exist
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: Table 'demo_01.t_dynamic_template' doesn't exist] with root cause
java.sql.SQLSyntaxErrorException: Table 'demo_01.t_dynamic_template' doesn't exist

分析

  • spring 的@Transactional聲明式事務(wù)管理時(shí)通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的。
  • @DS注解加到mapper接口、service接口、service方法里都不生效,獲取的還是默認(rèn)的主數(shù)據(jù)源。猜測(cè)是由于spring的aop切面機(jī)制導(dǎo)致攔截不到@DS注解,進(jìn)而不能切換數(shù)據(jù)源,正確的做法是添加到service實(shí)現(xiàn)類(lèi)或者實(shí)現(xiàn)類(lèi)里具體的方法上。
  • 在事務(wù)方法內(nèi)調(diào)用@DS注解的方法,@DS注解同樣不生效,原因是spring只能攔截到最外層方法的@Transactional注解,此時(shí)加載該事務(wù)的數(shù)據(jù)源,在事務(wù)方法內(nèi)即使調(diào)用了@DS注解的方法,獲取的是外層事務(wù)的數(shù)據(jù)源,導(dǎo)致@DS失效。
  • 在同一個(gè)實(shí)現(xiàn)類(lèi)中,一個(gè)非DS注解的常規(guī)方法里調(diào)用@DS注解的方法,同樣存在@DS失效的情況,原因同2,是由spring的aop機(jī)制導(dǎo)致的,如果確有這種業(yè)務(wù)需要,可以將該DS注解方法定義在不同的類(lèi)中,通過(guò)bean注入的方式調(diào)用,就不會(huì)出現(xiàn)這個(gè)問(wèn)題。

解決方案

把查詢(xún)user的邏輯放到另外一個(gè)單獨(dú)的業(yè)務(wù)邏輯類(lèi)里面

/**
?* @author itender
?* @date 2023/4/28 14:25
?* @desc
?*/
public interface UserService {
? ? /**
? ? ?* 查詢(xún)用戶(hù)集合
? ? ?*
? ? ?* @return
? ? ?*/
? ? List<UserEntity> list();
}
/**
?* @author itender
?* @date 2023/4/28 14:27
?* @desc
?*/
@Service
public class UserServiceImpl implements UserService {
? ? private final UserMapper userMapper;
? ? @Autowired
? ? public UserServiceImpl(UserMapper userMapper) {
? ? ? ? this.userMapper = userMapper;
? ? }
? ? @DS("master")
? ? @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
? ? @Override
? ? public List<UserEntity> list() {
? ? ? ? return userMapper.selectList(new QueryWrapper<>());
? ? }
}

修改template業(yè)務(wù)類(lèi)

@DS("slave")
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
@Override
public Integer add(DynamicTemplateEntity template) {
    // List<UserEntity> userList = userMapper.selectList(new QueryWrapper<>());
    List<UserEntity> userList = userService.list();
    if (CollectionUtils.isEmpty(userList)) {
        template.setCreatedByName("");
    }
    Map<Integer, String> userMap = userList.stream().collect(Collectors.toMap(UserEntity::getId, UserEntity::getUsername, (key1, key2) -> key1));
    template.setCreatedByName(userMap.get(template.getCreatedBy()));
    template.setCreatedTime(new Date());
    dynamicTemplateMapper.insert(template);
    return template.getId();
}

測(cè)試成功插入一條數(shù)據(jù)。

總結(jié)

  • spring 的@Transactional聲明式事務(wù)管理時(shí)通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的。
  • @DS注解加到mapper接口、service接口、service方法里都不生效,獲取的還是默認(rèn)的主數(shù)據(jù)源。猜測(cè)是由于spring的aop切面機(jī)制導(dǎo)致攔截不到@DS注解,進(jìn)而不能切換數(shù)據(jù)源,正確的做法是添加到service實(shí)現(xiàn)類(lèi)或者實(shí)現(xiàn)類(lèi)里具體的方法上。
  • 在事務(wù)方法內(nèi)調(diào)用@DS注解的方法,@DS注解同樣不生效,原因是spring只能攔截到最外層方法的@Transactional注解,此時(shí)加載該事務(wù)的數(shù)據(jù)源,在事務(wù)方法內(nèi)即使調(diào)用了@DS注解的方法,獲取的是外層事務(wù)的數(shù)據(jù)源,導(dǎo)致@DS失效。
  • 在同一個(gè)實(shí)現(xiàn)類(lèi)中,一個(gè)非DS注解的常規(guī)方法里調(diào)用@DS注解的方法,同樣存在@DS失效的情況,原因同2,是由spring的aop機(jī)制導(dǎo)致的,如果確有這種業(yè)務(wù)需要,可以將該DS注解方法定義在不同的類(lèi)中,通過(guò)bean注入的方式調(diào)用,就不會(huì)出現(xiàn)這個(gè)問(wèn)題。

到此這篇關(guān)于Java中@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案的文章就介紹到這了,更多相關(guān)@DS+@Transactional數(shù)據(jù)源失效內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot集成WebSockets廣播消息(推薦)

    springboot集成WebSockets廣播消息(推薦)

    這篇文章主要介紹了springboot-集成WebSockets廣播消息,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Spring Gateway集成 Nacos注冊(cè)中心不能夠發(fā)現(xiàn)服務(wù)的解決方案

    Spring Gateway集成 Nacos注冊(cè)中心不能夠發(fā)現(xiàn)服務(wù)的解決方案

    文章描述了在將Eureka替換為Nacos后,Spring Cloud Gateway在調(diào)用Nacos注冊(cè)的服務(wù)時(shí)出現(xiàn)問(wèn)題,通過(guò)調(diào)試和分析,發(fā)現(xiàn)Spring Cloud Gateway在初始化時(shí)沒(méi)有正確加載Nacos的ReactiveDiscoveryClient,導(dǎo)致服務(wù)調(diào)用失敗,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • SpringBoot生成條形碼的方案詳解

    SpringBoot生成條形碼的方案詳解

    在Spring Boot, Spring Cloud 項(xiàng)目中整合ZXing庫(kù)來(lái)生成條形碼在特定行業(yè)也是一個(gè)常見(jiàn)需求,ZXing是google開(kāi)源的一個(gè)功能強(qiáng)大的Java庫(kù),專(zhuān)門(mén)用于二維碼/條形碼等的生成與解析,所以本文給大家介紹了SpringBoot生成條形碼的方案,需要的朋友可以參考下
    2024-08-08
  • Java實(shí)現(xiàn)泡泡堂對(duì)戰(zhàn)版游戲的示例代碼

    Java實(shí)現(xiàn)泡泡堂對(duì)戰(zhàn)版游戲的示例代碼

    本文將利用Java制作經(jīng)典游戲《泡泡堂》,文中使用了MVC模式,分離了模型、視圖和控制器,使得項(xiàng)目結(jié)構(gòu)清晰易于擴(kuò)展,感興趣的可以了解一下
    2022-04-04
  • 解決微服務(wù)下Mybatis?xml無(wú)效綁定問(wèn)題及分析Invalid?bound?statement

    解決微服務(wù)下Mybatis?xml無(wú)效綁定問(wèn)題及分析Invalid?bound?statement

    這篇文章主要介紹了解決微服務(wù)下Mybatis?xml無(wú)效綁定問(wèn)題及分析Invalid?bound?statement,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • JVM線(xiàn)上調(diào)優(yōu)參數(shù)配置實(shí)踐完全指南

    JVM線(xiàn)上調(diào)優(yōu)參數(shù)配置實(shí)踐完全指南

    JVM調(diào)優(yōu)的基本思路涉及多個(gè)方面,旨在提升Java應(yīng)用的性能、穩(wěn)定性和響應(yīng)速度,下面這篇文章主要介紹了JVM線(xiàn)上調(diào)優(yōu)參數(shù)配置的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-08-08
  • Java中MyBatis Plus知識(shí)點(diǎn)總結(jié)

    Java中MyBatis Plus知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理一篇關(guān)于Java中MyBatis Plus知識(shí)點(diǎn)總結(jié),需要的朋友們參考下。
    2019-10-10
  • Java?新特性之Option示例詳解

    Java?新特性之Option示例詳解

    使用Optional開(kāi)發(fā)時(shí)要注意正確使用Optional的“姿勢(shì)”,特別注意不要使用3.2節(jié)提到的錯(cuò)誤示范,謹(jǐn)慎使用isPresent()和get()方法,盡量多使用map()、filter()、orElse()等方法來(lái)發(fā)揮Optional的作用,對(duì)Java??Option相關(guān)知識(shí)感興趣的朋友一起看看吧
    2024-02-02
  • Spring boot使用logback實(shí)現(xiàn)日志管理過(guò)程詳解

    Spring boot使用logback實(shí)現(xiàn)日志管理過(guò)程詳解

    這篇文章主要介紹了Spring boot使用logback實(shí)現(xiàn)日志管理過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 詳解JDBC對(duì)Mysql utf8mb4字符集的處理

    詳解JDBC對(duì)Mysql utf8mb4字符集的處理

    這篇文章主要介紹了詳解JDBC對(duì)Mysql utf8mb4字符集的處理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11

最新評(píng)論

洪湖市| 罗江县| 清水县| 玛纳斯县| 绥宁县| 宽城| 康定县| 谢通门县| 靖边县| 扶风县| 阆中市| 榆林市| 民和| 新密市| 黄陵县| 开平市| 安溪县| 武宁县| 鄄城县| 涟源市| 绩溪县| 武义县| 永靖县| 英吉沙县| 乌审旗| 鞍山市| 普兰县| 汉中市| 齐河县| 依兰县| 石门县| 广丰县| 普洱| 漳平市| 丰宁| 哈尔滨市| 浑源县| 南漳县| 三都| 巴塘县| 定结县|