mybatis自动分表和JdbcTemplate自动建表
需求背景:由于业务的增长,原有的表存放的太多的数据,每次去查询的数据耗时很久,严重影响了查询效率,所以才有了今天的博客文章,在处理问题的过程中,有考虑mysql的分区方案,我的分区是按照月份的,但是对于定时任务来说,时间存在重复的,所以mysql分区方案被剔除,因为项目xxl-job的方案,主要针对的表是xxl_job_log,但是改变涉及的位置比较多,手动去修改,一个是比较麻烦,二是容易出现测试测漏掉的情况发生,所以引入了mybatis的拦截器Interceptor,整体方案比较简单,但是因为存在同一个时间,很多任务都会同时执行的问题,所以会有并发比较高的问题
使用的数据库:mysql
使用的java的持久层框架: mybatis
拦截器部分的全部代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | package com.java.mybatisservice.interceptor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @Description: * @Author: 喵星人 * @Create: 2023/11/10 11:02 */ /** * method = "query"拦截select方法、而method = "update"则能拦截insert、update、delete的方法 * * @author 喵星人 */ @Intercepts ({ @Signature (type = Executor. class , method = "query" , args = {MappedStatement. class , Object. class , RowBounds. class , ResultHandler. class }), @Signature (type = Executor. class , method = "update" , args = {MappedStatement. class , Object. class }) }) @Component @Slf4j public class ReplaceTableInterceptor implements Interceptor { private final String tableName = "recy_bank_resume" ; private final ReentrantLock lock = new ReentrantLock(); private final Pattern tablePattern; private final ConcurrentHashMap<String, String> tableNameCache = new ConcurrentHashMap<>(); /** * 保存当前月份的成员变量 */ private String currentMonth; public ReplaceTableInterceptor() { // 在构造方法中创建正则表达式 String regex = "\\b" + Pattern.quote(tableName) + "\\b" ; tablePattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); // 初始化当前月份 currentMonth = LocalDate.now().format(DateTimeFormatter.ofPattern( "yyyyMMdd" )); } @Override public Object intercept(Invocation invocation) throws Throwable { updateTableNameCache(); // 更新表名缓存 Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[ 0 ]; Object parameterObject = args[ 1 ]; BoundSql boundSql = ms.getBoundSql(parameterObject); String originalSql = boundSql.getSql(); // log.info("【原始sql】:{}", originalSql); if (isSelectStatement(ms) && isTargetTable(originalSql, tableName)) { String newTableName = tableNameCache.get( "current" ); String newSql = originalSql.replace(tableName, newTableName); log.info( "【修改后的sql】:{}" , newSql); // 确保替换表名是原子操作 lock.lock(); try { BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql, boundSql.getParameterMappings(), parameterObject); MappedStatement newMs = copyMappedStatement(ms, new BoundSqlSqlSource(newBoundSql)); args[ 0 ] = newMs; } finally { lock.unlock(); } } return invocation.proceed(); } private void updateTableNameCache() { String currentMonthNow = LocalDate.now().format(DateTimeFormatter.ofPattern( "yyyyMMdd" )); String newTableName = tableName + currentMonthNow; tableNameCache.computeIfAbsent( "current" , k -> newTableName); } private String getNewTableName(String tableName) { // 根据需求生成新的表名,可以使用当前日期等方式 String currentMonthNow = LocalDate.now().format(DateTimeFormatter.ofPattern( "yyyyMMdd" )); if (!currentMonth.equals(currentMonthNow)) { // 如果月份变化了,更新当前月份和需要的表名 currentMonth = currentMonthNow; return tableName + currentMonthNow; } // 月份没变化,直接返回原表名 return tableName + currentMonth; } private boolean isTargetTable(String sql, String tableName) { // 使用预先创建的正则表达式 Matcher matcher = tablePattern.matcher(sql); return matcher.find(); } private boolean isSelectStatement(MappedStatement mappedStatement) { return mappedStatement.getSqlCommandType() == SqlCommandType.SELECT; } private MappedStatement copyMappedStatement(MappedStatement ms, SqlSource newSqlSource) { MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); builder.resource(ms.getResource()); builder.fetchSize(ms.getFetchSize()); builder.statementType(ms.getStatementType()); builder.keyGenerator(ms.getKeyGenerator()); if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0 ) { builder.keyProperty(String.join( "," , ms.getKeyProperties())); } builder.timeout(ms.getTimeout()); builder.parameterMap(ms.getParameterMap()); builder.resultMaps(ms.getResultMaps()); builder.resultSetType(ms.getResultSetType()); builder.cache(ms.getCache()); builder.flushCacheRequired(ms.isFlushCacheRequired()); builder.useCache(ms.isUseCache()); return builder.build(); } /*** * MappedStatement构造器接受的是SqlSource * 实现SqlSource接口,将BoundSql封装进去 */ public static class BoundSqlSqlSource implements SqlSource { private BoundSql boundSql; public BoundSqlSqlSource(BoundSql boundSql) { this .boundSql = boundSql; } @Override public BoundSql getBoundSql(Object parameterObject) { return boundSql; } } } |
pom文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | <?xml version= "1.0" encoding= "UTF-8" ?> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion> 4.0 . 0 </modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version> 2.4 . 2 </version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.mybatis</groupId> <artifactId>mybatis-service</artifactId> <version> 0.0 . 1 -SNAPSHOT</version> <name>mybatis-service</name> <description>Demo project for Spring Boot</description> <properties> <java.version> 1.8 </java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version> 2.1 . 4 </version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional> true </optional> </dependency> <!--实体类字段校验依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version> 8.0 . 27 </version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version> 3.9 </version> </dependency> <!--引入junit单元测试依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version> 4.12 </version> </dependency> <!--引入thymeleaf依赖--> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-starter-thymeleaf</artifactId>--> <!-- </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--添加fastjson依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version> 1.2 . 83 </version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
配置文件application.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | server.port= 80 logging.level.com.java=debug logging.level.web=debug log4j.logger.org.mybatis=DEBUG spring.devtools.add-properties= false ip.port= 127.0 . 0.1 : 3306 spring.datasource.driver- class -name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql: //${ip.port}/yourheart?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.hikari.connection-timeout= 20000 spring.datasource.hikari.maximum-pool-size= 10 spring.datasource.hikari.minimum-idle= 10 mybatis.mapper-locations=classpath:mapping/*.xml mybatis.configuration.map-underscore-to-camel- case = true |
启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.java.mybatisservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MybatisServiceApplication { public static void main(String[] args) { SpringApplication.run(MybatisServiceApplication. class , args); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?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.java.mybatisservice.mapper.RecyBankResumeMapper" > <select id= "getAll" resultType= "com.java.mybatisservice.bank.controller.front.RecyBankResume" > SELECT * FROM recy_bank_resume WHERE bank_resume_status= '2' ORDER BY update_resume_times DESC </select> <insert id= "adds" parameterType= "com.java.mybatisservice.bank.controller.front.BankResume" > INSERT INTO recy_bank_resume(bank_end,bank_name,bank_funds,bank_use,update_resume_times,resume_user,bank_resume_status) VALUES(#{bankEnd},#{bankName},#{bankFunds},#{bankUse},NOW(),#{resumeUser},#{bankResumeStatus}) </insert> </mapper> |
测试类相关代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.java.mybatisservice; import com.java.mybatisservice.mapper.RecyResumerMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class MybatisServiceApplicationTests { @Autowired private RecyResumerMapper recyResumerMapper; @Test public void test(){ } } |
以上代码解决高并发环境数据处理错误的场景,保证了原子性,避免了线程不安全的问题发生
下面列出自动建表相关,以下项目其实就是分布式定时任务xxl-job中的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | package com.xxl.job.executor.service.jobhandler; import com.xxl.job.core.handler.annotation.XxlJob; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; /** * XxlJob开发示例(Bean模式) * * 开发步骤: * 1、任务开发:在Spring Bean实例中,开发Job方法; * 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。 * 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志; * 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果; * * @author xuxueli 2019-12-11 21:52:51 */ @Component public class SampleXxlJob { private static Logger logger = LoggerFactory.getLogger(SampleXxlJob. class ); @Autowired private JdbcTemplate jdbcTemplate; @XxlJob ( "demoJobHandler11" ) public void demoJobHandle11() throws Exception { String tableName = "xxl_job_log" + LocalDate.now().format(DateTimeFormatter.ofPattern( "yyyyMM" )); createTableIfNotExists(tableName); } private void createTableIfNotExists(String tableName) { if (!isTableExists(tableName)) { String createTableSql = "CREATE TABLE " + tableName + " (\n" + " `id` bigint(20) NOT NULL AUTO_INCREMENT,\n" + " `job_group` int(11) NOT NULL COMMENT '执行器主键ID',\n" + " `job_id` int(11) NOT NULL COMMENT '任务,主键ID',\n" + " `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',\n" + " `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',\n" + " `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',\n" + " `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',\n" + " `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',\n" + " `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',\n" + " `trigger_code` int(11) NOT NULL COMMENT '调度-结果',\n" + " `trigger_msg` text COMMENT '调度-日志',\n" + " `handle_time` datetime DEFAULT NULL COMMENT '执行-时间',\n" + " `handle_code` int(11) NOT NULL COMMENT '执行-状态',\n" + " `handle_msg` text COMMENT '执行-日志',\n" + " `alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',\n" + " PRIMARY KEY (`id`),\n" + " KEY `I_trigger_time` (`trigger_time`),\n" + " KEY `I_handle_code` (`handle_code`),\n" + " KEY `trigger_handle_alarm_retry` (`trigger_code`,`handle_code`,`alarm_status`,`executor_fail_retry_count`)\n" + ") ENGINE=InnoDB AUTO_INCREMENT=47953569 DEFAULT CHARSET=utf8mb4;" ; try { jdbcTemplate.execute(createTableSql); logger.info( "Double-check if the table is created successfully" ); if (!isTableExists(tableName)) { throw new RuntimeException( "Failed to create table: " + tableName); } } catch (Exception e) { // Log error and re-try table creation logger.error( "Error creating table:{}" ,e.getMessage()); createTableIfNotExists(tableName); } } else { logger.info( "表:{} 已经存在" ,tableName); } } private boolean isTableExists(String tableName) { try (Connection connection = jdbcTemplate.getDataSource().getConnection()) { DatabaseMetaData metaData = connection.getMetaData(); try (ResultSet tables = metaData.getTables( null , null , tableName, new String[] { "TABLE" })) { return tables.next(); } } catch (SQLException e) { throw new RuntimeException( "Failed to check table existence: " + tableName, e); } } } |
我使用的mysql数据库的版本是5.7.43
对应的配置文件的数据库信息
1 2 3 4 5 | # 2023 年 10 月 30 日添加 spring.datasource.url=jdbc:mysql: //127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root spring.datasource.driver- class -name=com.mysql.jdbc.Driver |
pom文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | <?xml version= "1.0" encoding= "UTF-8" ?> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion> 4.0 . 0 </modelVersion> <parent> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-executor-samples</artifactId> <version> 2.3 . 0 </version> </parent> <artifactId>xxl-job-executor-sample-springboot</artifactId> <packaging>jar</packaging> <name>${project.artifactId}</name> <description>Example executor project for spring boot.</description> <url>https: //www.xuxueli.com/</url> <properties> </properties> <dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot (依赖管理:继承一些默认的依赖,工程需要依赖的jar包的管理,申明其他dependency的时候就不需要version) --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope> import </scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- spring-boot-starter-web (spring-webmvc + tomcat) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- xxl-job-core --> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${project.parent.version}</version> </dependency> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-starter-data-jpa</artifactId>--> <!-- </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <!-- spring-boot-maven-plugin (提供了直接运行项目的插件:如果是通过parent方式继承spring-boot-starter-parent则不用此插件) --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> |
xxl-job的主pom文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion> 4.0 . 0 </modelVersion> <groupId>com.xuxueli</groupId> <artifactId>xxl-job</artifactId> <version> 2.3 . 0 </version> <packaging>pom</packaging> <name>${project.artifactId}</name> <description>A distributed task scheduling framework.</description> <url>https: //www.xuxueli.com/</url> <modules> <module>xxl-job-core</module> <module>xxl-job-admin</module> <module>xxl-job-executor-samples</module> </modules> <properties> <project.build.sourceEncoding>UTF- 8 </project.build.sourceEncoding> <project.reporting.outputEncoding>UTF- 8 </project.reporting.outputEncoding> <maven.compiler.encoding>UTF- 8 </maven.compiler.encoding> <maven.compiler.source> 1.8 </maven.compiler.source> <maven.compiler.target> 1.8 </maven.compiler.target> <maven.test.skip> true </maven.test.skip> <netty-all.version> 4.1 . 58 .Final</netty-all.version> <gson.version> 2.8 . 6 </gson.version> <spring.version> 5.3 . 26 </spring.version> <spring-boot.version> 2.4 . 2 </spring-boot.version> <mybatis-spring-boot-starter.version> 2.1 . 4 </mybatis-spring-boot-starter.version> <mysql-connector-java.version> 5.1 . 6 </mysql-connector-java.version> <slf4j-api.version> 1.7 . 30 </slf4j-api.version> <junit.version> 5.7 . 1 </junit.version> <javax.annotation-api.version> 1.3 . 2 </javax.annotation-api.version> <groovy.version> 3.0 . 7 </groovy.version> <maven-source-plugin.version> 3.2 . 1 </maven-source-plugin.version> <maven-javadoc-plugin.version> 3.2 . 0 </maven-javadoc-plugin.version> <maven-gpg-plugin.version> 1.6 </maven-gpg-plugin.version> <maven-war-plugin.version> 3.3 . 1 </maven-war-plugin.version> <logback.version> 1.2 . 10 </logback.version> <log4j.version> 2.17 . 1 </log4j.version> <tomcat.version> 9.0 . 73 </tomcat.version> </properties> <build> <plugins> </plugins> </build> <licenses> <license> <name>GNU General Public License version 3 </name> <url>https: //opensource.org/licenses/GPL-3.0</url> </license> </licenses> <scm> <tag>master</tag> <url>https: //github.com/xuxueli/xxl-job.git</url> <connection>scm:git:https: //github.com/xuxueli/xxl-job.git</connection> <developerConnection>scm:git:git @github .com:xuxueli/xxl-job.git</developerConnection> </scm> <developers> <developer> <id>XXL</id> <name>xuxueli</name> <email> 931591021 @qq .com</email> <url>https: //github.com/xuxueli</url> </developer> </developers> <dependencyManagement> <dependencies> <!-- 显式指定Tomcat版本 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-el</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-websocket</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> </dependencies> </dependencyManagement> <profiles> <profile> <id>release</id> <build> <plugins> <!-- Source --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>${maven-source-plugin.version}</version> <executions> <execution> <phase> package </phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <!-- Javadoc --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>${maven-javadoc-plugin.version}</version> <executions> <execution> <phase> package </phase> <goals> <goal>jar</goal> </goals> <configuration> <doclint>none</doclint> </configuration> </execution> </executions> </plugin> <!-- GPG --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <version>${maven-gpg-plugin.version}</version> <configuration> <useAgent> false </useAgent> </configuration> <executions> <execution> <phase>verify</phase> <goals> <goal>sign</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <distributionManagement> <snapshotRepository> <id>oss</id> <url>https: //oss.sonatype.org/content/repositories/snapshots/</url> </snapshotRepository> <repository> <id>oss</id> <url>https: //oss.sonatype.org/service/local/staging/deploy/maven2/</url> </repository> </distributionManagement> </profile> </profiles> </project> |
如果文字存在不好理解的情况,对应的也会录制对应的视频发布到b站,希望可以对您有所帮忙
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)