Java随记

Java

java保留两位小数

1、使用String.format()方法:

public static void stringFormatdecimalFormatKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        String result = String.format("%.2f", number);
        System.out.println(result);
    }

输出:3.14

2、BigDecimal保留两位小数

import java.math.BigDecimal;

public static void bigdecimalKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        BigDecimal decimal = new BigDecimal(number);
        BigDecimal rounded = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(rounded);
    }

输出:3.14

3、使用DecimalFormat类:

public static void decimalFormatKeepTwoDecimalPlaces(){
        double number = 3.1415926;
        DecimalFormat decimalFormat = new DecimalFormat("#.00");
        String result = decimalFormat.format(number);
        System.out.println(result);
    }

输出:3.14

基本数据类型

/**
 * 基本数据类型,在定义的时候根据不同的类型在内存中分配不同的大小进行存储。
 *
 *
 * 整数:
 *      byte(1字节byte=8位)
 *      1000 0000 ~ 01111111 最高位是符号位0表示正 1表示负
 *      byte值的范围:-128 ~ 127
 *
 *
 *      short(2字节) -32768~32767
 *
 *      \ int(4字节) -2,147,483,648 ~ 21 4748 3647(21亿多)
 *
 *      \ long(8字节)
 *
 * 浮点型:
 *      float(4字节) 定义float类型变量时,变量要以"f"或"F"结尾
 *      单精度浮点数 提供大约6-7位的有效数字。
 *
 *      \ double(8字节)
 *      双精度浮点数 提供大约15-16位的有效数字。
 *      推荐使用double,因为现代计算机硬件通常更擅长处理双精度浮点数。
 *
 *      简单来说double精度更高,可以表示更细的浮点数,通俗的讲就是小数点后面可以表示更多的数字。
 *
 * 布尔型:
 *      boolean(1字节)
 *
 * 字符型:
 *      char(2字节)
 *
 *
 */


/**
     * 运算
     *
     * 整数除法运算,结果是取整
     * 浮点数除整数 结果为 浮点数
     * 整数 除 浮点数 结果为 浮点数
     *
     * 文件大小 23435.12 MB
     *
     * 速率 = 文件大小 / 用时
     * 用时
     */
    @Test
    public void test3(){
        int fileSizeB = 46960880; // 44.7 MB
        int fileSizeMB = fileSizeB / 1024 / 1024;
        System.out.println(fileSizeMB);// 44 整数除整数结果也是取整

        double fileSizeMB1 = fileSizeB / 1024 / 1024;
        System.out.println(fileSizeMB1); // 44.0 只是将整数赋值给了一个浮点数double

        double fileSizeB1 = 46960880;
        double fileSizeMB2 = fileSizeB1 / 1024 / 1024;
        System.out.println(fileSizeMB2);// 44.78538513183594 浮点数除整数 结果为 浮点数

        // 结果保留一位小数
        System.out.println(String.format("%.1f", fileSizeMB2));// 44.8 会自动四舍五入

        DecimalFormat decimalFormat = new DecimalFormat("#.0");
        System.out.println(decimalFormat.format(fileSizeMB2));// 44.8 会自动四舍五入

        // 向下截断小数部分
        System.out.println(Math.floor(fileSizeMB2));// 44.0

        // 向上截断小数部分
        System.out.println(Math.ceil(fileSizeMB2));// 45.0

        // 保留一位小数,不进行四舍五入
        System.out.println((int) (fileSizeMB2 * 10));
        double truncatedNumber = (int) (fileSizeMB2 * 10) / 10.0; // 整数 除 浮点数 结果为 浮点数
        System.out.println(truncatedNumber);// 44.7


        int mil = 23435; // 毫秒
        double second = mil / 1000.0;
        System.out.println(second);

        double speed = (int)((fileSizeMB2 / second) * 10) / 10.0;
        System.out.println(speed + " MB/S");// 1.9 MB/S
    }

分页查询

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

        
        
            com.github.pagehelper
            pagehelper-spring-boot-starter
            1.2.8
        

yml配置

pagehelper:
  helperDialect: mysql或者oracle
  supportMethodsArguments: true
  params: count=countSql
  • helperDialect: mysql:指定了数据库方言为 MySQL。
  • supportMethodsArguments: true:开启了支持方法参数,允许在方法中传递参数进行分页。
  • params: count=countSql:通过传递 count 参数来执行 countSql,这通常是用于执行查询总记录数的 SQL。
// 分页
if(highSearchVO.getPageNo() != null) PageHelper.startPage(highSearchVO.getPageNo(),highSearchVO.getPageSize());
List> maps = dynamicDataRetrievalMapper.highSearch(highSearchVO);

在需要分页查询之前调用PageHelper.startPage设置,会自动limit

websocket实时通信

业务中,客户端和服务端经常需要实时返回一些状态等消息,现总结一下websocket实时通信用法。

服务端

服务端一般用来接收客户端的ws连接,然后给客户端发送消息,不能主动发送连接。



    org.springframework.boot
    spring-boot-starter-websocket
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
package com.lin.ws;

/**
 *
 */
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lin.entity.vo.UploadMsgVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import javax.swing.Timer;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/webSocket/{topic}")
@Slf4j
public class WebSocketServer {
    private Session session;
    private String topic;
    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet<>();

    private static List uploadMsgList = new ArrayList<>(3);

    private javax.swing.Timer timer = new Timer(3000, e -> {
        sendMessage(JSONObject.toJSONString(uploadMsgList),"upload");
        uploadMsgList.clear();
    });

    /**
     * concurrent包的线程安全set,用来存放每个客户端对应的MyWebSocket对象
     */
    private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap();

    /**
     * 保存ws会话
     * 为了保存在线用户信息,在方法中新建一个list存储一下【实际项目依据复杂度,可以存储到数据库或者缓存】
     */
    private final static List SESSIONS = Collections.synchronizedList(new ArrayList<>());

    /**
     * 建立连接
     *  ws://192.168.31.47:9988/webSocket/{topic}
     * 当客户端发送: ws://192.168.31.47:9988/webSocket/upload ws请求,就可以和这个ws服务端建立ws连接了。
     *
     * @param session ws连接会话
     * @param topic ws连接主题
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("topic") String topic) {
        this.session = session;
        this.topic = topic;
        webSocketSet.add(this);
        SESSIONS.add(session);
        if (webSocketMap.containsKey(topic)) {
            webSocketMap.remove(topic);
            webSocketMap.put(topic,this);
        } else {
            webSocketMap.put(topic,this);
            addOnlineCount();
        }

        if("upload".equals(topic)) timer.start();
        // log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());
        log.info("[连接topic:{}] 建立连接, 当前连接数:{}", this.topic, webSocketMap.size());
        System.out.println(this);
    }

    /**
     * 断开连接
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        if (webSocketMap.containsKey(topic)) {
            webSocketMap.remove(topic);
            subOnlineCount();
        }

        if("upload".equals(topic)) timer.stop();
        // log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
        log.info("[连接topic:{}] 断开连接, 当前连接数:{}", topic, webSocketMap.size());
    }

    /**
     * 发送错误
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("[连接topic:{}] 错误原因:{}", this.topic, error.getMessage());
        error.printStackTrace();
    }

    /**
     * 收到消息
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        // log.info("【websocket消息】收到客户端发来的消息:{}", message);
        log.info("[连接topic:{}] 收到消息:{}", this.topic, message);

        UploadMsgVO uploadMsgVO = null;
        try {
            uploadMsgVO = JSON.parseObject(message, UploadMsgVO.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (uploadMsgVO != null) {
            int index = uploadMsgList.indexOf(uploadMsgVO);
            if(index == -1) uploadMsgList.add(uploadMsgVO);
            else uploadMsgList.set(index,uploadMsgVO);
        }

//        sendMessage(uploadMsgList.toString(),"upload");
    }

    /**
     * 发送消息
     * @param message 消息
     * @param topic 接收消息的主题(只要订阅这个主题都会收到消息)
     */
    public void sendMessage(String message,String topic) {
        WebSocketServer webSocketServer = webSocketMap.get(topic);
        if (webSocketServer!=null){
            log.info("【websocket消息】推送消息, message={}", message);
            try {
                webSocketServer.session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[连接topic:{}] 发送消息失败, 消息:{}", this.topic, message, e);
            }
        }
    }

    /**
     * 发送object消息
     * @param message
     * @param topic
     */
    public void sendObjectMessage(Object message,String topic) {
        WebSocketServer webSocketServer = webSocketMap.get(topic);
        if (webSocketServer!=null){
            log.info("【websocket消息】推送消息, message={}", message);
            try {
                webSocketServer.session.getBasicRemote().sendObject(message);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[连接topic:{}] 发送消息失败, 消息:{}", this.topic, message, e);
            }
        }
    }

    /**
     * 群发消息
     * @param message
     */
    public void sendMassMessage(String message) {
        try {
            for (Session session : SESSIONS) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(message);
                    log.info("[连接topic:{}] 发送消息:{}",session.getRequestParameterMap().get("topic"),message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前连接数
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 当前连接数加一
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 当前连接数减一
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

Java客户端

有个需求需要Java发送ws连接,将业务处理后的消息都汇总到ws服务端,由ws服务端汇总处理发送给客户端。

        
        
            org.java-websocket
            Java-WebSocket
            1.3.5
        

Java客户端代码

package com.example.web.socket;

import com.example.config.MyConfig;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;

@Component
@Slf4j
public class MyWebSocketClient {
    @Autowired
    private MyConfig myConfig;

    @Bean
    public WebSocketClient webSocketClient() throws URISyntaxException, UnknownHostException {
        String IP = InetAddress.getLocalHost().getHostAddress();

        // 建立ws连接对象
        org.java_websocket.client.WebSocketClient webSocketClient =
                new org.java_websocket.client.WebSocketClient(
                        new URI("ws://"+myConfig.getJavaIP()+":"+myConfig.getJavaPort()+"/webSocket/" + IP),
                        new Draft_6455()) {

            @Override
            public void onOpen(ServerHandshake handshakedata) {
                log.info("[websocket] 连接成功");
            }

            @Override
            public void onMessage(String message) {
                log.info("[websocket] 收到消息={}", message);

            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                log.info("[websocket] 退出连接");
            }

            @Override
            public void onError(Exception ex) {
                log.info("[websocket] 连接错误={}", ex.getMessage());
            }
        };

        // 连接
        webSocketClient.connect();

        return webSocketClient;
    }
}

使用

    @Autowired
    private WebSocketClient webSocketClient;

    // 发送消息
    webSocketClient.send(JSON.toJSONString(uploadMsg));

excel导入导出

直接使用阿里的easy-excel

EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com)

我的代码在gitee:excel-process: excel导入、导出、下载数据模板

程序运行内存

调用第三方接口

Java API

使用标准的 Java API 中的 java.net 包来进行 HTTP 请求。GET

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class ApiCaller {

    public static void main(String[] args) {
        try {
            // 第三方接口的URL
            String apiUrl = "https://api.example.com/data";

            // 创建 URL 对象
            URL url = new URL(apiUrl);

            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法
            connection.setRequestMethod("GET");

            // 获取响应代码
            int responseCode = connection.getResponseCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // 处理响应内容
                System.out.println("Response: " + response.toString());
            } else {
                System.out.println("HTTP Request Failed with response code: " + responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

post 

public static String sendPostRequest(String remoteUrl,String requestBody){
        String result = null;
        try {

            // 创建 URL 对象
            URL url = new URL(remoteUrl);

            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法为 POST
            connection.setRequestMethod("POST");

            connection.setRequestProperty("Content-Type", "application/json");

            // 启用输入输出流
            connection.setDoOutput(true);

            // 设置请求体
            try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
                outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));
            }

            // 获取响应代码
            int responseCode = connection.getResponseCode();

            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // 处理响应内容
                log.info("响应内容:{}",response.toString());

                result = response.toString();
            } else {
                log.error("请求失败,响应码是:{} " , responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("出错了:",e);
        }
        return result;
    }

Apache HttpClient

Apache HttpClient 是一个功能强大、灵活且可扩展的 HTTP 客户端库,它提供了更高级的功能,如连接池、Cookie 管理等。



    org.apache.httpcomponents
    httpclient
public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

工具

hutool构建树形结构



    cn.hutool
    hutool-all
    5.8.20
/*
    SysMenu自己构成树形结构
*/
@Override
public List> tree(SysMenu sysMenu) {
    //配置
    TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
    // 自定义属性名 都要默认值的
    treeNodeConfig.setWeightKey("order");
    treeNodeConfig.setIdKey("rid");
    // 最大递归深度
    treeNodeConfig.setDeep(3);
    List list = this.list();

    // "0"指定父id
    List> treeNodes = TreeUtil.build(list, "0", treeNodeConfig,
            (treeNode, tree) -> {
                tree.setId(treeNode.getMenuId());
                tree.setParentId(treeNode.getParentId());
                //tree.setWeight(treeNode.getWeight());
                tree.setName(treeNode.getMenuName());
                // 扩展属性 ...
                tree.putExtra("route", treeNode.getRoute());
                tree.putExtra("seq", treeNode.getSeq());
                //tree.putExtra("other", new Object());
            });
    return treeNodes;
}

/*
    List 以sourceId为父id构建树形
*/
@Override
public ResponseResult tree1(Long sourceId) {
    // 根据sourceId查询所有文件夹
    FileFolder fileFolder = new FileFolder();
    fileFolder.setParentId(sourceId);
    List fileFolders = fileFolderMapper.selectByParentId(sourceId);

    //配置
    TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
    // 自定义属性名 都要默认值的
    treeNodeConfig.setIdKey("id");


    List> treeNodes = TreeUtil.build(fileFolders, sourceId, treeNodeConfig,
            (treeNode, tree) -> {
                tree.setId(treeNode.getFolderId());
                tree.setParentId(treeNode.getParentId());
                tree.setName(treeNode.getFolderName());
            });

    return ResponseResult.success(treeNodes);
}
/*
    List dataSources
    List fileFolders
    List dataModels
    三者构建树形,dataSources为主节点。
*/
@Override
public ResponseResult tree2(Long sourceId) {
    // 所有数据源
    List dataSources = new ArrayList<>();
    DataSource dataSource = dataSourceMapper.selectDataSourceById(sourceId);
    dataSources.add(dataSource);

    // 所有文件夹
    FileFolder fileFolder = new FileFolder();
    fileFolder.setParentId(sourceId);
    List fileFolders = fileFolderMapper.selectByParentId(sourceId);

    // 所有数据模型
    List dataModels = dataModelMapper.selectBySourceIdAndParentId(sourceId,fileFolders);

    Stream> sourceStream = dataSources.stream().map(e->{
        TreeNode treeNode=new TreeNode<>();
        treeNode.setId(e.getId());
        treeNode.setName(e.getSourceName());
        treeNode.setParentId(0L);

        // 扩展字段赋值
//            Map extraMap = new HashMap<>();
//            extraMap.put("level", "zd");
//            treeNode.setExtra(extraMap);
        return treeNode;
    });

    Stream> folderStream = fileFolders.stream().map(e->{
        TreeNode treeNode=new TreeNode<>();
        treeNode.setId(e.getFolderId());
        treeNode.setName(e.getFolderName());
        treeNode.setParentId(e.getParentId());

        // 扩展字段赋值
//            Map extraMap = new HashMap<>();
//            extraMap.put("level", "dl");
//            treeNode.setExtra(extraMap);
        return treeNode;
    });

    Stream> modelStream = dataModels.stream().map(e->{
        TreeNode treeNode=new TreeNode<>();
        treeNode.setId(e.getId());
        treeNode.setName(e.getModelName());
        treeNode.setParentId(e.getParentId() == null ? e.getSourceId() : e.getParentId());

        // 扩展字段赋值
//            Map extraMap = new HashMap<>();
//            extraMap.put("level", "dl");
//            treeNode.setExtra(extraMap);
        return treeNode;
    });

    List> treeNodeList=Stream.concat(Stream.concat(sourceStream,folderStream),modelStream).collect(Collectors.toList());
    // 配置
    TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
    // 自定义属性名(修改默认名称)
    treeNodeConfig.setChildrenKey("children");
    treeNodeConfig.setNameKey("name");

    //转换器
    List> treeNodes = TreeUtil.build(treeNodeList, 0L, treeNodeConfig,
            (treeNode, tree) -> {
                // 给树节点赋值(还能set 父 或子节点树)
                tree.setId(treeNode.getId());
                tree.setParentId(treeNode.getParentId());

                tree.setName(treeNode.getName());
                // 扩展属性值赋值
                // treeNode.getExtra().getOrDefault("domain", null) 是获取上面Map放进去的值,没有就是 null
                if(CollectionUtil.isNotEmpty(treeNode.getExtra())){
                    tree.putAll(treeNode.getExtra());
                }
            });
    return ResponseResult.success(treeNodes);
}

数据库

存储过程

零基础学SQL(十二、存储过程)_sql创建存储过程-CSDN博客

完成指定功能的一段sql的集合,可以看作一个方法使用。

Oracle

比如我写过的这个,查询前一天的异常数量,并将异常数量汇总到STATISTICS_LOG表中:

CREATE OR REPLACE PROCEDURE "PROC_CAL_SERVER_STATUS_LOG"
AS
TYPE TYPE_ARRAY IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;

DATA_DATE NUMBER;
--定义当前日期
V_CUR_DATE VARCHAR2(20);
V_CUR_NUM INT;
V_EXE_SQL VARCHAR2(255);
V_TYPE VARCHAR2(20);

--定义一个数组
TYPES TYPE_ARRAY;

V_SOFTWAEW_TYPE VARCHAR2(20);
V_TOTAL_TYPE VARCHAR2(50);
V_SELECT_SQL VARCHAR2(255);
BEGIN

  --给数组赋值
  TYPES(1):= 'SERVER_STATUS';
  TYPES(2):= 'SOFTWARE_STATUS';
  TYPES(3):= 'DEVICE_STATUS';
  TYPES(4):= 'DBTABLE_STATUS';
  TYPES(5):= 'FOLDER_STATUS';
  TYPES(6):= 'SWICHER_STATUS';
  TYPES(7):= 'SWICHER_LINE_STATUS';
  TYPES(8):= 'SIG_STATUS';
  TYPES(9):= 'TEM_HUM_STATUS';
  TYPES(10):= 'ACU_STATUS';

  -- 前一天日期
  V_CUR_DATE := TO_CHAR(SYSDATE-1,'YYYYMMDD');

  -- 遍历TYPES数组
  FOR i IN 1..TYPES.COUNT LOOP
 	--当前
    V_TYPE := TYPES(i);
    V_TOTAL_TYPE := TYPES(i) || '_LOG';

	-- 给V_SELECT_SQL赋值
    V_SELECT_SQL := 'SELECT COUNT(*) FROM '|| V_TOTAL_TYPE ||' WHERE RUN_STATUS = ''异常'' and status_time >= trunc(sysdate-1) and status_time < trunc(sysdate)';
    
    DBMS_OUTPUT.put_line(V_SELECT_SQL);
    
    -- 执行sql语句,并将结果赋值给V_CUR_NUM
    EXECUTE IMMEDIATE V_SELECT_SQL INTO V_CUR_NUM;
    
    V_EXE_SQL := 'INSERT INTO STATISTICS_LOG(STATUS_TIME, NUM, DEVICE_TYPE) VALUES(TO_DATE(' || '''' || V_CUR_DATE || '''' || ',''yyyyMMdd''), '
  || V_CUR_NUM || ',' || '''' || V_TYPE || '''' || ')';
    EXECUTE IMMEDIATE V_EXE_SQL;

  END LOOP;
  COMMIT;
END;

TYPE TYPE_ARRAY IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER; 是声明了一个 PL/SQL 中的关联数组类型(Associative Array Type),其键是 BINARY_INTEGER 类型,值是 VARCHAR2(20) 类型。这种类型通常用于在 PL/SQL 中创建临时的索引数组,可以通过整数索引进行访问。在你的代码中,TYPES 就是这样一个关联数组。

--创建了一个存储过程,可以打印当前时间
CREATE OR REPLACE PROCEDURE MY_PRO_TEST AS
	V_CUR_DATE VARCHAR2(20);
	V_SELECT_SQL VARCHAR2(255);
BEGIN
	V_SELECT_SQL := 'SELECT TO_CHAR(SYSDATE, ''YYYY-MM-DD HH24:MI:SS'') FROM dual';
  EXECUTE IMMEDIATE V_SELECT_SQL INTO V_CUR_DATE;
  DBMS_OUTPUT.put_line(V_CUR_DATE);
end;

触发器

定时任务

MySQL MySQL 创建定时任务 详解_mysql 任务计划-CSDN博客

定时任务是基于特定时间周期触发来执行某些任务,而触发器(Triggers)是基于某个表所产生的事件触发的,区别也就在这里。

Oracle

https://www.cnblogs.com/luler/p/16004689.html

--创建
DECLARE
	xxxjobid number;
BEGIN
	DBMS_JOB.SUBMIT(
		JOB => xxxjobid,
		WHAT => 'begin 存储过程名; end;	或者	SQL语句;',
		NEXT_DATE => sysdate+3/(24*60),/**初次执行时间,当前时间的3分后*/
		interval => ''  /**每次执行的间隔时间*/
  );
commit;
end;
--查询定时任务
SELECT * FROM DBA_JOBS;
SELECT * FROM USER_JOBS;

举例:

CREATE OR REPLACE PROCEDURE MY_PRO_TEST AS
BEGIN
	INSERT INTO MY_TEST(MY_TIME) VALUES(sysdate);
end;
DECLARE
   printTime NUMBER;
BEGIN
   DBMS_JOB.SUBMIT(
      JOB => printTime,
      WHAT => 'begin my_pro_test; end;',
      INTERVAL =>'TRUNC(SYSDATE+1)' 
   );

   COMMIT;
END;

每天凌晨12点执行上面那个定时任务。

配置druid数据库连接池

SpringBoot集成连接池 - 集成数据库Druid连接池 | Java 全栈知识体系

        
        
            mysql
            mysql-connector-java
            runtime
        

        
        
            com.alibaba
            druid-spring-boot-starter
            1.2.8
        
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test_db?useSSL=false&autoReconnect=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: bfXa4Pt2lUUScy8jakXf
    # Druid datasource
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 初始化大小
      initial-size: 5
      # 最小连接数
      min-idle: 10
      # 最大连接数
      max-active: 20
      # 获取连接时的最大等待时间
      max-wait: 60000
      # 一个连接在池中最小生存的时间,单位是毫秒
      min-evictable-idle-time-millis: 300000
      # 多久才进行一次检测需要关闭的空闲连接,单位是毫秒
      time-between-eviction-runs-millis: 60000
      # 配置扩展插件:stat-监控统计,log4j-日志,wall-防火墙(防止SQL注入),去掉后,监控界面的sql无法统计
      filters: stat,wall
      # 检测连接是否有效的 SQL语句,为空时以下三个配置均无效
      validation-query: SELECT 1
      # 申请连接时执行validationQuery检测连接是否有效,默认true,开启后会降低性能
      test-on-borrow: true
      # 归还连接时执行validationQuery检测连接是否有效,默认false,开启后会降低性能
      test-on-return: true
      # 申请连接时如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效,默认false,建议开启,不影响性能
      test-while-idle: true
      # 是否开启 StatViewServlet
      stat-view-servlet:
        enabled: true
        # 访问监控页面 白名单,默认127.0.0.1
        allow: 127.0.0.1
        login-username: admin
        login-password: admin
      # FilterStat
      filter:
        stat:
          # 是否开启 FilterStat,默认true
          enabled: true
          # 是否开启 慢SQL 记录,默认false
          log-slow-sql: true
          # 慢 SQL 的标准,默认 3000,单位:毫秒
          slow-sql-millis: 5000
          # 合并多个连接池的监控数据,默认false
          merge-sql: false
  jpa:
    open-in-view: false
    generate-ddl: false
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
        format_sql: true
        use-new-id-generator-mappings: false

数据库日期字符串转换

MySQL

日期转字符串:

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS formatted_date;

字符串转日期 

SELECT STR_TO_DATE('2022-12-01 12:23:01', '%Y-%m-%d %H:%i:%S') AS converted_date;

Oracle

SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS converted_string
FROM dual;
SELECT TO_DATE('2023-12-01', 'YYYY-MM-DD') AS converted_date
FROM dual;

SQL判空

Oracle:select nvl(perms,'') from dual;如果perms为空则返回''

MySQL:select ifnull(perms,'') ;

聚合数据

Oracle数据库wm_concat()函数的使用方法

如:

shopping:

----------------------------------------

u_id goods num

------------------------------------------

1 苹果 2

2 梨子 5

1 西瓜 4

3 葡萄 1

3 香蕉 1

1 橘子 3

=======================

想要的结果为:

--------------------------------

u_id goods_sum


1 苹果,西瓜,橘子

2 梨子

3 葡萄,香蕉

--------------------------------

select u_id, wmsys.wm_concat(goods) goods_sum from shopping group by u_id

想要的结果2:

--------------------------------

u_id goods_sum


1 苹果(2斤),西瓜(4斤),橘子(3斤)

2 梨子(5斤)

3 葡萄(1斤),香蕉(1斤)

---------------------------------

使用oracle wm_concat(column)函数实现:

select u_id, wmsys.wm_concat(goods || '(' || num || '斤)' ) goods_sum from shopping group by u_id

MySQL对应的group_concat()

1.使用条件查询 查询部门为20的员工列表

-- 查询部门为20的员工列表 SELECT t.DEPTNO,t.ENAME FROM EMP t where t.DEPTNO = '20' ; 效果:

Java随记_第1张图片

2.使用 group_concat() 将多行合并成一行(比较常用)

语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'] )

不指定分隔符的话,默认是 ,

SELECT T.DEPTNO, group_concat(T.ENAME ORDER BY DEPTNO separator ',') FROM EMP T WHERE T.DEPTNO = '20' GROUP BY T.DEPTNO; 效果:

Java随记_第2张图片

递归树形层次查询

Oracle的start with

SELECT
    *
FROM
    SM_SYSTEM S 
    START WITH S. ID IN (101, 102, 420) 
    CONNECT BY NOCYCLE PRIOR S. ID = S.PARENT_ID

Oracle中START WITH...CONNECT BY PRIOR用法-CSDN博客

基本语法:

SELECT ... FROM + 表名 START WITH + 条件1 CONNECT BY PRIOR + 条件2 WHERE + 条件3

查询具有层次关系的树形数据。

条件1:是根节点的限定语句,当然可以放宽限定条件,以取得多个根节点,也就是多棵树; 作为树的根节点。

MySQL的WITH RECURSIVE

 -- 查ID为101, 102, 420的系统以及他的子系统的信息

WITH recursive temp AS (
	SELECT * FROM SM_SYSTEM WHERE ID IN (101, 102, 420)
	
	UNION
	
	SELECT ss.* FROM SM_SYSTEM ss join temp ON ss.PARENT_ID = temp.ID
)
SELECT * FROM temp;

1、SELECT * FROM SM_SYSTEM WHERE ID IN (101, 102, 420) 是起始查询

2、连接起始查询和递归查询

3、SELECT ss.* FROM SM_SYSTEM ss join temp ON ss.PARENT_ID = temp.ID 递归查询

先查询SELECT * FROM SM_SYSTEM WHERE ID IN (101, 102, 420),然后进行递归查询,将满足ss.PARENT_ID = temp.ID的记录都递归查询出来,然后再拿着这个查询结果查出满足PARENT_ID = id条件的所有记录,直到不满足条件。最后将处理查询的结果和递归查询的结果连接。

-- 查询所有的子文件夹
WITH recursive temp AS (
            SELECT *
            FROM file_folder
            WHERE folder_id in ('1742029296582828032')

            UNION DISTINCT 

            SELECT ff.*
            FROM file_folder ff
                     join temp ON ff.parent_id = temp.folder_id
        )
        SELECT *
        FROM temp

Java随记_第3张图片

-- 查询所有的父文件夹
WITH recursive temp AS (
            SELECT *
            FROM file_folder
            WHERE folder_id in (1742389699888300032)

            UNION  

            SELECT ff.*
            FROM file_folder ff
                     join temp ON ff.folder_id = temp.parent_id
        )
        SELECT *
        FROM temp

Java随记_第4张图片

修改字段名和字段类型

-- 修改字段名和字段类型
ALTER TABLE sm_dept
CHANGE COLUMN ID ID BIGINT AUTO_INCREMENT,
ADD PRIMARY KEY (ID);

-- 修改sm_dept表的字段名ID改为ID,并且类型改为BIGINT AUTO_INCREMENT自增,并且添加主键ADD PRIMARY KEY (ID)

插入数据将自增id赋值给实体的id属性



insert into t_checkgroup(code,name,sex,helpCode,remark,attention)
values (#{code},#{name},#{sex},#{helpCode},#{remark},#{attention})

mysql中varchar和 text的区别

mysql中varchar和 text的区别_text和varchar_念广隶的博客-CSDN博客

JDBC操作

public ResponseResult getDataSourceTableMsg(Long sourceId, String tableName) {
        ResponseResult result = null;

        // 获取数据源信息
        DataSource dataSource = dataSourceMapper.selectDataSourceById(sourceId);
        String executedSql = "select * from " + tableName;

        try (Connection connection = DriverManager.getConnection(dataSource.getSourceUrl(), dataSource.getUserName(), dataSource.getPassword());
             PreparedStatement preparedStatement = connection.prepareStatement(executedSql);
             ResultSet resultSet = preparedStatement.executeQuery()){

            // 获取数据库元数据
            DatabaseMetaData databaseMetaData = connection.getMetaData();

            // 获取查询结果集的元数据,可以获取结果集中的列名,通过列名可以获取结果
            ResultSetMetaData metaData = resultSet.getMetaData();
            List> resultList = new ArrayList<>();
            while (resultSet.next()) {
                Map temp = new HashMap<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    temp.put(metaData.getColumnName(i),resultSet.getString(metaData.getColumnName(i)));
                }
                resultList.add(temp);
            }


            // 由于表的字段信息只能next遍历一次,所以缓存表字段结果集数据到 map(key是注释 value是表名)
            Map columnDataList = new HashMap<>();

            // 根据表名tableName可以获取表的字段信息
            try (ResultSet columns = databaseMetaData.getColumns(null,null,tableName,null)){
                while (columns.next()) {
                    // 遍历可以获取字段注释和字段名信息
                    columnDataList.put(columns.getString("REMARKS"),columns.getString("COLUMN_NAME"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            // 封装数据
            List> resultList = new ArrayList<>();
            while (resultSet.next()) {
                Map resultMap = new HashMap<>();
                for (String key : columnDataList.keySet()) {
                    resultMap.put(key,resultSet.getString(columnDataList.get(key)));
                }
                resultList.add(resultMap);
            }
            result = ResponseResult.success(resultList);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            result = ResponseResult.fail("发生错误");
        }
        return result;
    }

Mybatis

批量操作

批量更新

在url连接后面要加上allowMultiQueries=true允许执行多个 SQL 查询。这在某些情况下可能会有用,但要小心使用,以避免 SQL 注入等安全问题

批量插入


        insert into monitored_equipment
        (node_id,
        channel_id,
        equipment_ip,
        equipment_name,
        frequency_parameter,
        normal_gain)
        values
        
            (#{item.nodeId},
            #{item.channelId},
            #{item.equipmentIp},
            #{item.equipmentName},
            #{item.frequencyParameter},
            #{item.normalGain})
        
    

解析后如以下,要同时执行多条sql,所以连接url要加allowMultiQueries参数

UPDATE draw_data
            SET `order` = 0
            WHERE id = 1;
UPDATE draw_data
            SET `order` = 1
            WHERE id = 2;
...

for循环

        
            UPDATE draw_data
            SET `order` = #{index}
            WHERE id = #{id}
        

参数类型typeAliasesPackage

mybatis:
  typeAliasesPackage: com.xx.entity

SignalMonitoringNode会自己去com.xx.entity里找

增删改查


        insert into signal_monitoring_node
        
            channel_id,
            monitoring_model_id,
            node_id,
            node_ip,
            
         
        
            #{channelId},
            #{monitoringModelId},
            #{nodeId},
            #{nodeIp},
            
         
    

        update signal_monitoring_node
        
            channel_id = #{channelId},
            monitoring_model_id = #{monitoringModelId},
            node_id = #{nodeId},
            node_ip = #{nodeIp},
            node_name = #{nodeName},
            center_frequency = #{centerFrequency},
            bandwidth = #{bandwidth},
            signal_power = #{signalPower},
            normal_gain = #{normalGain},
            run_status = #{runStatus},
            status_time = #{statusTime},
        
        where id = #{id}
    
    
        select id, channel_id, monitoring_model_id, node_id, node_ip, node_name, center_frequency, bandwidth, signal_power, normal_gain, run_status, status_time from signal_monitoring_node
    

    

查询返回数组集合

List selectNodeId(Long channelId);
    

如果返回的是String[]也一样

Spring

加载配置文件yml

spring.profiles.active=dev,mysql

Spring Boot 会加载 application-dev.propertiesapplication-dev.yml 以及 application-mysql.propertiesapplication-mysql.yml 中的配置项到application.yml主配置文件中。

配置类

@Component
@ConfigurationProperties(prefix = "ftp.client")
@Data
public class FTPPoolConfig extends GenericObjectPoolConfig {

    // 默认进入的路径
    String workingDirectory;
    // 主机地址
    String host;
# ftp 连接参数
# 默认进入的路径
ftp.client.workingDirectory=/
# 主机地址
ftp.client.host=xx
# 主机端口
ftp.client.port=21
# 主机用户名
ftp.client.username=xx

工具类中获取配置类

@Component
@ConfigurationProperties(prefix = "gen")
@PropertySource(value = { "classpath:application.yml" })
public class GenConfig
{
    /** 作者 */
    public static String author;

    /** 生成包路径 */
    public static String packageName;

    /** 自动去除表前缀,默认是false */
    public static boolean autoRemovePre;

    /** 表前缀(类名不会包含表前缀) */
    public static String tablePrefix;


    public static String getAuthor() {
        return author;
    }

    @Value("${author}")
    public void setAuthor(String author) {
        GenConfig.author = author;
    }

    public static String getPackageName() {
        return packageName;
    }

    @Value("${packageName}")
    public void setPackageName(String packageName) {
        GenConfig.packageName = packageName;
    }


    public static boolean getAutoRemovePre() {
        return autoRemovePre;
    }

    @Value("${autoRemovePre}")
    public void setAutoRemovePre(boolean autoRemovePre) {
        GenConfig.autoRemovePre = autoRemovePre;
    }

    public static String getTablePrefix() {
        return tablePrefix;
    }

    @Value("${tablePrefix}")
    public void setTablePrefix(String tablePrefix) {
        GenConfig.tablePrefix = tablePrefix;
    }
}

SpringBoot

多数据源

有些业务需要操作其他数据库的数据,这时候除了自己的数据库,还得配置另外一个数据库进行切换使用。

依赖



    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.2.2




    com.alibaba
    druid-spring-boot-starter
    1.2.8




    mysql
    mysql-connector-java
    runtime




    com.baomidou
    dynamic-datasource-spring-boot-starter
    3.5.2

配置


# 数据源配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # 主库数据源
      master:
        url: jdbc:mysql://ip:3306/data-manage?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
        username: root
        password: 123456
      # 从库数据源
      slave:
        # 从数据源开关/默认关闭
        enabled: true
        url: jdbc:mysql://ip:3306/data_analyze_platform?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
        username: hello
        password: 123456

      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置连接超时时间
      connectTimeout: 30000
      # 配置网络超时时间
      socketTimeout: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false

DruidConfig 

@Configuration
public class DruidConfig
{
    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource masterDataSource(DruidProperties druidProperties)
    {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.slave")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    public DataSource slaveDataSource(DruidProperties druidProperties)
    {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource)
    {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }
    
    /**
     * 设置数据源
     *
     * @param targetDataSources 备选数据源集合
     * @param sourceName 数据源名称
     * @param beanName bean名称
     */
    public void setDataSource(Map targetDataSources, String sourceName, String beanName)
    {
        try
        {
            DataSource dataSource = SpringUtils.getBean(beanName);
            targetDataSources.put(sourceName, dataSource);
        }
        catch (Exception e)
        {
        }
    }

}

DynamicDataSourceContextHolder 

/**
 * 数据源切换处理
 * 
 * @author lin
 */
public class DynamicDataSourceContextHolder
{
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源的变量
     */
    public static void setDataSourceType(String dsType)
    {
        log.info("切换到{}数据源", dsType);
        CONTEXT_HOLDER.set(dsType);
    }

    /**
     * 获得数据源的变量
     */
    public static String getDataSourceType()
    {
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType()
    {
        CONTEXT_HOLDER.remove();
    }
}

DynamicDataSource

/**
 * 动态数据源
 * 
 * @author lin
 */
public class DynamicDataSource extends AbstractRoutingDataSource
{
    public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources)
    {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey()
    {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

DataSourceAspect 

/**
 * 这是一个使用Spring AOP和切面的类,
 * 它通过@Aspect注解声明自己是一个切面,
 * 而@Order(1)用于指定切面的执行顺序。
 * 该切面的主要作用是根据@DataSource注解来动态切换数据源。
 */
@Aspect
@Order(1)
@Component
public class DataSourceAspect
{
    protected Logger logger = LoggerFactory.getLogger(getClass());

    // @Pointcut定义了切点,即切面在哪些地方执行。
    // 这里的切点是所有带有@DataSource注解或者类上带有@DataSource注解的方法。
    @Pointcut("@annotation(com.huishi.annotation.DataSource)"
            + "|| @within(com.huishi.annotation.DataSource)")
    public void dsPointCut()
    {
        // dsPointCut()方法:
        // 这个方法是一个空方法,其主要作用是给@Pointcut注解提供一个命名的切点,使得@Around注解可以引用这个切点。
        // 给切入点起名dsPointCut
    }

    // @Around注解表示在目标方法执行前后执行一些逻辑。
    // 在这里,它用于切面织入,即在目标方法执行前切换数据源,在目标方法执行后清理数据源。

    /**
     *
     * @param point 目标方法,可以理解为目标方法被拦截下来了。
     * @return 就是目标方法的返回值
     */
    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable
    {
        DataSource dataSource = getDataSource(point);

        if (dataSource != null)
        {
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        }

        try
        {
            // 继续执行下一个通知或目标方法调用
            return point.proceed();
        }
        finally
        {
            // 销毁数据源 在执行方法之后
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    /**
     * 获取需要切换的数据源
     */
    public DataSource getDataSource(ProceedingJoinPoint point)
    {
        // 获取目标方法的签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取目标方法上的DataSource注解
        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
        if (Objects.nonNull(dataSource))
        {
            return dataSource;
        }

        // 获取目标方法类上的DataSource注解
        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
    }
}

DataSource 

/**
 * 自定义多数据源切换注解
 *
 * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
 * 
 * 使用:在需要切换数据源的方法或类上加上 @DataSource(value = DataSourceType.SLAVE),不加默认使用主库
 *
 * @author lin
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
//@Inherited
public @interface DataSource
{
    /**
     * 切换数据源名称
     */
    public DataSourceType value() default DataSourceType.MASTER;
}

DataSourceType 

/**
 * 数据源枚举
 * 
 * @author lin
 */
public enum DataSourceType
{
    /**
     * 主库
     */
    MASTER,

    /**
     * 从库
     */
    SLAVE
}

Git

初始化提交

# 添加所有修改过的文件
git add .

# 提交到本地仓库
git commit -m "提交描述"

#设置远程仓库地址
git remote add origin <远程仓库地址>


# 推送到远程仓库
git push origin <分支名称>

程序部署

nohup java 
-XX:MetaspaceSize=150m -XX:MaxMetaspaceSize=150m 
-Xms320m -Xmx768m 
-jar -Dspringfox.documentation.swagger.v2.host=127.0.0.1:9987/api 
-Dspring.profiles.active=online 
web-data-query-1.0-SNAPSHOT.jar  
>/dev/null 2>&1
  1. nohup 这是一个 Unix/Linux 命令,用于在终端关闭后继续运行程序。后台运行,它将程序的标准输出和标准错误输出重定向到文件 nohup.out,这样即使终端关闭,也能够保持程序的运行。

  2. java 启动 Java 虚拟机。

  3. -XX:MetaspaceSize=150m -XX:MaxMetaspaceSize=150m 这是设置 JVM 元空间大小的选项。Metaspace 是 Java 8 之后用于替代永久代的内存区域,它存储类的元数据。

  4. -Xms320m -Xmx768m 这是设置 Java 堆的初始大小和最大大小的选项。在这里,堆的初始大小为 320MB,最大大小为 768MB。

  5. -jar 指定要运行的 Java 程序是一个 JAR 文件。

  6. -Dspringfox.documentation.swagger.v2.host=127.0.0.1:9987/api 通过 -D 参数设置了 Spring Boot 应用程序的系统属性。在这里,设置了 Swagger 文档的主机地址。

  7. -Dspring.profiles.active=online 同样是通过 -D 参数设置了 Spring Boot 应用程序的系统属性,这里激活了名为 online 的 Spring Profile。

  8. web-data-query-1.0-SNAPSHOT.jar 指定要运行的 JAR 包名称。

  9. >/dev/null 2>&1 这部分是将标准输出和标准错误输出重定向到 /dev/null,这意味着输出会被丢弃,不会在终端显示。

综合起来,这个命令的作用是在后台运行一个 Java 应用程序,使用指定的 JVM 配置、Spring Profile 和其他系统属性。

你可能感兴趣的:(Java,java,开发语言)