SpringBoot项目从搭建到发布

第一章 SpringBoot项目环境搭建


前言

目前正在练手springboot+vue,因为很多步骤会遇到困难,当时查完资料解决,过一段时间就会忘记,所以决定建个系列记录下来。其实中间很多过程已经被其他大神写过,且这次开发经历仅供学习分享与讨论,就直接借鉴过来了,会附上原作者传送门。本次项目准备写文档临时起意,之前的步骤未作记录,比如部署linux虚拟机,利用mycat实现读写分离等,这个等项目需要用到的时候再加说明。好了现在让我们开始吧!


第二章 使用IDEA搭建一个简单的SpringBoot项目——初始化项目


前言

该篇文章质量很高,我利用作者教程一次搭建成功,直接复制过来


创建项目

在这里插入图片描述2.选择“Spring Initializr”,点击next;(jdk1.8默认即可)
在这里插入图片描述
3.完善项目信息,组名可不做修改,项目名可做修改;最终建的项目名为:test,src->main->java下包名会是:com->example->test;点击next;
在这里插入图片描述
4.Web下勾选Spring Web Start,(网上创建springboot项目多是勾选Web选项,而较高版本的Springboot没有此选项,勾选Spring Web Start即可,2.1.8版本是Spring Web);Template Englines勾选Thymeleaf;SQL勾选:MySQL Driver,JDBC API 和 MyBatis Framework三项;点击next;
在这里插入图片描述
5.选择项目路径,点击finish;打开新的窗口;
在这里插入图片描述
在这里插入图片描述
6.刚创建好的项目目录结构


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204142502112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3llamlhbGlhbmd6aQ==,size_16,color_FFFFFF,t_70)

7.点击右侧的Maven,点击设置(扳手图标)进行项目Maven仓库的配置;
在这里插入图片描述
8.(1)选择本地Maven路径;(2)勾选配置文件后边的选项,然后修改为本地Maven的配置文件,它会根据配置文件直接找到本地仓库位置;
在这里插入图片描述
9.配置完后,如果没有自动导包,可以点击左上角重新导包按钮,或者呢个下载按钮,选择下载所有源文件和文档
在这里插入图片描述
10.在templates文件下新建index.html页面,作为启动的初始页面;
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
    你好!初学者,我是SpringBoot的简单启动页面!
</body>
</html>

11.在com.example.test下新建controller文件夹,在controller文件夹下建一个简单的helloController类;(Controller类要添加@Controller注解,项目启动时,SpringBoot会自动扫描加载Controller)
在这里插入图片描述

package com.example.test.controller;
 
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class HelloController {
 
    @RequestMapping("/index")
    public String sayHello(){
        return "index";
    }
}

12.在resources文件夹下application中先配置DataSource基本信息,application文件有两种文件格式,一种是以.properties为后缀,一种是以.yml为后缀的,两种配置方式略有差别,详情可参考这个网址:https://blog.csdn.net/qq_29648651/article/details/78503853;在这我是用.yml后缀的文件格式。右键application文件选择Refact,选择Rename,将后缀改为yml;
在这里插入图片描述

 
spring:
  datasource:
    name: test  #数据库名
    url: jdbc:mysql://localhost:3306/test #url
    username: root  #用户名
    password: 123456  #密码
    driver-class-name: com.mysql.jdbc.Driver  #数据库链接驱动

13.运行项目启动类TestApplication.java
在这里插入图片描述
!可以发现上面有一个WARN警告,那是因为还没有配置编写MyBatis的相关文件,下面会进行详解;

2019-08-02 09:14:27.473  WARN 9120 --- [           main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.example.test]' package. Please check your configuration.

14.在浏览器中输入localhost:8080,回车显示初始的index界面;到这项目的初步搭建已经完成,下面可以下一些简单的业务逻辑,比如从数据库获取信息,登录之类的简单功能;
在这里插入图片描述
15.在进行下一步编写时,我们先来链接一下数据库;点击右侧的Database,点“加号”,新建数据库链接;
在这里插入图片描述
16.填写数据库相关信息,点击Test Connection;
在这里插入图片描述
17.如果链接失败可能是驱动的问题,点击左上角的小扳手,进入数据库设置界面
在这里插入图片描述
18.连接成功后,显示数据库信息,user表的基本信息也显示了,下面就照这个来了;
在这里插入图片描述
19.往下的我就没照做了,下面是我自己搭建的项目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
20.我的数据库,连的mycat。启动三台虚拟机,运行linux1和linux2中的mysql,运行Linux3中的mycat,关闭防火墙
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
21.原文传送门
点这里

第三章 整合全局捕获异常


前言

@ExceptionHandler 表示拦截异常
• @ControllerAdvice 是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类
• @ControllerAdvice 可以指定扫描范围
• @ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换
o 返回 String,表示跳到某个 view
o 返回 modelAndView
o 返回 model + @ResponseBody


@ControllerAdvice

1. 控制层代码
在这里插入图片描述

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ErrorController {
    // 全局捕获异常  使用AOP技术,采用异常通知
    @RequestMapping("/getUser")
    public String getUser(int i){
            int j = 1/i;
        return "success"+j;
    }
}

2.异常拦截代码
在这里插入图片描述

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice(basePackages = "com.example.test.controller")
public class GlobalExceptionHandler {
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Map<String,Object> errorResult(){
        Map<String,Object> errorResultMap = new HashMap<>();
        errorResultMap.put("errorCode","500");
        errorResultMap.put("errorMsg","系统错误!");
        return errorResultMap;
    }
}

3.运行结果
在这里插入图片描述


第四章 springboot+log4j.yml配置日志文件


前言

此处为转载,原作者写的比较详细,就一个地方有问题,去掉默认日志,加载别的日志 , 切换log4j2日志读取应该放在spring-boot-starter下而不是spring-boot-starter-web;会无法打包


一,Maven 依赖 pom.xml配置

1. 掉默认日志,以便切换到log4j2的日志依赖

        <dependency>
            <!-- 包含 mvc,aop 等jar资源 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <!--去掉默认日志,加载别的日志 , 切换log4j2日志读取  -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2. 然后添加如下两个日志依赖

		<!-- 配置 log4j2 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		
		<!-- 加上这个才能辨认到log4j2.yml文件 -->
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-yaml</artifactId>
		</dependency>

二,在工程根目录下添加 lo4g2.yml 配置文件

1, 文件存放位置
在这里插入图片描述
2, 配置文件内容

# 共有8个级别,按照从低到高为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。
Configuration:
  status: warn
  monitorInterval: 30
  Properties: # 定义全局变量
    Property: # 缺省配置(用于开发环境)。其他环境需要在VM参数中指定,如下:
      #测试:-Dlog.level.console=warn -Dlog.level.xjj=trace
      #生产:-Dlog.level.console=warn -Dlog.level.xjj=info
      - name: log.level.console
        value: info
      - name: log.path
        value: log
      - name: project.name
        value: opendoc
      - name: log.pattern
        value: "%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID:-} [%15.15t] %-30.30C{1.} : %m%n"
  Appenders:
    Console:  #输出到控制台
      name: CONSOLE
      target: SYSTEM_OUT
      PatternLayout:
        pattern: ${log.pattern}
#   启动日志
    RollingFile:
      - name: ROLLING_FILE
        fileName: ${log.path}/${project.name}.log
        filePattern: "${log.path}/historyRunLog/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"
        PatternLayout:
          pattern: ${log.pattern}
        Filters:
#        一定要先去除不接受的日志级别,然后获取需要接受的日志级别
          ThresholdFilter:
            - level: error
              onMatch: DENY
              onMismatch: NEUTRAL
            - level: info
              onMatch: ACCEPT
              onMismatch: DENY
        Policies:
          TimeBasedTriggeringPolicy:  # 按天分类
            modulate: true
            interval: 1
        DefaultRolloverStrategy:     # 文件最多100个
          max: 100
#   平台日志
      - name: PLATFORM_ROLLING_FILE
        ignoreExceptions: false
        fileName: ${log.path}/platform/${project.name}_platform.log
        filePattern: "${log.path}/platform/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"
        PatternLayout:
          pattern: ${log.pattern}
        Policies:
          TimeBasedTriggeringPolicy:  # 按天分类
            modulate: true
            interval: 1
        DefaultRolloverStrategy:     # 文件最多100个
          max: 100
#   业务日志
      - name: BUSSINESS_ROLLING_FILE
        ignoreExceptions: false
        fileName: ${log.path}/bussiness/${project.name}_bussiness.log
        filePattern: "${log.path}/bussiness/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"
        PatternLayout:
          pattern: ${log.pattern}
        Policies:
          TimeBasedTriggeringPolicy:  # 按天分类
            modulate: true
            interval: 1
        DefaultRolloverStrategy:     # 文件最多100个
          max: 100
#   错误日志
      - name: EXCEPTION_ROLLING_FILE
        ignoreExceptions: false
        fileName: ${log.path}/exception/${project.name}_exception.log
        filePattern: "${log.path}/exception/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"
        ThresholdFilter:
          level: error
          onMatch: ACCEPT
          onMismatch: DENY
        PatternLayout:
          pattern: ${log.pattern}
        Policies:
          TimeBasedTriggeringPolicy:  # 按天分类
            modulate: true
            interval: 1
        DefaultRolloverStrategy:     # 文件最多100个
          max: 100
#   DB 日志
      - name: DB_ROLLING_FILE
        ignoreExceptions: false
        fileName: ${log.path}/db/${project.name}_db.log
        filePattern: "${log.path}/db/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"
        PatternLayout:
          pattern: ${log.pattern}
        Policies:
          TimeBasedTriggeringPolicy:  # 按天分类
            modulate: true
            interval: 1
        DefaultRolloverStrategy:     # 文件最多100个
          max: 100
  Loggers:
    Root:
      level: info
      AppenderRef:
        - ref: CONSOLE
        - ref: ROLLING_FILE
        - ref: EXCEPTION_ROLLING_FILE
    Logger:
      - name: platform
        level: info
        additivity: false
        AppenderRef:
          - ref: CONSOLE
          - ref: PLATFORM_ROLLING_FILE
      - name: bussiness
        level: info
        additivity: false
        AppenderRef:
          - ref: BUSSINESS_ROLLING_FILE
      - name: exception
        level: debug
        additivity: true
        AppenderRef:
          - ref: EXCEPTION_ROLLING_FILE
      - name: db
        level: info
        additivity: false
        AppenderRef:
          - ref: DB_ROLLING_FILE
#    监听具体包下面的日志
#    Logger: # 为com.xjj包配置特殊的Log级别,方便调试
#      - name: com.xjj
#        additivity: false
#        level: ${sys:log.level.xjj}
#        AppenderRef:
#          - ref: CONSOLE
#          - ref: ROLLING_FILE

3, 在application.yml引入log4j2.yml

#在application.yml引入log4j2.yml
logging:
  config: classpath:log4j2.yml 

三, 不同日志枚举类

1, 本地日志枚举类

package com.tcs.irecr.util;
/**
 * 
 * 本地日志枚举
 * 由于配置了4个文件存放不同日志,分别为平台日志(${project.name}_platform.log)、 业务日志(${project.name}_bussiness.log)、错误日志(${project.name}_exception.log)、DB 日志(${project.name}_db.log),
 * 文件夹外面为运行日志,不同文件日志级别不一样,因此程序员在开发时候需要注意引入不同日志,
 * 也就是说开发出现的日志,程序员可以进行分类,分别调用公共方法即可。
 * 公共类编辑如下;
 * 
 * @author 1632369
 *
 */
public enum LogEnum {
 
	BUSSINESS("bussiness"),PLATFORM("platform"),DB("db"),EXCEPTION("exception");
 
 
    private String category;
 
 
    LogEnum(String category) {
        this.category = category;
    }
 
    public String getCategory() {
        return category;
    }
 
    public void setCategory(String category) {
        this.category = category;
    }
    
 
 
}

四, 不同日志工具类util编辑

1, 本地日志参考类

package com.tcs.irecr.util;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
/**
 * 本地日志参考类
 * @author Administrator
 *
 */
public class LogUtils {
	   /**
     * 获取业务日志logger
     *
     * @return
     */
    public static Logger getBussinessLogger() {
        return LoggerFactory.getLogger(LogEnum.BUSSINESS.getCategory());
    }
 
    /**
     * 获取平台日志logger
     *
     * @return
     */
    public static Logger getPlatformLogger() {
        return LoggerFactory.getLogger(LogEnum.PLATFORM.getCategory());
    }
 
    /**
     * 获取数据库日志logger
     *
     * @return
     */
    public static Logger getDBLogger() {
        return LoggerFactory.getLogger(LogEnum.DB.getCategory());
    }
 
 
    /**
     * 获取异常日志logger
     *
     * @return
     */
    public static Logger getExceptionLogger() {
        return LoggerFactory.getLogger(LogEnum.EXCEPTION.getCategory());
    }
 
}

五, 运行时自动在工程目录下生产日志目录和日志文件

在这里插入图片描述

六, 原文章传送门

点这里

第五章 Spring Boot集成lombok


前言

简洁代码,很实用的插件


一,Maven 依赖 pom.xml配置

1. 导入依赖包

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

2. 使用IDEA需要安装Lombok插件,我这里已经下载好,如果没下载安装点击install进行下载安装即可
在这里插入图片描述
3. 实体类演示@Data----简化get/set,toString等方法,@Slf4j------简化 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
在这里插入图片描述

import lombok.Data;

@Data
public class UserInfoDto {
    private Integer id;
    private String name;
}

在这里插入图片描述

import com.example.test.dto.UserInfoDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Slf4j
public class helloController {
    @RequestMapping("/index")
    public String sayHello(){
        UserInfoDto userInfoDto = new UserInfoDto();
        userInfoDto.setId(1);
        userInfoDto.setName("天下第一");
        log.info("打印结果是-----"+userInfoDto.toString());
        return "index";
    }
}

3.其他特性

@Data 标签,生成getter/setter toString()等方法 
@NonNull : 让你不在担忧并且爱上NullPointerException 
@CleanUp : 自动资源管理:不用再在finally中添加资源的close方法 
@Setter/@Getter : 自动生成set和get方法 
@ToString : 自动生成toString方法 
@EqualsAndHashcode : 从对象的字段中生成hashCode和equals的实现 
@NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor 
自动生成构造方法 
@Data : 自动生成set/get方法,toString方法,equals方法,hashCode方法,不带参数的构造方法 
@Value : 用于注解final类 
@Builder : 产生复杂的构建器api类
@SneakyThrows : 异常处理(谨慎使用) 
@Synchronized : 同步方法安全的转化 
@Getter(lazy=true) : 
@Log : 支持各种logger对象,使用时用对应的注解,如:@Log4

第六章 Spring Boot使用@Async实现异步调用


前言

现实中校验excel时可能会用到,之前项目校验上传数据时我是单开了个线程完成通知,看这次能不能替换实现。


一,Controller类

1. 启动加上@EnableAsync 在这里插入图片描述

import com.example.test.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * springboot异步调用
 */
@RestController
@Slf4j
@EnableAsync // 开启异步调用
public class MemberController {
    @Autowired
    private MemberService memberService;
    @RequestMapping("/addMemberAndEmail")
    public String addMemberAndEmail(){
        log.info("1");
        String result  = memberService.addMemberAndEmail();
        log.info("4");
        return "result"+result;
    }
}

2.需要执行异步方法上加入 @Async,在方法上加上@Async之后 底层使用多线程技术
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b4fc6855c2303f0d20395de15fd3130d.png

import com.example.test.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MemberServiceImpl implements MemberService {
    @Override
    @Async // 相当于此方法单独开辟一个新线程执行
    public String addMemberAndEmail() {
        log.info("2");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("3");
        return "2021新年好!!!";
    }
}

3.执行结果未加 @Async和@Async
在这里插入图片描述
在这里插入图片描述
4.执行结果加 @Async和@Async
在这里插入图片描述
在这里插入图片描述

第七章 Spring Boot不同环境配置文件


前言

注意:yml文件冒号前一定要加空格…


一.@Value的使用与开发,测试,生产环境不同配置文件使用

1. 此处仅用开发环境文件做演示,建立application-dev.yml文件
在这里插入图片描述
2. 配置application.yml文件
在这里插入图片描述
代码

spring:
  profiles:
    active: dev

3. 演示代码controller层

import com.example.test.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ValueController {
    @Autowired
    private MemberService memberService;


    @RequestMapping("/testValue")
    public String testValue(){
       return  memberService.readUrlbyValue();
    }
}

4. 演示代码servicer层

import com.example.test.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MemberServiceImpl implements MemberService {

    @Value("${devurl}")
    private String devurl;

    @Override
    @Async // 相当于此方法单独开辟一个新线程执行
    public String addMemberAndEmail() {
        log.info("2");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("3");
        return "2021新年好!!!";
    }

    @Override
    public String readUrlbyValue() {
        return devurl;
    }
}

5. 运行结果

(https://img-blog.csdnimg.cn/20210205103858693.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3llamlhbGlhbmd6aQ==,size_16,color_FFFFFF,t_70)

第八章 Spring Boot与mybatis三剑客


前言

说实话今天我为了整合这个踩了不少坑,花了将近半天时间才成功。这里记下来避免好学者和我一样查资料浪费时间


一.逆向生成文件–神器MyBatis-Generator

1.首先不多说pom.xml导入需要架包,这里踩坑一,我之前用的mysql-connector-java版本是8.0.12,而我的mysql版本只有 5.7.33,生成时会报 CLIENT_PLUGIN_AUTH is required错误,而且驱动应该改成"com.mysql.cj.jdbc.Driver"而不是"com.mysql.jdbc.Driver"。

       <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
            <scope>runtime</scope>
        </dependency>

		 <!--MBG插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
            </plugin>

2. 配置generatorConfig.xml文件, 配置文件中的是配置驱动的一个简单的方式,可以通过location制定路径。

​ 元素用于指定生成一组对象的环境。例如指定要连接的数据库,要生成对象的类型和要处理的数据库中的表。其中的defaultModelType属性很重要,这个属性定义了MBG如何生成实体类,推荐使用flat模式,为每一张表只生成一个包含表所有字段的实体类。

​ 指定生成实体类的生成路径,trimStrings属性会对查询条件进行trim操作,默认值是false。

​ 指定生成xml文件的路径。

​ 指定生成dao接口。

可以配置多个,用于指定生成数据库中的那个表的底层类,可以指定生成的实体类的name,enableCountXXX属性可以去除不需要的sql方法,其中columnOverride可以指定表中使用的枚举类,ignoreColumn可以忽略表中的字段,columnOverride和ignoreColumn可以指定0个或多个。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <classPathEntry
            location="F:\repository\mysql\mysql-connector-java\5.1.41\mysql-connector-java-5.1.41.jar"/>

    <context id="MysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">

        <property name="javaFileEncoding" value="UTF-8"/>

        <commentGenerator>
            <property name="suppressDate" value="false"/>
            <property name="addRemarkComments" value="true"/>
            <property name="suppressAllComments" value="false"/>
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://192.168.70.122:8066/TESTDB?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false"
                        userId="root"
                        password="123456">
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <javaModelGenerator targetPackage="com.example.test.entity"
                            targetProject="src\main\java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mappers" targetProject="src\main\resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.test.dao"
                             targetProject="src\main\java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>


        <table schema="" tableName="user_info" enableCountByExample="true" domainObjectName="userInfo">
        </table>

      <!--  <table schema="ins_personal_claim" tableName="claim_image_info" enableCountByExample="false" domainObjectName="ClaimImageInfo">
            <columnOverride column="image_type" javaType="com.jd.ins.personal.claim.domain.enums.ImageType" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
            <ignoreColumn column="create_time"/>
            <ignoreColumn column="update_time"/>
        </table>-->

    </context>
</generatorConfiguration>

3. mvn install 和点击myBatis-Generator生产文件

在这里插入图片描述

4. 结果
在这里插入图片描述

二.mybatis plugin

1. mybatis plugin作为一款优秀的mybatis跳转插件

在这里插入图片描述
2. 安装重启,分页插件就不说了,项目中用别的插件。

在这里插入图片描述
在这里插入图片描述

第九章 Spring Boot与多数据源(事务)


前言

副数据源用192.168.70.120/test
在这里插入图片描述


一.配置多数据源

1.首先不多说pom.xml导入需要架包, 再原有依赖基础上,新增以下依赖

<!-- 配置多数据源用相关依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

        <!-- 配置动态数据源 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>2.5.6</version>
        </dependency>

2.上次逆向生成配置有问题,最显著的是生成目录resources/mappers/,实际应该为resources/mapper,顺便类命名规范,否则会报Invalid bound statement(not found)错误。这里提供generatorConfig.xml最新生成文件,删除之前的重新再生成下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <classPathEntry
            location="F:\repository\mysql\mysql-connector-java\5.1.41\mysql-connector-java-5.1.41.jar"/>

    <context id="MysqlTables" targetRuntime="MyBatis3" defaultModelType="flat">

        <property name="javaFileEncoding" value="UTF-8"/>

        <commentGenerator>
            <property name="suppressDate" value="false"/>
            <property name="addRemarkComments" value="true"/>
            <property name="suppressAllComments" value="false"/>
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://192.168.70.122:8066/TESTDB?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false"
                        userId="root"
                        password="123456">
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <javaModelGenerator targetPackage="com.example.test.entity"
                            targetProject="src\main\java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mapper" targetProject="src\main\resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.test.dao"
                             targetProject="src\main\java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>


        <table schema="" tableName="user_info"  domainObjectName="UserInfo">
        </table>

      <!--  <table schema="ins_personal_claim" tableName="claim_image_info" enableCountByExample="false" domainObjectName="ClaimImageInfo">
            <columnOverride column="image_type" javaType="com.jd.ins.personal.claim.domain.enums.ImageType" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
            <ignoreColumn column="create_time"/>
            <ignoreColumn column="update_time"/>
        </table>-->

    </context>
</generatorConfiguration>

3.将主要配置转移到application-dev.yml,学以致用。

application.yml

server:
  port: 8080
spring:
  profiles:
    active: dev
# Mybatis配置
#mybatis:
  #mapper-locations: classpath:mapper/*/*.xml  #配置映射文件
  #type-aliases-package: com.example.test.entity #配置实体类

#在application.yml引入log4j2.yml
logging:
  config: classpath:log4j2.yml

application-dev.yml


spring:
  datasource:
    dynamic:
    # 这是默认主数据源
      primary: TESTDB
      datasource:
        TESTDB:
          url: jdbc:mysql://192.168.70.122:8066/TESTDB?characterEncoding=utf8 #url
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        test:
          url: jdbc:mysql://192.168.70.120:3306/test?characterEncoding=utf8 #url
          username: root
          password: root
          driver-class-name: com.mysql.jdbc.Driver
      durid:
        initial-size: 1
        max-active: 20
        min-idle: 1
        max-wait: 60000
devurl: 172.0.0.1

4.在dao下新建文件extension,在其下新建接口UserInfoExtensionMapper。

在这里插入图片描述
代码

import com.example.test.entity.UserInfo;

import java.util.List;

public interface UserInfoExtensionMapper {
    List<UserInfo> selectUerInfos();
}

5.在resources/mapper下新建文件extension,在其下新建xml配置文件UserInfoExtensionMapper.xml。
在这里插入图片描述
代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.test.dao.extension.UserInfoExtensionMapper">
  <resultMap id="BaseResultMap" type="com.example.test.entity.UserInfo">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon Feb 08 10:26:10 CST 2021.
    -->
    <result column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
  </resultMap>

  <select id="selectUerInfos" parameterType="com.example.test.entity.UserInfo" resultMap="BaseResultMap">
    select * from
    user_info
  </select>

</mapper>

6.在entity下新建Tset类。
在这里插入图片描述
代码

import lombok.Data;

@Data
public class Tset {
    private Integer id;
    private String name;
}

7.在dao下新建TestMapperjie接口,这里**@DS(“test”)**,表示进入192.168.70.120/test数据源。
在这里插入图片描述
代码

import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.test.entity.Tset;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@DS("test")
public interface TestMapper {

    @Select("SELECT * FROM test001")
    List<Tset> selectTsets();
}

8.新建service层
在这里插入图片描述
代码

public interface MemberService {
    // 读取多数据库的值
    String readDataSources();
}

在这里插入图片描述
代码

import com.example.test.dao.TestMapper;
import com.example.test.dao.extension.UserInfoExtensionMapper;
import com.example.test.entity.Tset;
import com.example.test.entity.UserInfo;
import com.example.test.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class MemberServiceImpl implements MemberService {

    @Value("haha")
    private String devurl;
    @Autowired
    private TestMapper testMapper;
    @Autowired
    private UserInfoExtensionMapper userInfoMapper;

    @Override
    public String readDataSources() {
        log.info("kaishi");
        List<UserInfo> userInfos = null;
        try {
            userInfos = userInfoMapper.selectUerInfos();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("jieshu");
        List<Tset> tsetList = null;
        String testString = "";
        try {
            tsetList = testMapper.selectTsets();
            testString = tsetList.get(0).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("testString--------------------"+testString);
        return userInfos.get(0).toString()+testString;
    }
}

9.新建controller层
在这里插入图片描述
代码

    @RequestMapping("/dataSourse")
    public String dataSourse(){
        String result = memberService.readDataSources();
        return result;
    }

10.启动类,注意要加**@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)**,去除掉对DruidDataSourceAutoConfigure的自动配置,否则你的程序会报错:Error creating bean with name ‘dataSource’ defined in class path resource [com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.class]

在这里插入图片描述
11.运行结果
在这里插入图片描述

二.多数据源事务问题

1.逻辑层

dao层 加 @Transactional(propagation = Propagation.REQUIRES_NEW)
在这里插入图片描述
代码

 @Transactional(propagation = Propagation.REQUIRES_NEW)
    @DS("test")
    @Insert("insert into test001 (id,name) values(#{id}, #{name})")
    Integer insterTest(Tset tset);

service层 加 @Transactional

在这里插入图片描述
代码

 @Transactional
    public String insertDataSources() {
     /* UserInfoExample example = new UserInfoExample();
        UserInfoExample.Criteria criteria =example.createCriteria();
        criteria.andIdEqualTo(2);
        criteria.andNameEqualTo("老北鼻");*/
      UserInfo userInfo = new UserInfo();
      userInfo.setId(2);
      userInfo.setName("老北鼻");
        try {
            userInfoMapper.insert(userInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Tset tset = new Tset();
        tset.setId(2);
        tset.setName("二舅");
        testMapper.insterTest(tset);
        return "成功";
    }

controller层
在这里插入图片描述
代码

 @RequestMapping("/insertDataSourse")
    public String insertDataSourse(){
        String result = memberService.insertDataSources();
        return result;
    }

2. 结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.回滚机制
在这里插入图片描述
代码

 @Transactional
    public String insertDataSources() {
     /* UserInfoExample example = new UserInfoExample();
        UserInfoExample.Criteria criteria =example.createCriteria();
        criteria.andIdEqualTo(2);
        criteria.andNameEqualTo("老北鼻");*/
      UserInfo userInfo = new UserInfo();
      userInfo.setId(3);
      userInfo.setName("小北鼻");
        try {
            userInfoMapper.insert(userInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Tset tset = new Tset();
        tset.setId(3);
        tset.setName("三舅");
        testMapper.insterTest(tset);
        int i = 5/0;
        return "成功";
    }
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.example.test.dao")
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

2.此方法就到此为止吧,在TestApplication上添加@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class),最多只能保证改变数据源时不报错,并不能解决事务问题,我百度了很多文章想解决此问题,无一都失败了,不知道是不是自己环境问题。如果有谁看到了这又感兴趣的话,可以自己尝试下能不能解决事务问题,并告知下我结果。在此感谢!

三.多数据源事务问题2

1.懈怠了一段时间,今天继续更。前段时间重新装了下idea,更新到了2020.3(破解全传送门下面会给出,感谢原作者。)将mysql更新到了8。因为linux虚拟机换软件太麻烦,我直接装在了本地,先凑合着用,等闲的时候再将几台虚拟机一起更新吧。然后多数据源数据问题换了个方法已经解决了,使用的方法是springboot+atomikos+多数据源管理事务(mysql 8.0),终于不用继续钻牛角尖啦!

idea2020.3下载入口

2.pom.xm引入依赖(将mysql-connector-java版本更新到8)

 <!-- 配置动态数据源 -->
		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
<!--           <version>5.1.46</version>-->
            <!--<scope>runtime</scope>-->
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>2.5.6</version>
        </dependency>

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

        <!--导入配置文件处理器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

3.上配置文件application-datasou.yml(记得在application.yml里面切换到此配置文件)


spring:
  datasource:
    #  spring.datasource.test1
    #    druid:
    test1:
      #      jdbc-url,url,jdbcurl哪个合适用哪个
      jdbcurl: jdbc:mysql://localhost:3306/test1?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
      username: root
      password: root
      #        driver-class-name: com.mysql.jdbc.Driver
      #
      # driver-class-name: com.mysql.jdbc.Driver
      driver-class-name: com.mysql.cj.jdbc.Driver
      type: com.alibaba.druid.pool.DruidDataSource
      #        下面是另外加的配置数据源的参数
      minPoolSize: 3
      maxPoolSize: 25
      maxLifetime: 20000
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60

    test2:
      jdbcurl: jdbc:mysql://localhost:3306/test2?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
      username: root
      password: root
      # driver-class-name: com.mysql.jdbc.Driver
      driver-class-name: com.mysql.cj.jdbc.Driver
      type: com.alibaba.druid.pool.DruidDataSource
      minPoolSize: 3
      maxPoolSize: 25
      maxLifetime: 20000
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60


  mvc:
    servlet:
     load-on-startup: 100
mybatis:
  mapper-locations: classpath:mapper/*.xml
#设置静态资源路径,多个以逗号分隔
spring.resources.static-locations: classpath:static/,file:static/


4.创建以下目录
在这里插入图片描述
5.创建类DBConfig1,DBConfig2。

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "spring.datasource.test1") // 注意这个前缀要和application.yml文件的前缀一样
public class DBConfig1 {

    // 比如这个jdbcurl在properties中是这样子的mysql.datasource.test1.username = root
    private String jdbcurl;
    private String username;
    private String password;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    private String testQuery;
}
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "spring.datasource.test2")// 注意这个前缀要和application.yml文件的前缀一样
public class DBConfig2 {
    // 比如这个jdbcurl在properties中是这样子的mysql.datasource.test1.username = root
    private String jdbcurl;
    private String username;
    private String password;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    private String testQuery;

}

6.创建类MyBatisConfig1,MyBatisConfig2。

import com.example.test.config.DBConfig1;
import com.mysql.cj.jdbc.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@MapperScan(basePackages = "com.example.test.mapper1", sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class MyBatisConfig1 {

    // 配置数据源
    //@Bean(name = "testDataSource")  //test1DataSource
    @Bean(name = "test1DataSource")  //test1DataSource
    public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        //mysqlXaDataSource.setUrl(testConfig.getUrl());
        mysqlXaDataSource.setUrl(testConfig.getJdbcurl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(testConfig.getPassword());
        mysqlXaDataSource.setUser(testConfig.getUsername());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 将本地事务注册到创 Atomikos全局事务
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName("test1DataSource");

        xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(testConfig.getTestQuery());
        return xaDataSource;
    }

    @Bean(name = "test1SqlSessionFactory")
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean(name = "test1SqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(
            @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
import com.example.test.config.DBConfig2;
import com.mysql.cj.jdbc.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@MapperScan(basePackages = "com.example.test.mapper2", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class MyBatisConfig2 {

    // 配置数据源
    //@Bean(name = "testDataSource")
    @Bean(name = "test2DataSource")  //test2DataSource
    public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        //mysqlXaDataSource.setUrl(testConfig.getUrl());
        mysqlXaDataSource.setUrl(testConfig.getJdbcurl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(testConfig.getPassword());
        mysqlXaDataSource.setUser(testConfig.getUsername());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 将本地事务注册到创 Atomikos全局事务
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName("test2DataSource");

        xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(testConfig.getTestQuery());
        return xaDataSource;
    }

    @Bean(name = "test2SqlSessionFactory")
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean(name = "test2SqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(
            @Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

7.创建接口UserMapper1,UserMapper2。

import com.example.test.dto.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;


public interface UserMapper1 {
    // 查询语句
    @Select("SELECT * FROM user_info WHERE NAME = #{name}")
    User findByName(@Param("name") String name);

    // 添加
    @Insert("INSERT INTO user_info(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);
}
import com.example.test.dto.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;


public interface UserMapper2 {
    // 查询语句
    @Select("SELECT * FROM user_info WHERE NAME = #{name}")
    User findByName(@Param("name") String name);

    // 添加
    @Insert("INSERT INTO user_info(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);
}

8.创建类UserInfoDto。

import lombok.Data;

@Data
public class UserInfoDto {
    private Integer id;
    private String name;
    private Integer age;
}

9.创建接口ManyService1,类ManyServiceImpl1。

public interface ManyService1 {
    public int insert(String name, Integer age);

    public int insertDb1AndDb2(String name, Integer age);
}
import com.example.test.mapper1.UserMapper1;
import com.example.test.mapper2.UserMapper2;
import com.example.test.service.ManyService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
public class ManyServiceImpl1 implements ManyService1 {

    @Autowired
    private UserMapper1 userMapper1;
    @Autowired
    private UserMapper2 userMapper2;

    // 开启事务,由于使用jta+atomikos解决分布式事务,所以此处不必再指定事务
    @Override
    @Transactional
    public int insert(String name, Integer age) {
        int insert = userMapper1.insert(name, age);
        //int i = 1 / age;// 赋值age为0故意引发事务
        return insert;
    }

    // 开启事务,由于使用jta+atomikos解决分布式事务,所以此处不必再指定事务
    @Override
    @Transactional
    public int insertDb1AndDb2(String name, Integer age) {
        int insert = userMapper1.insert(name, age);
        int insert2 = userMapper2.insert(name, age);
        int i = 1 / age;// 赋值age为0故意引发事务
        return insert + insert2;
    }
}

10.创建类ManyController。

import com.example.test.service.ManyService1;
import com.example.test.service.ManyService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class ManyController {

    @Autowired
    private ManyService1 manyService1;

    @Resource
    private ManyService2 manyService2;

    @RequestMapping(value = "datasource1")
    public int datasource1(String name, Integer age) {
        return manyService1.insert(name, age);
    }

    @RequestMapping(value = "datasource2")
    public int datasource2(String name, Integer age) {
        return manyService2.insert(name, age);
    }

    /**
     * @Param:
     * @Description: 这里测试两个service两个数据源的事务(不加上atomikos插件的情况下测试,
     *使用DataSource1Config和DataSource2Config 两个配置类, 关闭DBConfig1, DBConfig2和MyBatisConfig1, MyBatisConfig1两个类)
     * @Author:
     */
    //http://localhost:8080/manyDatasource/testManyTrans?name=tom4&age=2
    @RequestMapping(value = "testManyTrans")
    public int testManyTrans(String name, Integer age) {
        int i = 0;
        int i1 = manyService1.insert(name, age);
        System.out.println("manyService1.insert :" + i1);

        /*
        第二个事务中会手动造成一个异常~,
        但是第一个事务执行完毕了,保存到了数据库
        */
        int i2 = manyService2.insert(name, age);
        System.out.println("manyService2.insert :" + i2);
        return i;
    }


    /**
     * @Param:
     * @Description: 这里测试使用atomikos插件测试多数据源事务
     * @Author:
     */
    //http://localhost:8080/minsertDb1AndDb2?name=tom&age=2
    //http://localhost:8080/insertDb1AndDb2?name=jetty&age=0  //测试除数为0后的事务管理
    @RequestMapping(value = "insertDb1AndDb2")
    public int insertDb1AndDb2(String name, Integer age) {
        return manyService1.insertDb1AndDb2(name, age);
    }


}

11.配置启动类TestApplication。

import com.example.test.config.DBConfig1;
import com.example.test.config.DBConfig2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@EnableConfigurationProperties(value = {DBConfig1.class , DBConfig2.class })
@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

12.运行//http://localhost:8080/insertDb1AndDb2?name=tom&age=2。
结果
在这里插入图片描述
在这里插入图片描述

13.运行//http://localhost:8080/insertDb1AndDb2?name=jetty&age=0。

结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里我们发现数据并未插入成功,事务生效!

第十章 Spring Boot打包发布


前言

这个项目还是到这结束吧,初衷便是用来练手的,作为传统项目搭建到这里差不多够用了,下期准备搭建个spring Cloud项目,配上redis和消息中间件之类的 ,配上业务逻辑实战效果会更好些,先就这样吧。

一.打包

1.按如下步骤操作,先clean再install
在这里插入图片描述
2.出现如下结果表示打包成功。
在这里插入图片描述

二.发布

1.在项目target目录打开cmd,输入java -jar E:\workspace\test\target\test-0.0.1-SNAPSHOT.jar 如下表示启动成功。
在这里插入图片描述
在这里插入图片描述
2.测试 http://localhost:8080/insertDb1AndDb2?name=jetty&age=1在这里插入图片描述
在这里插入图片描述
发布成功!


总结

集众家之所长,毕其功于一役!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值