├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── transactionthread │ │ ├── TransactionthreadApplication.java │ │ ├── base │ │ ├── BaseThreadTransaction.java │ │ ├── BaseThreadTransactionTask.java │ │ └── ThreadTransaction.java │ │ ├── core │ │ ├── InputParamCallable.java │ │ ├── InputParamRunnable.java │ │ ├── MajorTaskCallable.java │ │ ├── MajorTaskRunnable.java │ │ ├── ThreadIndependenceTransactionTask.java │ │ ├── ThreadTask.java │ │ ├── ThreadTransactionTask.java │ │ └── ThreadTransactionTool.java │ │ └── threadpool │ │ ├── TransactionThreadPool.java │ │ ├── namefactory │ │ ├── AbstractNameThreadFactory.java │ │ └── TransactionNameThreadFactory.java │ │ └── rejectedexecutionhandler │ │ └── ThreadPoolRejectedExecutionHandler.java └── resources │ └── application.yml └── test └── java └── com └── example └── transactionthread └── TransactionthreadApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shining-stars-l/transaction-thread/6fb371a7138181a162aa30e2f5fee74a6783b811/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # transaction-thread项目介绍 2 | **保证异步线程能够保证事务的使用工具** 3 | ## 说明 4 | - 此工具是为了解决在使用`spring`框架下,解决使用异步线程执行任务出现的事务问题。 5 | - 针对不同的业务使用提供相应`api`,即可达到目的 6 | - 通过获取`spring`中`bean`的方式引入即可 7 | ## 特点 8 | - 支持`批量异步任务`执行 9 | - 支持接收异步任务执行结果的功能,调用api时,传入`List`类型集合参数即可 10 | - 支持`批量异步任务`执行,且支持`事务`,当某个异步任务出现`异常`,`事务`可回滚 11 | - 支持`主任务`和`批量异步任务`的执行,且支持`事务`,当`主任务`和`批量异步任务`中只要有一个任务发生异常`事务`都会`回滚` 12 | - 目前异步任务最大数量为`100` 13 | ## 注意 14 | - 底层采用的线程池为核心线程数为`0`,最大线程数为`101`,因为如果核心数不为`0`的话,当任务数大于了线程核心数会发生死锁情况。 15 | - 底层采用的事务级别为`READ_COMMITTED`,如果采用`REPEATABLE_READ`,由于mysql在`REPEATABLE_READ`级别会产生间隙锁,所以可能发生死锁情况。 16 | 17 | # ThreadTransactionTool工具使用 18 | ## 提供的api 19 | ```java 20 | /** 21 | * 异步任务运行 22 | * @param taskList 需要异步执行的任务 23 | */ 24 | public void execute(List taskList) 25 | 26 | /** 27 | * 异步任务运行 28 | * @param callTaskList 需要异步执行的任务(有返回值) 29 | * @param resultList 承载异步执行任务结果的集合 30 | * @param sequence 是否要求执行的任务 和 承载异步执行任务结果的集合保证顺序 31 | */ 32 | public void call(List> callTaskList,List resultList,boolean sequence) 33 | 34 | /** 35 | * 异步任务独立事务运行(出现异常回滚本异步任务,其他异步任务不会回滚) 36 | * @param taskList 需要异步执行的任务 37 | */ 38 | public void independenceTransactionExecute(List taskList) 39 | /** 40 | * 异步任务独立事务运行(出现异常回滚本异步任务,其他异步任务不会回滚) 41 | * @param callTaskList 需要异步执行的任务(有返回值) 42 | * @param resultList 承载异步执行任务结果的集合 43 | */ 44 | public void independenceTransactionCall(List> callTaskList,List resultList) 45 | /** 46 | * @param taskList 需要异步执行的任务 47 | */ 48 | public void transactionExecute(List taskList) 49 | 50 | /** 51 | * @param callTaskList 需要异步执行的任务(有返回值) 52 | * @param resultList 承载异步执行任务结果的集合 53 | */ 54 | public void transactionCall(List> callTaskList, List resultList) 55 | 56 | /** 57 | * @param majorTaskRunnable 需要执行的主任务 58 | * @param taskList 需要异步执行的任务 59 | * @throws Throwable 抛出的异常 60 | */ 61 | public void transactionExecute(MajorTaskRunnable majorTaskRunnable, List taskList) 62 | 63 | /** 64 | * @param majorTaskRunnable 需要执行的主任务 65 | * @param callTaskList 需要异步执行的任务(有返回值) 66 | * @param resultList 承载异步执行任务结果的集合 67 | * @throws Throwable 抛出的异常 68 | */ 69 | public void transactionCall(MajorTaskRunnable majorTaskRunnable, 70 | List> callTaskList, List resultList) 71 | 72 | /** 73 | * @param majorTaskCallable 需要执行的主任务(有返回值) 74 | * @param taskList 需要异步执行的任务 75 | * @return T 主任务的返回值 76 | * @throws Throwable 抛出的异常 77 | */ 78 | public T transactionExecute(MajorTaskCallable majorTaskCallable, List taskList) 79 | 80 | /** 81 | * @param majorTaskCallable 需要执行的主任务(有返回值) 82 | * @param callTaskList 需要异步执行的任务(有返回值) 83 | * @param resultList 承载异步执行任务结果的集合 84 | * @return T 主任务的返回值 85 | * @throws Throwable 抛出的异常 86 | */ 87 | public T transactionCall(MajorTaskCallable majorTaskCallable, 88 | List> callTaskList, List resultList) 89 | 90 | /** 91 | * @param majorTaskCallable 需要执行的主任务(有返回值) 92 | * @param inputParamTaskList 需要异步执行的任务(需要有主任务中的返回值来做输入参数) 93 | * @return T 主任务的返回值 94 | * @throws Throwable 抛出的异常 95 | */ 96 | public T transactionExecuteInputParamTask(MajorTaskCallable majorTaskCallable, 97 | List> inputParamTaskList) 98 | 99 | /** 100 | * @param majorTaskCallable 需要执行的主任务(有返回值) 101 | * @param inputParamCallTaskList 需要异步执行的任务(有返回值)(需要有主任务中的返回值来做输入参数) 102 | * @param resultList 承载异步执行任务结果的集合 103 | * @return T 主任务的返回值 104 | * @throws Throwable 抛出的异常 105 | */ 106 | public T transactionCallInputParamCallTask(MajorTaskCallable majorTaskCallable, 107 | List> inputParamCallTaskList, List resultList) 108 | ``` 109 | ## api使用示例 110 | ### 1. public void execute(List taskList) 111 | #### 说明 112 | 异步任务运行 113 | ```java 114 | public Integer addAccount(int id){ 115 | List runnableList = new ArrayList<>(); 116 | for(int i = 1; i<= 20; i++){ 117 | int temp = i; 118 | Runnable r = () -> { 119 | Account account = new Account(); 120 | account.setId(temp); 121 | account.setAccountId(IdGeneratorUtil.getId()); 122 | account.setName("sss"); 123 | account.setPassword("www"); 124 | account.setAge(temp); 125 | this.add(account); 126 | }; 127 | runnableList.add(r); 128 | } 129 | threadTransactionTool.execute(runnableList); 130 | return null; 131 | } 132 | ``` 133 | ### 2. public void call(List> callTaskList,List resultList) 134 | #### 说明 135 | 异步任务运行,通过`List类型入参`拿到异步任务结果。 136 | ```java 137 | public Object addAccount(int id){ 138 | List> callableList = new ArrayList<>(); 139 | for(int i = 1; i<= 20; i++){ 140 | int temp = i; 141 | Callable c = () -> { 142 | Account account = new Account(); 143 | account.setId(temp); 144 | account.setAccountId(IdGeneratorUtil.getId()); 145 | account.setName("sss"); 146 | account.setPassword("www"); 147 | account.setAge(temp); 148 | this.add(account); 149 | return temp; 150 | }; 151 | callableList.add(c); 152 | } 153 | List resultList = new ArrayList<>(); 154 | threadTransactionTool.call(callableList,resultList,true); 155 | return resultList; 156 | } 157 | ``` 158 | ### 3. public void independenceTransactionExecute(List taskList) 159 | #### 说明 160 | 异步任务`独立事务`运行(出现异常`回滚`本异步任务,其他异步任务`不会回滚`) 161 | ```java 162 | public Integer addAccount(int id){ 163 | List runnableList = new ArrayList<>(); 164 | for(int i = 1; i<= 20; i++){ 165 | int temp = i; 166 | Runnable r = () -> { 167 | Account account = new Account(); 168 | account.setId(temp); 169 | account.setAccountId(IdGeneratorUtil.getId()); 170 | account.setName("sss"); 171 | account.setPassword("www"); 172 | account.setAge(temp); 173 | this.add(account); 174 | }; 175 | runnableList.add(r); 176 | } 177 | threadTransactionTool.independenceTransactionExecute(runnableList); 178 | return null; 179 | } 180 | ``` 181 | 182 | ### 4. public void independenceTransactionCall(List> callTaskList,List resultList) 183 | #### 说明 184 | 异步任务`独立事务`运行(出现异常`回滚`本异步任务,其他异步任务`不会回滚`),通过`List类型入参`拿到异步任务结果。 185 | ```java 186 | public Object addAccount(int id){ 187 | List> callableList = new ArrayList<>(); 188 | for(int i = 1; i<= 20; i++){ 189 | int temp = i; 190 | Callable c = () -> { 191 | Account account = new Account(); 192 | account.setId(temp); 193 | account.setAccountId(IdGeneratorUtil.getId()); 194 | account.setName("sss"); 195 | account.setPassword("www"); 196 | account.setAge(temp); 197 | this.add(account); 198 | return temp; 199 | }; 200 | callableList.add(c); 201 | } 202 | List resultList = new ArrayList<>(); 203 | threadTransactionTool.independenceTransactionCall(callableList,resultList); 204 | return resultList; 205 | } 206 | ``` 207 | ### 5. public void transactionExecute(List taskList) 208 | #### 说明 209 | 处理异步执行的任务 210 | ```java 211 | public Integer addUserAndAccount(User user){ 212 | long startTime = System.currentTimeMillis(); 213 | Integer result = userMapper.add(user); 214 | 215 | List runnableList = new ArrayList<>(); 216 | for(int i = 1; i<= 20; i++){ 217 | int temp = i; 218 | Runnable r = () -> { 219 | Account account = new Account(); 220 | account.setId(temp); 221 | account.setAccountId(IdGeneratorUtil.getId()); 222 | account.setName("sss"); 223 | account.setPassword("www"); 224 | account.setAge(temp); 225 | accountService.add(account); 226 | }; 227 | runnableList.add(r); 228 | } 229 | 230 | try { 231 | threadTransactionTool.transactionExecute(runnableList); 232 | } catch (Throwable e) { 233 | System.out.println("===检测到异常回滚!!!==="); 234 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 235 | } 236 | 237 | long endTime = System.currentTimeMillis(); 238 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 239 | return result; 240 | } 241 | ``` 242 | #### 特点 243 | 批量`异步任务`执行时,当其中一个出现`异常`后,其余的`异步任务`都会`回滚`。但是`当主任务`添加user的操作出现异常,异步任务`不会回滚`,需要使用`threadTransactionTool`提供的另外方法api。 244 | 245 | ### 6. public void transactionCall(List> callTaskList, List resultList) 246 | #### 说明 247 | 处理异步执行的任务,并拿到异步任务`结果` 248 | ```java 249 | public Object addUserAndAccount(User user){ 250 | long startTime = System.currentTimeMillis(); 251 | 252 | Integer result = 0; 253 | List> callableList = new ArrayList<>(); 254 | for(int i = 1; i<= 20; i++){ 255 | int temp = i; 256 | Callable call = () -> { 257 | Account account = new Account(); 258 | account.setId(temp); 259 | account.setAccountId(IdGeneratorUtil.getId()); 260 | account.setName("sss"); 261 | account.setPassword("www"); 262 | account.setAge(temp); 263 | accountService.add(account); 264 | return temp; 265 | }; 266 | callableList.add(call); 267 | } 268 | 269 | List resultList = new ArrayList<>(); 270 | try { 271 | threadTransactionTool.transactionCall(callableList,resultList); 272 | } catch (Throwable e) { 273 | System.out.println("===检测到异常回滚!!!==="); 274 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 275 | } 276 | 277 | long endTime = System.currentTimeMillis(); 278 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 279 | return resultList; 280 | } 281 | ``` 282 | #### 特点 283 | 对`介绍5`的api增强了`接收异步结果`的功能,通过传入`resultList`参数实现。 284 | 285 | ### 7. public void transactionExecute(MajorTaskRunnable majorTaskRunnable, List taskList) 286 | #### 说明 287 | 处理主任务和异步执行的任务 288 | ```java 289 | public Integer addUserAndAccount(User user){ 290 | long startTime = System.currentTimeMillis(); 291 | 292 | Integer result = 0; 293 | List runnableList = new ArrayList<>(); 294 | for(int i = 1; i<= 20; i++){ 295 | int temp = i; 296 | Runnable r = () -> { 297 | Account account = new Account(); 298 | account.setId(temp); 299 | account.setAccountId(IdGeneratorUtil.getId()); 300 | account.setName("sss"); 301 | account.setPassword("www"); 302 | account.setAge(temp); 303 | accountService.add(account); 304 | }; 305 | runnableList.add(r); 306 | } 307 | try { 308 | threadTransactionTool.transactionExecute(() -> { 309 | userMapper.add(user); 310 | }, runnableList); 311 | } catch (Throwable e) { 312 | System.out.println("===检测到异常回滚!!!==="); 313 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 314 | } 315 | 316 | long endTime = System.currentTimeMillis(); 317 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 318 | return result; 319 | } 320 | ``` 321 | #### 特点 322 | 批量`异步任务`执行时,当其中一个出现`异常`后,其余的`异步任务`都会`回滚`。并且`主任务`添加user的操作出现`异常`,`异步任务`也能够`回滚`。 323 | 324 | ### 8. public void transactionCall(MajorTaskRunnable majorTaskRunnable, List> callTaskList, List resultList) 325 | #### 说明 326 | 处理主任务和异步执行的任务并拿到异步任务`结果` 327 | ```java 328 | public Object addUserAndAccount(User user){ 329 | long startTime = System.currentTimeMillis(); 330 | 331 | Integer result = 0; 332 | List> callableList = new ArrayList<>(); 333 | for(int i = 1; i<= 20; i++){ 334 | int temp = i; 335 | Callable call = () -> { 336 | Account account = new Account(); 337 | account.setId(temp); 338 | account.setAccountId(IdGeneratorUtil.getId()); 339 | account.setName("sss"); 340 | account.setPassword("www"); 341 | account.setAge(temp); 342 | accountService.add(account); 343 | return temp; 344 | }; 345 | callableList.add(call); 346 | } 347 | 348 | List resultList = new ArrayList<>(); 349 | try { 350 | threadTransactionTool.transactionCall(() -> { 351 | userMapper.add(user); 352 | }, callableList,resultList); 353 | } catch (Throwable e) { 354 | System.out.println("===检测到异常回滚!!!==="); 355 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 356 | } 357 | 358 | long endTime = System.currentTimeMillis(); 359 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 360 | return resultList; 361 | } 362 | ``` 363 | #### 特点 364 | 对`介绍7`的api增强了`接收异步结果`的功能,通过传入`resultList`参数实现。 365 | 366 | ### 9. public T transactionExecute(MajorTaskCallable majorTaskCallable, List taskList) 367 | #### 说明 368 | 处理主任务和异步执行的任务,并返回主任务`结果` 369 | ```java 370 | public Integer addUserAndAccount(User user){ 371 | long startTime = System.currentTimeMillis(); 372 | 373 | Integer result = 0; 374 | List runnableList = new ArrayList<>(); 375 | for(int i = 1; i<= 20; i++){ 376 | int temp = i; 377 | Runnable r = () -> { 378 | Account account = new Account(); 379 | account.setId(temp); 380 | account.setAccountId(IdGeneratorUtil.getId()); 381 | account.setName("sss"); 382 | account.setPassword("www"); 383 | account.setAge(temp); 384 | accountService.add(account); 385 | }; 386 | runnableList.add(r); 387 | } 388 | try { 389 | result = threadTransactionTool.transactionExecute(() -> { 390 | int insertResult = userMapper.add(user); 391 | return insertResult; 392 | }, runnableList); 393 | } catch (Throwable e) { 394 | System.out.println("===检测到异常回滚!!!==="); 395 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 396 | } 397 | 398 | long endTime = System.currentTimeMillis(); 399 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 400 | return result; 401 | } 402 | ``` 403 | #### 特点 404 | 对`介绍7`的api增强了`返回主任务结果`的功能。 405 | 406 | ### 10. public T transactionCall(MajorTaskCallable majorTaskCallable, List> callTaskList, List resultList) 407 | #### 说明 408 | 处理主任务和异步执行的任务,并返回主任务`结果`,并且拿到异步任务`结果` 409 | ```java 410 | public Object addUserAndAccount(User user){ 411 | long startTime = System.currentTimeMillis(); 412 | 413 | Integer result = 0; 414 | List> callableList = new ArrayList<>(); 415 | for(int i = 1; i<= 20; i++){ 416 | int temp = i; 417 | Callable call = () -> { 418 | Account account = new Account(); 419 | account.setId(temp); 420 | account.setAccountId(IdGeneratorUtil.getId()); 421 | account.setName("sss"); 422 | account.setPassword("www"); 423 | account.setAge(temp); 424 | accountService.add(account); 425 | return temp; 426 | }; 427 | callableList.add(call); 428 | } 429 | 430 | List resultList = new ArrayList<>(); 431 | try { 432 | result = threadTransactionTool.transactionCall(() -> { 433 | int insertResult = userMapper.add(user); 434 | return insertResult; 435 | }, callableList,resultList); 436 | } catch (Throwable e) { 437 | System.out.println("===检测到异常回滚!!!==="); 438 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 439 | } 440 | 441 | long endTime = System.currentTimeMillis(); 442 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 443 | return resultList; 444 | } 445 | ``` 446 | #### 特点 447 | 对`介绍7`的api增强了`接收主任务结果`的功能。也增强了`接收异步结果`的功能,通过传入`resultList`参数实现。 448 | ### 11. public T transactionExecuteInputParamTask(MajorTaskCallable majorTaskCallable, List> inputParamTaskList) 449 | #### 说明 450 | 处理主任务和异步执行的任务(`异步任务需要主任务的返回值`),并返回主任务`结果` 451 | ```java 452 | public Object addUserAndAccount(User user){ 453 | long startTime = System.currentTimeMillis(); 454 | String userNameResult = null; 455 | List> inputParamRunnableList = new ArrayList<>(); 456 | for(int i = 1; i<= 20; i++){ 457 | int temp = i; 458 | InputParamRunnable c = (InputParamRunnable) userName -> { 459 | Account account = new Account(); 460 | account.setId(temp); 461 | account.setAccountId(IdGeneratorUtil.getId()); 462 | account.setName("sss"); 463 | account.setPassword("www"); 464 | account.setAge(temp); 465 | account.setUserName(userName); 466 | accountService.add(account); 467 | }; 468 | inputParamRunnableList.add(c); 469 | } 470 | try { 471 | userNameResult = threadTransactionTool.transactionExecuteInputParamTask(() -> { 472 | userMapper.add(user); 473 | User userResult = userMapper.get(user.getId()); 474 | return userResult.getName(); 475 | },inputParamRunnableList); 476 | } catch (Throwable e) { 477 | System.out.println("===检测到异常回滚!!!"+e+"==="); 478 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 479 | } 480 | 481 | long endTime = System.currentTimeMillis(); 482 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 483 | return userNameResult; 484 | } 485 | ``` 486 | #### 特点 487 | 对`介绍9`的api增加了异步任务需要主任务`返回值`的功能。 488 | 489 | ### 12. public T transactionCallInputParamCallTask(MajorTaskCallable majorTaskCallable, List> inputParamCallTaskList, List resultList) 490 | #### 说明 491 | 处理主任务和异步执行的任务(`异步任务需要主任务的返回值`),并返回主任务`结果` ,以及拿到异步任务`结果` 492 | ```java 493 | public Object addUserAndAccount(User user){ 494 | long startTime = System.currentTimeMillis(); 495 | String userNameResult = null; 496 | List> inputParamCallableList = new ArrayList<>(); 497 | for(int i = 1; i<= 20; i++){ 498 | int temp = i; 499 | InputParamCallable c = (InputParamCallable) userName -> { 500 | Account account = new Account(); 501 | account.setId(temp); 502 | account.setAccountId(IdGeneratorUtil.getId()); 503 | account.setName("sss"); 504 | account.setPassword("www"); 505 | account.setAge(temp); 506 | account.setUserName(userName); 507 | try { 508 | Thread.sleep(1000); 509 | } catch (InterruptedException e) { 510 | e.printStackTrace(); 511 | } 512 | accountService.add(account); 513 | return temp; 514 | }; 515 | inputParamCallableList.add(c); 516 | } 517 | List resultList = new ArrayList<>(); 518 | try { 519 | userNameResult = threadTransactionTool.transactionCallInputParamCallTask(() -> { 520 | userMapper.add(user); 521 | User userResult = userMapper.get(user.getId()); 522 | return userResult.getName(); 523 | },inputParamCallableList,resultList); 524 | } catch (Throwable e) { 525 | System.out.println("===检测到异常回滚!!!"+e+"==="); 526 | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 527 | } 528 | 529 | long endTime = System.currentTimeMillis(); 530 | System.out.println("===耗时:"+(endTime - startTime)+"==="); 531 | return resultList; 532 | } 533 | ``` 534 | 535 | ## 原理 536 | ![](https://files.mdnice.com/user/12133/09d545fd-307d-49ed-a626-dbca688be0ac.png) 537 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.3 9 | 10 | 11 | com.example.transactionthread 12 | transactionthread 13 | 0.0.1-SNAPSHOT 14 | transactionthread 15 | Demo project for Spring Boot 16 | 17 | 1.8 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-test 28 | test 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-jdbc 34 | 35 | 36 | 37 | mysql 38 | mysql-connector-java 39 | 6.0.6 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 53 | 8 54 | 8 55 | 56 | 57 | 58 | 59 | 60 | src/main/java 61 | 62 | **/*.xml 63 | 64 | 65 | 66 | src/main/resources 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/TransactionthreadApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TransactionthreadApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TransactionthreadApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/base/BaseThreadTransaction.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.base; 2 | 3 | import com.example.transactionthread.core.InputParamCallable; 4 | import com.example.transactionthread.core.MajorTaskCallable; 5 | import com.example.transactionthread.core.MajorTaskRunnable; 6 | import com.example.transactionthread.core.ThreadIndependenceTransactionTask; 7 | import com.example.transactionthread.core.ThreadTask; 8 | import com.example.transactionthread.core.ThreadTransactionTask; 9 | import com.example.transactionthread.threadpool.TransactionThreadPool; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 12 | import org.springframework.stereotype.Component; 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.concurrent.Callable; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.CountDownLatch; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | import java.util.concurrent.atomic.AtomicInteger; 23 | 24 | /** 25 | * @program: toolkit 26 | * @description: 事务线程基类(不对外暴露,是作为ThreadTransactionTool的抽象基类) 27 | * @author: lk 28 | * @create: 2022-01-12 29 | **/ 30 | @Component 31 | public class BaseThreadTransaction { 32 | 33 | /** 34 | * Spring事务管理器 35 | * */ 36 | @Autowired 37 | private DataSourceTransactionManager txManager; 38 | 39 | /** 40 | * 异步任务最大数量 41 | * */ 42 | private final static int MAX_TASK = 100; 43 | 44 | 45 | /** 46 | * 异步任务基础执行 47 | * @param taskList 需要异步执行的任务 48 | * */ 49 | public void baseExecute(List taskList){ 50 | try{ 51 | if (taskList != null && taskList.size() > 0) { 52 | checkTaskList(taskList, MAX_TASK); 53 | for (Runnable task : taskList) { 54 | ThreadTask threadTask = 55 | new ThreadTask(task); 56 | TransactionThreadPool.execute(threadTask); 57 | } 58 | } 59 | }catch (Throwable e) { 60 | throw new RuntimeException(e); 61 | } 62 | } 63 | /** 64 | * 异步任务基础执行 65 | * @param callTaskList 需要异步执行的任务(有返回值) 66 | * @param resultList 承载异步执行任务结果的集合 67 | * @param sequence 是否要求resultList中的结果和执行的任务顺序相同 true是 false否 68 | * */ 69 | public void baseCall(List> callTaskList,List resultList,boolean sequence) { 70 | try{ 71 | if (callTaskList != null && callTaskList.size() > 0) { 72 | checkTaskList(callTaskList, MAX_TASK); 73 | //任务线程计数器 74 | CountDownLatch threadCountDownLatch = threadLatch(getSize(null,callTaskList,null)); 75 | if (sequence) { 76 | List taskIdList = new ArrayList<>(callTaskList.size()); 77 | Map executeResultMap = new ConcurrentHashMap<>(callTaskList.size()); 78 | AtomicInteger atomicInteger = new AtomicInteger(0); 79 | for (Callable callTask : callTaskList) { 80 | String taskId = String.valueOf(atomicInteger.incrementAndGet()); 81 | taskIdList.add(taskId); 82 | ThreadTask threadTask = new ThreadTask(threadCountDownLatch,callTask,taskId,executeResultMap); 83 | TransactionThreadPool.execute(threadTask); 84 | } 85 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 86 | for (String taskId : taskIdList) { 87 | resultList.add(executeResultMap.get(taskId)); 88 | } 89 | }else { 90 | List executeResultList = Collections.synchronizedList(new ArrayList<>()); 91 | for (Callable callTask : callTaskList) { 92 | ThreadTask threadTask = new ThreadTask(threadCountDownLatch,callTask,executeResultList); 93 | TransactionThreadPool.execute(threadTask); 94 | } 95 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 96 | resultList.addAll(executeResultList); 97 | } 98 | } 99 | } catch (InterruptedException e) { 100 | throw new RuntimeException(e); 101 | } catch (Throwable e) { 102 | throw new RuntimeException(e); 103 | } 104 | } 105 | 106 | /** 107 | * 异步任务独立事务基础执行 108 | * @param taskList 需要异步执行的任务 109 | * @param callTaskList 需要异步执行的任务(有返回值) 110 | * @param resultList 承载异步执行任务结果的集合 111 | * */ 112 | public void independenceTransactionBaseExecute(List taskList, List> callTaskList,List resultList){ 113 | 114 | try{ 115 | if (taskList != null && taskList.size() > 0) { 116 | checkTaskList(taskList, MAX_TASK); 117 | for (Runnable task : taskList) { 118 | ThreadIndependenceTransactionTask taskTask = 119 | new ThreadIndependenceTransactionTask(txManager,task); 120 | TransactionThreadPool.execute(taskTask); 121 | } 122 | }else if (callTaskList != null && callTaskList.size() > 0) { 123 | checkTaskList(callTaskList, MAX_TASK); 124 | //任务线程计数器 125 | CountDownLatch threadCountDownLatch = threadLatch(getSize(taskList,callTaskList,null)); 126 | List executeResultList = Collections.synchronizedList(new ArrayList<>()); 127 | for (Callable callTask : callTaskList) { 128 | ThreadIndependenceTransactionTask taskTask = 129 | new ThreadIndependenceTransactionTask(txManager,threadCountDownLatch,callTask,executeResultList); 130 | TransactionThreadPool.execute(taskTask); 131 | } 132 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 133 | resultList.addAll(executeResultList); 134 | } 135 | } catch (InterruptedException e) { 136 | throw new RuntimeException(e); 137 | } catch (Throwable e) { 138 | throw new RuntimeException(e); 139 | } 140 | } 141 | 142 | /** 143 | * 基础执行 144 | * @param majorTaskRunnable 需要执行的主任务 145 | * @param majorTaskCallable 需要执行的主任务(有返回值) 146 | * @param taskList 需要异步执行的任务(包括Runnable、InputParamRunnable类型) 147 | * @param callTaskList 需要异步执行的任务(有返回值) 148 | * @param inputParamCallableList 需要异步执行的任务(有返回值)(需要有主任务中的返回值来做输入参数) 149 | * @param resultList 载异步执行任务结果的集合 150 | * @param threadTransaction 需要自定义实现的转换任务接口 151 | * */ 152 | public T baseTransactionExecute(MajorTaskRunnable majorTaskRunnable, MajorTaskCallable majorTaskCallable, 153 | List taskList, List> callTaskList, List> inputParamCallableList, 154 | List resultList, ThreadTransaction threadTransaction){ 155 | //主线程计数器 156 | CountDownLatch mainCountDownLatch = mainLatch(); 157 | //任务线程计数器 158 | CountDownLatch threadCountDownLatch = threadLatch(getSize(taskList,callTaskList,inputParamCallableList)); 159 | //回滚标识符 160 | AtomicBoolean rollBackFlag = rollbackFlag(); 161 | //存放每个任务回滚标识的集合 162 | List taskRollBackFlagList = taskRollBackFlagList(); 163 | T t = null; 164 | try{ 165 | //没有返回值的主任务执行 166 | if (majorTaskRunnable != null) { 167 | try { 168 | majorTaskRunnable.launchRun(); 169 | } catch (Throwable e) { 170 | rollBackFlag.set(true); 171 | throw new RuntimeException(e); 172 | } 173 | } 174 | //有返回值的主任务执行 175 | if (majorTaskCallable != null) { 176 | try { 177 | t = majorTaskCallable.launchCall(); 178 | } catch (Throwable e) { 179 | rollBackFlag.set(true); 180 | throw new RuntimeException(e); 181 | } 182 | } 183 | 184 | if (taskList != null && taskList.size() > 0) { 185 | checkTaskList(taskList, MAX_TASK); 186 | for (Object task : taskList) { 187 | ThreadTransactionTask threadTransactionTask = threadTransaction.getThreadTransactionTask(task); 188 | 189 | threadTransactionTask.build() 190 | .setRollBackFlag(rollBackFlag) 191 | .setTxManager(txManager) 192 | .setMainCountDownLatch(mainCountDownLatch) 193 | .setThreadCountDownLatch(threadCountDownLatch) 194 | .setTaskRollBackFlagList(taskRollBackFlagList) 195 | .setInputParam(t); 196 | 197 | TransactionThreadPool.execute(threadTransactionTask); 198 | } 199 | 200 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 201 | 202 | setRollBackFlag(taskRollBackFlagList,rollBackFlag); 203 | }else if (callTaskList != null && callTaskList.size() > 0) { 204 | checkTaskList(callTaskList, MAX_TASK); 205 | List executeResultList = Collections.synchronizedList(new ArrayList<>()); 206 | for (Callable callTask : callTaskList) { 207 | ThreadTransactionTask threadTransactionTask = threadTransaction.getThreadTransactionTask(callTask); 208 | threadTransactionTask.build() 209 | .setRollBackFlag(rollBackFlag) 210 | .setTxManager(txManager) 211 | .setMainCountDownLatch(mainCountDownLatch) 212 | .setThreadCountDownLatch(threadCountDownLatch) 213 | .setTaskRollBackFlagList(taskRollBackFlagList) 214 | .setInputParam(t) 215 | .setList(executeResultList); 216 | 217 | TransactionThreadPool.execute(threadTransactionTask); 218 | } 219 | 220 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 221 | 222 | setRollBackFlag(taskRollBackFlagList,rollBackFlag); 223 | 224 | resultList.addAll(executeResultList); 225 | }else if (inputParamCallableList != null && inputParamCallableList.size() > 0) { 226 | checkTaskList(inputParamCallableList, MAX_TASK); 227 | List executeResultList = Collections.synchronizedList(new ArrayList<>()); 228 | for (InputParamCallable inputParamCallTask : inputParamCallableList) { 229 | ThreadTransactionTask threadTransactionTask = threadTransaction.getThreadTransactionTask(inputParamCallTask); 230 | threadTransactionTask.build() 231 | .setRollBackFlag(rollBackFlag) 232 | .setTxManager(txManager) 233 | .setMainCountDownLatch(mainCountDownLatch) 234 | .setThreadCountDownLatch(threadCountDownLatch) 235 | .setTaskRollBackFlagList(taskRollBackFlagList) 236 | .setInputParam(t) 237 | .setList(executeResultList); 238 | 239 | TransactionThreadPool.execute(threadTransactionTask); 240 | } 241 | 242 | threadCountDownLatch.await(20, TimeUnit.SECONDS); 243 | 244 | setRollBackFlag(taskRollBackFlagList,rollBackFlag); 245 | 246 | resultList.addAll(executeResultList); 247 | } 248 | } catch (InterruptedException e) { 249 | throw new RuntimeException(e); 250 | } catch (Throwable e) { 251 | throw new RuntimeException(e); 252 | } finally { 253 | mainCountDownLatch.countDown(); 254 | } 255 | return t; 256 | } 257 | 258 | 259 | /** 260 | * 验证异步任务的数量 261 | * @param taskList 异步任务 262 | * @taskMaximum 最大数量限制 263 | * */ 264 | private void checkTaskList(List taskList, int taskMaximum) { 265 | if ((taskList != null && taskList.size() > taskMaximum)) { 266 | throw new RuntimeException("The task exceeded the maximum limit"); 267 | } 268 | } 269 | 270 | /** 271 | * 获得异步任务的数量 272 | * @param taskList 异步任务 273 | * @param callTaskList 异步任务(有返回值) 274 | * @param inputParamCallableList 异步任务(需要主任务输入参数、有返回值) 275 | * @taskMaximum 最大数量限制 276 | * */ 277 | public int getSize(List taskList, List> callTaskList, List> inputParamCallableList){ 278 | if (taskList != null) { 279 | return taskList.size(); 280 | } 281 | if (callTaskList != null) { 282 | return callTaskList.size(); 283 | } 284 | if (inputParamCallableList != null) { 285 | return inputParamCallableList.size(); 286 | } 287 | return 0; 288 | } 289 | 290 | /** 291 | * 主任务计数器 292 | * @return CountDownLatch 293 | * */ 294 | public CountDownLatch mainLatch(){ 295 | //主线程计数器 296 | CountDownLatch mainCountDownLatch = new CountDownLatch(1); 297 | return mainCountDownLatch; 298 | } 299 | 300 | /** 301 | * 任务线程计数器 302 | * @param size 任务数量 303 | * @return CountDownLatch 304 | * */ 305 | public CountDownLatch threadLatch(int size) { 306 | //任务线程计数器 307 | CountDownLatch threadCountDownLatch = new CountDownLatch(size); 308 | return threadCountDownLatch; 309 | } 310 | 311 | /** 312 | * 回滚标识符 313 | * @return AtomicBoolean 314 | * */ 315 | public AtomicBoolean rollbackFlag(){ 316 | //回滚标识符 317 | AtomicBoolean rollBackFlag = new AtomicBoolean(false); 318 | return rollBackFlag; 319 | } 320 | 321 | /** 322 | * 存放每个任务回滚标识的集合 323 | * @return List 324 | * */ 325 | public List taskRollBackFlagList(){ 326 | //存放每个任务回滚标识的集合 327 | List taskRollBackFlagList = Collections.synchronizedList(new ArrayList<>()); 328 | return taskRollBackFlagList; 329 | } 330 | 331 | /** 332 | * 判断异步的任务来设置回滚标识 333 | * @param taskRollBackFlagList 异步任务回滚标识集合 334 | * @param rollBackFlag 是否回滚标识 335 | * */ 336 | public void setRollBackFlag(List taskRollBackFlagList,AtomicBoolean rollBackFlag){ 337 | for (Boolean taskRollBackFlag : taskRollBackFlagList) { 338 | if (taskRollBackFlag) { 339 | rollBackFlag.set(true); 340 | throw new RuntimeException("an error occurred during task execution procedure"); 341 | } 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/base/BaseThreadTransactionTask.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.base; 2 | 3 | 4 | import com.example.transactionthread.core.InputParamCallable; 5 | import com.example.transactionthread.core.InputParamRunnable; 6 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 7 | import org.springframework.transaction.TransactionDefinition; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.Callable; 11 | import java.util.concurrent.CountDownLatch; 12 | import java.util.concurrent.atomic.AtomicBoolean; 13 | 14 | /** 15 | * @program: toolkit 16 | * @description: 事务线程基础类 17 | * @author: lk 18 | * @create: 2022-01-14 19 | **/ 20 | public abstract class BaseThreadTransactionTask implements Runnable { 21 | 22 | /** 23 | * 事务传播行为 24 | * */ 25 | protected int propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRES_NEW; 26 | 27 | /** 28 | * 事务隔离级别 29 | * */ 30 | protected int isolationLevel = TransactionDefinition.ISOLATION_READ_COMMITTED; 31 | 32 | /** 33 | * 回滚标识符 34 | */ 35 | protected AtomicBoolean rollBackFlag; 36 | /** 37 | * 事务管理器 38 | */ 39 | protected DataSourceTransactionManager txManager; 40 | /** 41 | * 主线程计数器 42 | */ 43 | protected CountDownLatch mainCountDownLatch; 44 | /** 45 | * 任务线程计数器 46 | */ 47 | protected CountDownLatch threadCountDownLatch; 48 | /** 49 | * 存放每个任务回滚标识的集合 50 | */ 51 | protected List taskRollBackFlagList; 52 | /** 53 | * 任务 54 | */ 55 | protected Runnable task; 56 | /** 57 | * 有返回值的任务 58 | * */ 59 | protected Callable callTask; 60 | /** 61 | * 装入异步任务结果的list 62 | * */ 63 | protected List list; 64 | /** 65 | * 任务id 66 | * */ 67 | protected String taskId; 68 | /** 69 | * 装入异步任务结果的map key:任务id value:任务结果 70 | * */ 71 | protected Map executeResultMap; 72 | /** 73 | * 输入参数 74 | */ 75 | protected T inputParam; 76 | /** 77 | * 带输入参数的任务 78 | */ 79 | protected InputParamRunnable inputParamTask; 80 | /** 81 | * 带输入参数的任务(有返回值) 82 | * */ 83 | protected InputParamCallable inputParamCallable; 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/base/ThreadTransaction.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.base; 2 | 3 | 4 | import com.example.transactionthread.core.ThreadTransactionTask; 5 | 6 | /** 7 | * @program: toolkit 8 | * @description: 具体执行 9 | * @author: lk 10 | * @create: 2022-01-12 11 | **/ 12 | @FunctionalInterface 13 | public interface ThreadTransaction { 14 | 15 | /** 16 | * 具体执行 17 | * */ 18 | ThreadTransactionTask getThreadTransactionTask(Object task); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/InputParamCallable.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | /** 4 | * @program: toolkit 5 | * @description: 有输入参数的Callable 6 | * @author: lk 7 | * @create: 2022-1-11 8 | **/ 9 | @FunctionalInterface 10 | public interface InputParamCallable { 11 | 12 | /** 13 | * 执行异步任务的方法 14 | * 15 | * @param v 参数 16 | * @return T 返回结果 17 | */ 18 | T acceptCall(V v); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/InputParamRunnable.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | /** 4 | * @program: toolkit 5 | * @description: 有输入参数的Runnable 6 | * @author: lk 7 | * @create: 2021-12-23 8 | **/ 9 | @FunctionalInterface 10 | public interface InputParamRunnable { 11 | 12 | /** 13 | * 执行异步任务的方法 14 | * 15 | * @param t 参数 16 | */ 17 | void acceptRun(T t); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/MajorTaskCallable.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | 4 | /** 5 | * @program: toolkit 6 | * @description: 有返回值的主任务接口 7 | * @author: lk 8 | * @create: 2021-12-23 9 | **/ 10 | @FunctionalInterface 11 | public interface MajorTaskCallable { 12 | 13 | /** 14 | * 执行主任务的方法 15 | * 16 | * @return V 返回值 17 | */ 18 | V launchCall(); 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/MajorTaskRunnable.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | /** 4 | * @program: toolkit 5 | * @description: 无返回值的主任务接口 6 | * @author: lk 7 | * @create: 2021-12-23 8 | **/ 9 | @FunctionalInterface 10 | public interface MajorTaskRunnable { 11 | 12 | /** 13 | * 执行主任务的方法 14 | * 15 | * @throws Exception 抛出的异常 16 | */ 17 | void launchRun(); 18 | } -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/ThreadIndependenceTransactionTask.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | 4 | import com.example.transactionthread.base.BaseThreadTransactionTask; 5 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 6 | import org.springframework.transaction.TransactionDefinition; 7 | import org.springframework.transaction.TransactionStatus; 8 | import org.springframework.transaction.support.DefaultTransactionDefinition; 9 | import java.util.List; 10 | import java.util.concurrent.Callable; 11 | import java.util.concurrent.CountDownLatch; 12 | 13 | 14 | /** 15 | * @description: 独立事务线程任务类 16 | * @author: lk 17 | * @create: 2022-01-14 18 | **/ 19 | public class ThreadIndependenceTransactionTask extends BaseThreadTransactionTask { 20 | 21 | /** 22 | * 事务传播行为 23 | * */ 24 | private int propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRES_NEW; 25 | 26 | 27 | @Override 28 | public void run() { 29 | DefaultTransactionDefinition def = new DefaultTransactionDefinition(); 30 | // 事务传播行为 31 | def.setPropagationBehavior(propagationBehavior); 32 | // 事务隔离级别 33 | def.setIsolationLevel(isolationLevel); 34 | // 获得事务状态 35 | TransactionStatus status = txManager.getTransaction(def); 36 | try { 37 | if (task != null) { 38 | task.run(); 39 | } else if (callTask != null) { 40 | V v = callTask.call(); 41 | list.add(v); 42 | } 43 | txManager.commit(status); 44 | } catch (Throwable e) { 45 | txManager.rollback(status); 46 | throw new RuntimeException(e); 47 | } finally { 48 | if(threadCountDownLatch != null) { 49 | threadCountDownLatch.countDown(); 50 | } 51 | } 52 | } 53 | 54 | public ThreadIndependenceTransactionTask(DataSourceTransactionManager txManager, Runnable task) { 55 | this.txManager = txManager; 56 | this.task = task; 57 | } 58 | 59 | public ThreadIndependenceTransactionTask(DataSourceTransactionManager txManager, CountDownLatch threadCountDownLatch, Callable callTask, List list) { 60 | this.txManager = txManager; 61 | this.threadCountDownLatch = threadCountDownLatch; 62 | this.callTask = callTask; 63 | this.list = list; 64 | } 65 | 66 | public DataSourceTransactionManager getTxManager() { 67 | return txManager; 68 | } 69 | 70 | public void setTxManager(DataSourceTransactionManager txManager) { 71 | this.txManager = txManager; 72 | } 73 | 74 | public CountDownLatch getThreadCountDownLatch() { 75 | return threadCountDownLatch; 76 | } 77 | 78 | public void setThreadCountDownLatch(CountDownLatch threadCountDownLatch) { 79 | this.threadCountDownLatch = threadCountDownLatch; 80 | } 81 | 82 | public Runnable getTask() { 83 | return task; 84 | } 85 | 86 | public void setTask(Runnable task) { 87 | this.task = task; 88 | } 89 | 90 | public Callable getCallTask() { 91 | return callTask; 92 | } 93 | 94 | public void setCallTask(Callable callTask) { 95 | this.callTask = callTask; 96 | } 97 | 98 | public List getList() { 99 | return list; 100 | } 101 | 102 | public void setList(List list) { 103 | this.list = list; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/ThreadTask.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | import com.example.transactionthread.base.BaseThreadTransactionTask; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.CountDownLatch; 9 | 10 | /** 11 | * @program: toolkit 12 | * @description: 线程任务 13 | * @author: lk 14 | * @create: 2022-01-18 15 | **/ 16 | public class ThreadTask extends BaseThreadTransactionTask { 17 | 18 | 19 | @Override 20 | public void run() { 21 | try { 22 | if (task != null) { 23 | task.run(); 24 | } else if (callTask != null) { 25 | V v = callTask.call(); 26 | if (taskId != null && executeResultMap != null) { 27 | executeResultMap.put(taskId,v); 28 | }else { 29 | list.add(v); 30 | } 31 | } 32 | } catch (Throwable e) { 33 | throw new RuntimeException(e); 34 | } finally { 35 | if(threadCountDownLatch != null) { 36 | threadCountDownLatch.countDown(); 37 | } 38 | } 39 | } 40 | 41 | public ThreadTask(Runnable task){ 42 | this.task = task; 43 | } 44 | 45 | public ThreadTask(CountDownLatch threadCountDownLatch, Callable callTask, List list){ 46 | this.threadCountDownLatch = threadCountDownLatch; 47 | this.callTask = callTask; 48 | this.list = list; 49 | } 50 | 51 | public ThreadTask(CountDownLatch threadCountDownLatch, Callable callTask, String taskId, Map executeResultMap){ 52 | this.threadCountDownLatch = threadCountDownLatch; 53 | this.callTask = callTask; 54 | this.taskId = taskId; 55 | this.executeResultMap = executeResultMap; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/ThreadTransactionTask.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | 4 | import com.example.transactionthread.base.BaseThreadTransactionTask; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 8 | import org.springframework.transaction.TransactionStatus; 9 | import org.springframework.transaction.support.DefaultTransactionDefinition; 10 | import java.util.List; 11 | import java.util.concurrent.Callable; 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.concurrent.atomic.AtomicBoolean; 15 | 16 | /** 17 | * @program: toolkit 18 | * @description: 事务线程任务类 19 | * @author: lk 20 | * @create: 2021-12-15 21 | **/ 22 | public class ThreadTransactionTask extends BaseThreadTransactionTask { 23 | 24 | private Logger logger = LoggerFactory.getLogger(ThreadTransactionTask.class); 25 | 26 | 27 | @Override 28 | public void run() { 29 | DefaultTransactionDefinition def = new DefaultTransactionDefinition(); 30 | // 事务传播行为 31 | def.setPropagationBehavior(propagationBehavior); 32 | // 事务隔离级别 33 | def.setIsolationLevel(isolationLevel); 34 | // 获得事务状态 35 | TransactionStatus status = txManager.getTransaction(def); 36 | try { 37 | if (task != null) { 38 | task.run(); 39 | } else if (inputParamTask != null) { 40 | inputParamTask.acceptRun(inputParam); 41 | } else if (callTask != null) { 42 | V v = callTask.call(); 43 | list.add(v); 44 | } else if (inputParamCallable != null) { 45 | V v = inputParamCallable.acceptCall(inputParam); 46 | list.add(v); 47 | } 48 | taskRollBackFlagList.add(false); 49 | } catch (Throwable e) { 50 | taskRollBackFlagList.add(true); 51 | logger.error("task error message",e); 52 | } finally { 53 | threadCountDownLatch.countDown(); 54 | } 55 | try { 56 | mainCountDownLatch.await(20, TimeUnit.SECONDS); 57 | } catch (InterruptedException e) { 58 | logger.error("Interrupted error message:{}",e.getMessage()); 59 | Thread.currentThread().interrupt(); 60 | } 61 | 62 | if (rollBackFlag.get()) { 63 | txManager.rollback(status); 64 | } else { 65 | txManager.commit(status); 66 | } 67 | } 68 | 69 | public ThreadTransactionTask(Runnable task) { 70 | this.task = task; 71 | } 72 | 73 | public ThreadTransactionTask(Callable callTask) { 74 | this.callTask = callTask; 75 | } 76 | 77 | public ThreadTransactionTask(InputParamRunnable inputParamTask) { 78 | this.inputParamTask = inputParamTask; 79 | } 80 | 81 | public ThreadTransactionTask(InputParamCallable inputParamCallable) { 82 | this.inputParamCallable = inputParamCallable; 83 | } 84 | 85 | public ThreadTransactionTask build() { 86 | return this; 87 | } 88 | 89 | public AtomicBoolean getRollBackFlag() { 90 | return rollBackFlag; 91 | } 92 | 93 | public ThreadTransactionTask setRollBackFlag(AtomicBoolean rollBackFlag) { 94 | this.rollBackFlag = rollBackFlag; 95 | return this; 96 | } 97 | 98 | public DataSourceTransactionManager getTxManager() { 99 | return txManager; 100 | } 101 | 102 | public ThreadTransactionTask setTxManager(DataSourceTransactionManager txManager) { 103 | this.txManager = txManager; 104 | return this; 105 | } 106 | 107 | public CountDownLatch getMainCountDownLatch() { 108 | return mainCountDownLatch; 109 | } 110 | 111 | public ThreadTransactionTask setMainCountDownLatch(CountDownLatch mainCountDownLatch) { 112 | this.mainCountDownLatch = mainCountDownLatch; 113 | return this; 114 | } 115 | 116 | public CountDownLatch getThreadCountDownLatch() { 117 | return threadCountDownLatch; 118 | } 119 | 120 | public ThreadTransactionTask setThreadCountDownLatch(CountDownLatch threadCountDownLatch) { 121 | this.threadCountDownLatch = threadCountDownLatch; 122 | return this; 123 | } 124 | 125 | public List getTaskRollBackFlagList() { 126 | return taskRollBackFlagList; 127 | } 128 | 129 | public ThreadTransactionTask setTaskRollBackFlagList(List taskRollBackFlagList) { 130 | this.taskRollBackFlagList = taskRollBackFlagList; 131 | return this; 132 | } 133 | 134 | public Runnable getTask() { 135 | return task; 136 | } 137 | 138 | public ThreadTransactionTask setTask(Runnable task) { 139 | this.task = task; 140 | return this; 141 | } 142 | 143 | public Callable getCallTask() { 144 | return callTask; 145 | } 146 | 147 | public ThreadTransactionTask setCallTask(Callable callTask) { 148 | this.callTask = callTask; 149 | return this; 150 | } 151 | 152 | public List getList() { 153 | return list; 154 | } 155 | 156 | public ThreadTransactionTask setList(List list) { 157 | this.list = list; 158 | return this; 159 | } 160 | 161 | public T getInputParam() { 162 | return inputParam; 163 | } 164 | 165 | public ThreadTransactionTask setInputParam(T inputParam) { 166 | this.inputParam = inputParam; 167 | return this; 168 | } 169 | 170 | public InputParamRunnable getInputParamTask() { 171 | return inputParamTask; 172 | } 173 | 174 | public ThreadTransactionTask setInputParamTask(InputParamRunnable inputParamTask) { 175 | this.inputParamTask = inputParamTask; 176 | return this; 177 | } 178 | 179 | public InputParamCallable getInputParamCallable() { 180 | return inputParamCallable; 181 | } 182 | 183 | public ThreadTransactionTask setInputParamCallable(InputParamCallable inputParamCallable) { 184 | this.inputParamCallable = inputParamCallable; 185 | return this; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/core/ThreadTransactionTool.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.core; 2 | 3 | 4 | import com.example.transactionthread.base.BaseThreadTransaction; 5 | import org.springframework.stereotype.Component; 6 | import java.util.List; 7 | import java.util.concurrent.Callable; 8 | 9 | 10 | /** 11 | * @program: toolkit 12 | * @description: 事务线程工具类 13 | * @author: lk 14 | * @create: 2021-12-15 15 | **/ 16 | @Component 17 | public class ThreadTransactionTool extends BaseThreadTransaction { 18 | 19 | /** 20 | * 异步任务运行 21 | * @param taskList 需要异步执行的任务 22 | */ 23 | public void execute(List taskList) { 24 | super.baseExecute(taskList); 25 | } 26 | 27 | /** 28 | * 异步任务运行 29 | * @param callTaskList 需要异步执行的任务(有返回值) 30 | * @param resultList 承载异步执行任务结果的集合 31 | * @param sequence 是否要求执行的任务 和 承载异步执行任务结果的集合保证顺序 32 | */ 33 | public void call(List> callTaskList,List resultList,boolean sequence) { 34 | super.baseCall(callTaskList,resultList,sequence); 35 | } 36 | 37 | /** 38 | * 异步任务独立事务运行(出现异常回滚本异步任务,其他异步任务不会回滚) 39 | * @param taskList 需要异步执行的任务 40 | */ 41 | public void independenceTransactionExecute(List taskList) { 42 | super.independenceTransactionBaseExecute(taskList,null,null); 43 | } 44 | 45 | /** 46 | * 异步任务独立事务运行(出现异常回滚本异步任务,其他异步任务不会回滚) 47 | * @param callTaskList 需要异步执行的任务(有返回值) 48 | * @param resultList 承载异步执行任务结果的集合 49 | */ 50 | public void independenceTransactionCall(List> callTaskList,List resultList) { 51 | super.independenceTransactionBaseExecute(null,callTaskList,resultList); 52 | } 53 | 54 | /** 55 | * @param taskList 需要异步执行的任务 56 | */ 57 | public void transactionExecute(List taskList) { 58 | super.baseTransactionExecute(null,null,taskList,null,null,null, task -> new ThreadTransactionTask((Runnable) task)); 59 | } 60 | 61 | /** 62 | * @param callTaskList 需要异步执行的任务(有返回值) 63 | * @param resultList 承载异步执行任务结果的集合 64 | */ 65 | public void transactionCall(List> callTaskList, List resultList) { 66 | super.baseTransactionExecute(null,null,null,callTaskList,null,resultList, task -> new ThreadTransactionTask((Callable) task)); 67 | } 68 | 69 | /** 70 | * @param majorTaskRunnable 需要执行的主任务 71 | * @param taskList 需要异步执行的任务 72 | * @throws Throwable 抛出的异常 73 | */ 74 | public void transactionExecute(MajorTaskRunnable majorTaskRunnable, List taskList) { 75 | super.baseTransactionExecute(majorTaskRunnable,null,taskList,null,null,null, task -> new ThreadTransactionTask((Runnable) task)); 76 | } 77 | 78 | /** 79 | * @param majorTaskRunnable 需要执行的主任务 80 | * @param callTaskList 需要异步执行的任务(有返回值) 81 | * @param resultList 承载异步执行任务结果的集合 82 | * @throws Throwable 抛出的异常 83 | */ 84 | public void transactionCall(MajorTaskRunnable majorTaskRunnable, List> callTaskList, List resultList) { 85 | super.baseTransactionExecute(majorTaskRunnable,null,null,callTaskList,null,resultList, task -> new ThreadTransactionTask((Callable) task)); 86 | } 87 | 88 | /** 89 | * @param majorTaskCallable 需要执行的主任务(有返回值) 90 | * @param taskList 需要异步执行的任务 91 | * @return T 主任务的返回值 92 | * @throws Throwable 抛出的异常 93 | */ 94 | public T transactionExecute(MajorTaskCallable majorTaskCallable, List taskList) { 95 | return super.baseTransactionExecute(null,majorTaskCallable,taskList,null,null,null, task -> new ThreadTransactionTask((Runnable) task)); 96 | } 97 | 98 | /** 99 | * @param majorTaskCallable 需要执行的主任务(有返回值) 100 | * @param callTaskList 需要异步执行的任务(有返回值) 101 | * @param resultList 承载异步执行任务结果的集合 102 | * @return T 主任务的返回值 103 | * @throws Throwable 抛出的异常 104 | */ 105 | public T transactionCall(MajorTaskCallable majorTaskCallable, List> callTaskList, List resultList) { 106 | return super.baseTransactionExecute(null,majorTaskCallable,null,callTaskList,null,resultList, task -> new ThreadTransactionTask((Callable) task)); 107 | } 108 | 109 | /** 110 | * @param majorTaskCallable 需要执行的主任务(有返回值) 111 | * @param inputParamTaskList 需要异步执行的任务(需要有主任务中的返回值来做输入参数) 112 | * @return T 主任务的返回值 113 | * @throws Throwable 抛出的异常 114 | */ 115 | public T transactionExecuteInputParamTask(MajorTaskCallable majorTaskCallable, List> inputParamTaskList) { 116 | return super.baseTransactionExecute(null,majorTaskCallable,inputParamTaskList,null, null,null, task -> new ThreadTransactionTask((InputParamRunnable) task)); 117 | } 118 | 119 | /** 120 | * @param majorTaskCallable 需要执行的主任务(有返回值) 121 | * @param inputParamCallTaskList 需要异步执行的任务(有返回值)(需要有主任务中的返回值来做输入参数) 122 | * @param resultList 承载异步执行任务结果的集合 123 | * @return T 主任务的返回值 124 | * @throws Throwable 抛出的异常 125 | */ 126 | public T transactionCallInputParamCallTask(MajorTaskCallable majorTaskCallable, List> inputParamCallTaskList, List resultList) { 127 | return super.baseTransactionExecute(null,majorTaskCallable,null,null, inputParamCallTaskList,resultList, task -> new ThreadTransactionTask((InputParamCallable) task)); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/threadpool/TransactionThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.threadpool; 2 | 3 | import com.example.transactionthread.threadpool.namefactory.TransactionNameThreadFactory; 4 | import com.example.transactionthread.threadpool.rejectedexecutionhandler.ThreadPoolRejectedExecutionHandler; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.Callable; 7 | import java.util.concurrent.Future; 8 | import java.util.concurrent.RejectedExecutionHandler; 9 | import java.util.concurrent.SynchronousQueue; 10 | import java.util.concurrent.ThreadFactory; 11 | import java.util.concurrent.ThreadPoolExecutor; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * @program: transaction-thread 16 | * @author: lk 17 | * @create: 2021-12-16 14:09 18 | **/ 19 | 20 | public class TransactionThreadPool { 21 | private static ThreadPoolExecutor execute = null; 22 | 23 | static { 24 | execute = new CustomerThreadPoolExecutor( 25 | // 核心线程数 26 | 0, 27 | // 最大线程数 28 | 101, 29 | // 线程存活时间 30 | 60L, 31 | // 存活时间单位 32 | TimeUnit.SECONDS, 33 | // 队列容量 34 | new SynchronousQueue(), 35 | // 线程工厂 36 | new TransactionNameThreadFactory(), 37 | // 拒绝策略 38 | new ThreadPoolRejectedExecutionHandler.TransactionAbortPolicy()); 39 | } 40 | 41 | static class CustomerThreadPoolExecutor extends ThreadPoolExecutor { 42 | public CustomerThreadPoolExecutor(int corePoolSize, 43 | int maximumPoolSize, 44 | long keepAliveTime, 45 | TimeUnit unit, 46 | BlockingQueue workQueue, 47 | ThreadFactory threadFactory, 48 | RejectedExecutionHandler handler) { 49 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); 50 | } 51 | } 52 | 53 | /** 54 | * 执行任务 55 | * 56 | * @param r 提交的任务 57 | * @return 58 | */ 59 | public static void execute(Runnable r) { 60 | execute.execute(r); 61 | } 62 | 63 | /** 64 | * 执行带返回值任务 65 | * 66 | * @param c 提交的任务 67 | * @return 68 | */ 69 | public static Future submit(Callable c) { 70 | return execute.submit(c); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/threadpool/namefactory/AbstractNameThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.threadpool.namefactory; 2 | 3 | 4 | import java.util.concurrent.ThreadFactory; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | 7 | /** 8 | * @program: transaction-thread 9 | * @description: 线程工厂抽象基类 10 | * @author: lk 11 | * @create: 2021-12-16 12 | **/ 13 | public abstract class AbstractNameThreadFactory implements ThreadFactory { 14 | 15 | protected static final AtomicLong poolNum = new AtomicLong(1); 16 | private final ThreadGroup group; 17 | private final AtomicLong threadNum = new AtomicLong(1); 18 | private String namePrefix = ""; 19 | 20 | 21 | public AbstractNameThreadFactory() { 22 | SecurityManager s = System.getSecurityManager(); 23 | group = (s != null) ? s.getThreadGroup() : 24 | Thread.currentThread().getThreadGroup(); 25 | namePrefix = getNamePrefix() + "--thread--"; 26 | } 27 | 28 | /** 29 | * 子类实现获取线程池名称的前缀 30 | * 31 | * @return String 32 | */ 33 | public abstract String getNamePrefix(); 34 | 35 | /** 36 | * 将线程池工厂中设置线程名进行重写 37 | * 例子:子类重写的namePrefix--thread--2(每个线程池中线程的数量) 38 | */ 39 | @Override 40 | public Thread newThread(Runnable r) { 41 | String name = namePrefix + threadNum.getAndIncrement(); 42 | Thread t = new Thread(group, r, name, 0); 43 | if (t.isDaemon()) { 44 | t.setDaemon(false); 45 | } 46 | if (t.getPriority() != Thread.NORM_PRIORITY) { 47 | t.setPriority(Thread.NORM_PRIORITY); 48 | } 49 | return t; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/threadpool/namefactory/TransactionNameThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.threadpool.namefactory; 2 | 3 | /** 4 | * @program: transaction-thread 5 | * @description: 事务线程工厂 6 | * @author: lk 7 | * @create: 2021-12-16 14:09 8 | **/ 9 | public class TransactionNameThreadFactory extends AbstractNameThreadFactory { 10 | 11 | /** 12 | * 将线程池工厂的前缀 13 | * 例子:transaction-task-pool--1(线程池的数量) 14 | */ 15 | @Override 16 | public String getNamePrefix() { 17 | return "transaction-task-pool" + "--" + poolNum.getAndIncrement(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/transactionthread/threadpool/rejectedexecutionhandler/ThreadPoolRejectedExecutionHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread.threadpool.rejectedexecutionhandler; 2 | 3 | 4 | 5 | import java.util.concurrent.RejectedExecutionException; 6 | import java.util.concurrent.RejectedExecutionHandler; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | 9 | /** 10 | * @program: transaction-thread 11 | * @description: 线程池异常处理 12 | * @author: lk 13 | * @create: 2021-12-06 14 | **/ 15 | public class ThreadPoolRejectedExecutionHandler { 16 | 17 | /** 18 | * 事务线程池快速拒绝 19 | */ 20 | public static class TransactionAbortPolicy implements RejectedExecutionHandler { 21 | 22 | public TransactionAbortPolicy() { 23 | } 24 | 25 | @Override 26 | public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 27 | throw new RejectedExecutionException("ThreadPoolApplicationName Transaction Task " + r.toString() + 28 | " rejected from " + 29 | executor.toString()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #spring: 2 | # datasource: 3 | # username: root 4 | # password: root 5 | # url: jdbc:mysql://localhost:3306/tes?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC 6 | # driver-class-name: com.mysql.cj.jdbc.Driver 7 | -------------------------------------------------------------------------------- /src/test/java/com/example/transactionthread/TransactionthreadApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.transactionthread; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class TransactionthreadApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------